From 5ebb396638c48db4002e3f132a56de97d68f0a20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 6 Aug 2014 15:39:15 +0300 Subject: [PATCH 001/153] MDEV-6247: Merge 10.0-galera to 10.1. Merged lp:maria/maria-10.0-galera up to revision 3867. --- .bzrignore | 1 + BUILD/SETUP.sh | 2 +- BUILD/compile-amd64-debug-wsrep | 11 + BUILD/compile-amd64-wsrep | 9 + BUILD/compile-pentium-debug-wsrep | 12 + BUILD/compile-pentium-wsrep | 11 + BUILD/compile-pentium64-wsrep | 28 + CMakeLists.txt | 11 + Docs/README-wsrep | 488 +++++ client/client_priv.h | 3 + client/mysql_upgrade.c | 5 + client/mysqlcheck.c | 6 + client/mysqldump.c | 55 + cmake/cpack_rpm.cmake | 7 +- cmake/plugin.cmake | 22 +- cmake/wsrep.cmake | 76 + debian/dist/Debian/control | 2 +- debian/dist/Ubuntu/control | 2 +- include/mysql/service_logger.h | 2 +- include/mysqld_default_groups.h | 3 + include/thr_lock.h | 13 + mysql-test/extra/binlog_tests/binlog.test | 9 +- mysql-test/include/galera_cluster.inc | 10 + mysql-test/include/galera_connect.inc | 45 + mysql-test/include/galera_diff.inc | 100 ++ mysql-test/include/galera_end.inc | 25 + mysql-test/include/galera_init.inc | 26 + mysql-test/include/have_wsrep.inc | 8 + mysql-test/include/have_wsrep_enabled.inc | 9 + mysql-test/include/mtr_check.sql | 1 + mysql-test/include/mtr_warnings.sql | 8 + mysql-test/include/not_wsrep.inc | 7 + mysql-test/lib/My/ConfigFactory.pm | 3 + mysql-test/lib/mtr_cases.pm | 3 + mysql-test/mysql-test-run.pl | 58 + mysql-test/r/have_wsrep.require | 2 + .../r/mysql_tzinfo_to_sql_symlink.result | 1 + mysql-test/r/mysqld--help.result | 119 ++ mysql-test/r/not_wsrep.require | 2 + .../suite/binlog/r/binlog_row_binlog.result | 12 +- .../suite/binlog/r/binlog_stm_binlog.result | 12 +- mysql-test/suite/galera/galera_2nodes.cnf | 24 + mysql-test/suite/galera/my.cnf | 1 + mysql-test/suite/galera/r/basic.result | 30 + mysql-test/suite/galera/r/grant.result | 17 + mysql-test/suite/galera/r/partition.result | 23 + mysql-test/suite/galera/r/unique_key.result | 47 + mysql-test/suite/galera/t/basic.test | 26 + mysql-test/suite/galera/t/grant.test | 25 + mysql-test/suite/galera/t/partition.test | 31 + mysql-test/suite/galera/t/unique_key.test | 54 + .../suite/innodb/r/innodb-autoinc.result | 44 +- mysql-test/suite/innodb/t/innodb-autoinc.test | 44 +- .../suite/parts/r/partition_exch_qa_10.result | 2 +- .../suite/parts/t/partition_exch_qa_10.test | 2 +- .../suite/percona/innodb_sys_index.result | 2 +- .../suite/percona/innodb_sys_index.test | 3 +- .../suite/perfschema/r/rpl_statements.result | 6 +- .../suite/perfschema/t/rpl_statements.test | 4 +- .../wsrep_auto_increment_control_basic.result | 8 + .../r/wsrep_causal_reads_basic.result | 8 + .../r/wsrep_certify_nonpk_basic.result | 8 + .../r/wsrep_cluster_address_basic.result | 45 + .../r/wsrep_cluster_name_basic.result | 7 + .../r/wsrep_convert_lock_to_trx_basic.result | 8 + .../r/wsrep_data_home_dir_basic.result | 48 + .../sys_vars/r/wsrep_dbug_option_basic.result | 6 + .../suite/sys_vars/r/wsrep_debug_basic.result | 8 + .../sys_vars/r/wsrep_desync_basic.result | 3 + ...srep_drupal_282555_workaround_basic.result | 8 + .../r/wsrep_forced_binlog_format_basic.result | 8 + .../r/wsrep_load_data_splitting_basic.result | 8 + .../r/wsrep_log_conflicts_basic.result | 8 + .../sys_vars/r/wsrep_max_ws_rows_basic.result | 17 + .../sys_vars/r/wsrep_max_ws_size_basic.result | 17 + ...srep_mysql_replication_bundle_basic.result | 18 + .../r/wsrep_node_address_basic.result | 45 + .../wsrep_node_incoming_address_basic.result | 45 + .../sys_vars/r/wsrep_node_name_basic.result | 6 + .../sys_vars/r/wsrep_notify_cmd_basic.result | 6 + .../suite/sys_vars/r/wsrep_on_basic.result | 8 + .../sys_vars/r/wsrep_osu_method_basic.result | 12 + .../sys_vars/r/wsrep_provider_basic.result | 4 + .../r/wsrep_provider_options_basic.result | 4 + .../sys_vars/r/wsrep_recover_basic.result | 49 + .../r/wsrep_replicate_myisam_basic.result | 8 + .../r/wsrep_restart_slave_basic.result | 8 + .../r/wsrep_retry_autocommit_basic.result | 8 + .../r/wsrep_slave_threads_basic.result | 20 + .../sys_vars/r/wsrep_sst_auth_basic.result | 3 + .../sys_vars/r/wsrep_sst_donor_basic.result | 10 + ...rep_sst_donor_rejects_queries_basic.result | 8 + .../sys_vars/r/wsrep_sst_method_basic.result | 12 + .../r/wsrep_sst_receive_address_basic.result | 8 + .../r/wsrep_start_position_basic.result | 8 + .../t/wsrep_auto_increment_control_basic.test | 13 + .../sys_vars/t/wsrep_causal_reads_basic.test | 13 + .../suite/sys_vars/t/wsrep_certify_nonpk | 13 + .../sys_vars/t/wsrep_certify_nonpk_basic.test | 13 + .../t/wsrep_cluster_address_basic.test | 44 + .../sys_vars/t/wsrep_cluster_name_basic.test | 12 + .../t/wsrep_convert_lock_to_trx_basic.test | 13 + .../sys_vars/t/wsrep_data_home_dir_basic.test | 48 + .../sys_vars/t/wsrep_dbug_option_basic.test | 11 + .../suite/sys_vars/t/wsrep_debug_basic.test | 13 + .../sys_vars/t/wsrep_debug_option_basic.test | 13 + .../suite/sys_vars/t/wsrep_desync_basic.test | 4 + .../wsrep_drupal_282555_workaround_basic.test | 13 + .../t/wsrep_forced_binlog_format_basic.test | 14 + .../t/wsrep_load_data_splitting_basic.test | 13 + .../sys_vars/t/wsrep_log_conflicts_basic.test | 13 + .../sys_vars/t/wsrep_max_ws_rows_basic.test | 14 + .../sys_vars/t/wsrep_max_ws_size_basic.test | 14 + .../wsrep_mysql_replication_bundle_basic.test | 16 + .../sys_vars/t/wsrep_node_address_basic.test | 42 + .../t/wsrep_node_incoming_address_basic.test | 42 + .../sys_vars/t/wsrep_node_name_basic.test | 11 + .../sys_vars/t/wsrep_notify_cmd_basic.test | 11 + .../suite/sys_vars/t/wsrep_on_basic.test | 13 + .../sys_vars/t/wsrep_osu_method_basic.test | 18 + .../sys_vars/t/wsrep_provider_basic.test | 5 + .../t/wsrep_provider_options_basic.test | 5 + .../suite/sys_vars/t/wsrep_recover_basic.test | 47 + .../t/wsrep_replicate_myisam_basic.test | 13 + .../sys_vars/t/wsrep_restart_slave_basic.test | 13 + .../t/wsrep_retry_autocommit_basic.test | 13 + .../sys_vars/t/wsrep_slave_threads_basic.test | 16 + .../sys_vars/t/wsrep_sst_auth_basic.test | 12 + .../sys_vars/t/wsrep_sst_donor_basic.test | 12 + ...wsrep_sst_donor_rejects_queries_basic.test | 13 + .../sys_vars/t/wsrep_sst_method_basic.test | 17 + .../t/wsrep_sst_receive_address_basic.test | 13 + .../t/wsrep_start_position_basic.test | 14 + .../t/wsrep_wsrep_provider_basic.test | 11 + mysql-test/suite/wsrep/README | 7 + mysql-test/suite/wsrep/r/binlog_format.result | 35 + .../r/mysql_tzinfo_to_sql_symlink.result | 70 + .../suite/wsrep/r/pool_of_threads.result | 8 + mysql-test/suite/wsrep/r/trans.result | 9 + mysql-test/suite/wsrep/r/variables.result | 222 +++ mysql-test/suite/wsrep/t/binlog_format.opt | 1 + mysql-test/suite/wsrep/t/binlog_format.test | 27 + .../wsrep/t/mysql_tzinfo_to_sql_symlink.test | 40 + mysql-test/suite/wsrep/t/pool_of_threads.opt | 1 + mysql-test/suite/wsrep/t/pool_of_threads.test | 11 + mysql-test/suite/wsrep/t/trans.test | 14 + mysql-test/suite/wsrep/t/variables.test | 146 ++ mysql-test/t/mysql_tzinfo_to_sql_symlink.test | 11 + mysql-test/t/mysqld--help.test | 3 +- mysys/CMakeLists.txt | 4 + mysys/my_default.c | 12 + mysys/thr_lock.c | 172 ++ plugin/feedback/CMakeLists.txt | 1 + scripts/CMakeLists.txt | 10 + scripts/mysqld_multi.sh | 8 +- scripts/mysqld_safe.sh | 122 +- scripts/wsrep_sst_common | 157 ++ scripts/wsrep_sst_common.sh | 157 ++ scripts/wsrep_sst_mysqldump | 132 ++ scripts/wsrep_sst_mysqldump.sh | 132 ++ scripts/wsrep_sst_rsync | 335 ++++ scripts/wsrep_sst_rsync.sh | 335 ++++ scripts/wsrep_sst_xtrabackup | 715 ++++++++ scripts/wsrep_sst_xtrabackup-v2 | 930 ++++++++++ scripts/wsrep_sst_xtrabackup-v2.sh | 930 ++++++++++ scripts/wsrep_sst_xtrabackup.sh | 715 ++++++++ sql/CMakeLists.txt | 22 + sql/event_data_objects.cc | 16 + sql/events.cc | 55 +- sql/ha_partition.cc | 8 +- sql/ha_partition.h | 4 +- sql/handler.cc | 146 +- sql/handler.h | 18 + sql/lock.cc | 50 + sql/log.cc | 222 ++- sql/log.h | 21 +- sql/log_event.cc | 197 ++- sql/mdl.cc | 144 +- sql/mdl.h | 16 + sql/mysqld.cc | 833 ++++++++- sql/mysqld.h | 19 + sql/protocol.cc | 8 + sql/rpl_record.cc | 20 +- sql/set_var.cc | 4 + sql/set_var.h | 6 + sql/slave.cc | 44 + sql/sp.cc | 34 + sql/sql_acl.cc | 54 +- sql/sql_admin.cc | 4 + sql/sql_alter.cc | 21 +- sql/sql_base.cc | 57 +- sql/sql_builtin.cc.in | 9 +- sql/sql_class.cc | 316 +++- sql/sql_class.h | 68 +- sql/sql_connect.cc | 25 + sql/sql_delete.cc | 12 + sql/sql_insert.cc | 45 + sql/sql_lex.cc | 11 + sql/sql_parse.cc | 583 +++++- sql/sql_parse.h | 16 + sql/sql_partition_admin.cc | 13 + sql/sql_plugin.cc | 6 + sql/sql_prepare.cc | 20 +- sql/sql_reload.cc | 13 +- sql/sql_repl.cc | 9 + sql/sql_show.cc | 33 + sql/sql_table.cc | 75 +- sql/sql_trigger.cc | 58 + sql/sql_truncate.cc | 9 + sql/sql_update.cc | 12 + sql/sql_yacc.yy | 12 +- sql/sys_vars.cc | 275 +++ sql/table.cc | 3 + sql/transaction.cc | 51 + sql/tztime.cc | 11 + sql/wsrep_applier.cc | 387 ++++ sql/wsrep_applier.h | 38 + sql/wsrep_binlog.cc | 408 +++++ sql/wsrep_binlog.h | 59 + sql/wsrep_check_opts.cc | 379 ++++ sql/wsrep_hton.cc | 577 ++++++ sql/wsrep_mysqld.cc | 1562 +++++++++++++++++ sql/wsrep_mysqld.h | 320 ++++ sql/wsrep_notify.cc | 111 ++ sql/wsrep_priv.h | 53 + sql/wsrep_sst.cc | 1127 ++++++++++++ sql/wsrep_sst.h | 68 + sql/wsrep_thd.cc | 584 ++++++ sql/wsrep_thd.h | 38 + sql/wsrep_utils.cc | 524 ++++++ sql/wsrep_utils.h | 208 +++ sql/wsrep_var.cc | 584 ++++++ sql/wsrep_var.h | 85 + storage/innobase/CMakeLists.txt | 25 + storage/innobase/buf/buf0rea.cc | 6 +- storage/innobase/dict/dict0dict.cc | 24 +- storage/innobase/fil/fil0pagecompress.cc | 2 + storage/innobase/handler/ha_innodb.cc | 1402 +++++++++++++++ storage/innobase/handler/ha_innodb.h | 42 +- storage/innobase/handler/handler0alter.cc | 4 + storage/innobase/include/dict0mem.h | 3 + storage/innobase/include/ha_prototypes.h | 16 + storage/innobase/include/lock0lock.h | 10 + storage/innobase/include/rem0rec.h | 9 + storage/innobase/include/srv0srv.h | 12 + storage/innobase/include/sync0sync.ic | 3 + storage/innobase/include/trx0sys.h | 33 + storage/innobase/include/trx0sys.ic | 3 + storage/innobase/include/trx0trx.h | 3 + storage/innobase/lock/lock0lock.cc | 404 ++++- storage/innobase/os/os0file.cc | 23 +- storage/innobase/rem/rem0rec.cc | 134 ++ storage/innobase/row/row0ins.cc | 31 +- storage/innobase/row/row0upd.cc | 297 ++++ storage/innobase/srv/srv0conc.cc | 93 +- storage/innobase/srv/srv0srv.cc | 29 + storage/innobase/trx/trx0sys.cc | 134 ++ storage/innobase/trx/trx0trx.cc | 35 +- storage/innobase/wsrep/md5.cc | 74 + storage/innobase/wsrep/wsrep_md5.h | 26 + storage/perfschema/CMakeLists.txt | 4 + storage/xtradb/CMakeLists.txt | 25 + storage/xtradb/dict/dict0dict.cc | 24 +- storage/xtradb/fil/fil0fil.cc | 32 +- storage/xtradb/fil/fil0pagecompress.cc | 2 + storage/xtradb/handler/ha_innodb.cc | 1431 ++++++++++++++- storage/xtradb/handler/ha_innodb.h | 41 + storage/xtradb/handler/handler0alter.cc | 4 + storage/xtradb/include/dict0mem.h | 3 + storage/xtradb/include/ha_prototypes.h | 16 + storage/xtradb/include/rem0rec.h | 9 + storage/xtradb/include/srv0srv.h | 13 + storage/xtradb/include/sync0sync.ic | 3 + storage/xtradb/include/trx0sys.h | 33 + storage/xtradb/include/trx0sys.ic | 3 + storage/xtradb/include/trx0trx.h | 3 + storage/xtradb/lock/lock0lock.cc | 404 ++++- storage/xtradb/lock/lock0wait.cc | 35 +- storage/xtradb/os/os0file.cc | 24 +- storage/xtradb/rem/rem0rec.cc | 139 +- storage/xtradb/row/row0ins.cc | 31 +- storage/xtradb/row/row0upd.cc | 297 ++++ storage/xtradb/srv/srv0conc.cc | 93 +- storage/xtradb/srv/srv0srv.cc | 33 + storage/xtradb/trx/trx0roll.cc | 16 + storage/xtradb/trx/trx0sys.cc | 134 ++ storage/xtradb/trx/trx0trx.cc | 43 +- storage/xtradb/wsrep/md5.cc | 74 + storage/xtradb/wsrep/wsrep_md5.h | 26 + support-files/CMakeLists.txt | 3 +- support-files/mysql.server.sh | 15 +- support-files/mysql.spec.sh | 61 +- support-files/rpm/server.cnf | 16 + support-files/wsrep.cnf | 129 ++ support-files/wsrep.cnf.sh | 129 ++ support-files/wsrep.cnf.sh.moved | 129 ++ support-files/wsrep_notify | 102 ++ support-files/wsrep_notify.sh | 102 ++ wsrep/CMakeLists.txt | 25 + wsrep/wsrep_api.h | 1118 ++++++++++++ wsrep/wsrep_dummy.c | 407 +++++ wsrep/wsrep_gtid.c | 74 + wsrep/wsrep_loader.c | 203 +++ wsrep/wsrep_uuid.c | 83 + 304 files changed, 27333 insertions(+), 194 deletions(-) create mode 100644 BUILD/compile-amd64-debug-wsrep create mode 100644 BUILD/compile-amd64-wsrep create mode 100644 BUILD/compile-pentium-debug-wsrep create mode 100644 BUILD/compile-pentium-wsrep create mode 100644 BUILD/compile-pentium64-wsrep create mode 100644 Docs/README-wsrep create mode 100644 cmake/wsrep.cmake create mode 100644 mysql-test/include/galera_cluster.inc create mode 100644 mysql-test/include/galera_connect.inc create mode 100644 mysql-test/include/galera_diff.inc create mode 100644 mysql-test/include/galera_end.inc create mode 100644 mysql-test/include/galera_init.inc create mode 100644 mysql-test/include/have_wsrep.inc create mode 100644 mysql-test/include/have_wsrep_enabled.inc create mode 100644 mysql-test/include/not_wsrep.inc create mode 100644 mysql-test/r/have_wsrep.require create mode 100644 mysql-test/r/not_wsrep.require create mode 100644 mysql-test/suite/galera/galera_2nodes.cnf create mode 100644 mysql-test/suite/galera/my.cnf create mode 100644 mysql-test/suite/galera/r/basic.result create mode 100644 mysql-test/suite/galera/r/grant.result create mode 100644 mysql-test/suite/galera/r/partition.result create mode 100644 mysql-test/suite/galera/r/unique_key.result create mode 100644 mysql-test/suite/galera/t/basic.test create mode 100644 mysql-test/suite/galera/t/grant.test create mode 100644 mysql-test/suite/galera/t/partition.test create mode 100644 mysql-test/suite/galera/t/unique_key.test mode change 100755 => 100644 mysql-test/suite/parts/r/partition_exch_qa_10.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_auto_increment_control_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_causal_reads_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_certify_nonpk_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_cluster_address_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_cluster_name_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_convert_lock_to_trx_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_data_home_dir_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_dbug_option_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_debug_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_desync_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_drupal_282555_workaround_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_forced_binlog_format_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_load_data_splitting_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_log_conflicts_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_max_ws_rows_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_max_ws_size_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_mysql_replication_bundle_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_node_address_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_node_incoming_address_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_node_name_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_notify_cmd_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_on_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_osu_method_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_provider_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_provider_options_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_recover_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_replicate_myisam_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_restart_slave_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_retry_autocommit_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_slave_threads_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_sst_auth_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_sst_donor_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_sst_donor_rejects_queries_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_sst_method_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_sst_receive_address_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_start_position_basic.result create mode 100644 mysql-test/suite/sys_vars/t/wsrep_auto_increment_control_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_causal_reads_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_certify_nonpk create mode 100644 mysql-test/suite/sys_vars/t/wsrep_certify_nonpk_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_cluster_address_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_cluster_name_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_convert_lock_to_trx_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_data_home_dir_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_dbug_option_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_debug_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_debug_option_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_desync_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_drupal_282555_workaround_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_forced_binlog_format_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_load_data_splitting_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_log_conflicts_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_max_ws_rows_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_max_ws_size_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_mysql_replication_bundle_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_node_address_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_node_incoming_address_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_node_name_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_notify_cmd_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_on_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_osu_method_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_provider_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_provider_options_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_recover_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_replicate_myisam_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_restart_slave_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_retry_autocommit_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_slave_threads_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_sst_auth_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_sst_donor_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_sst_donor_rejects_queries_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_sst_method_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_sst_receive_address_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_start_position_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_wsrep_provider_basic.test create mode 100644 mysql-test/suite/wsrep/README create mode 100644 mysql-test/suite/wsrep/r/binlog_format.result create mode 100644 mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink.result create mode 100644 mysql-test/suite/wsrep/r/pool_of_threads.result create mode 100644 mysql-test/suite/wsrep/r/trans.result create mode 100644 mysql-test/suite/wsrep/r/variables.result create mode 100644 mysql-test/suite/wsrep/t/binlog_format.opt create mode 100644 mysql-test/suite/wsrep/t/binlog_format.test create mode 100644 mysql-test/suite/wsrep/t/mysql_tzinfo_to_sql_symlink.test create mode 100644 mysql-test/suite/wsrep/t/pool_of_threads.opt create mode 100644 mysql-test/suite/wsrep/t/pool_of_threads.test create mode 100644 mysql-test/suite/wsrep/t/trans.test create mode 100644 mysql-test/suite/wsrep/t/variables.test create mode 100755 scripts/wsrep_sst_common create mode 100644 scripts/wsrep_sst_common.sh create mode 100755 scripts/wsrep_sst_mysqldump create mode 100644 scripts/wsrep_sst_mysqldump.sh create mode 100755 scripts/wsrep_sst_rsync create mode 100644 scripts/wsrep_sst_rsync.sh create mode 100755 scripts/wsrep_sst_xtrabackup create mode 100755 scripts/wsrep_sst_xtrabackup-v2 create mode 100644 scripts/wsrep_sst_xtrabackup-v2.sh create mode 100644 scripts/wsrep_sst_xtrabackup.sh create mode 100644 sql/wsrep_applier.cc create mode 100644 sql/wsrep_applier.h create mode 100644 sql/wsrep_binlog.cc create mode 100644 sql/wsrep_binlog.h create mode 100644 sql/wsrep_check_opts.cc create mode 100644 sql/wsrep_hton.cc create mode 100644 sql/wsrep_mysqld.cc create mode 100644 sql/wsrep_mysqld.h create mode 100644 sql/wsrep_notify.cc create mode 100644 sql/wsrep_priv.h create mode 100644 sql/wsrep_sst.cc create mode 100644 sql/wsrep_sst.h create mode 100644 sql/wsrep_thd.cc create mode 100644 sql/wsrep_thd.h create mode 100644 sql/wsrep_utils.cc create mode 100644 sql/wsrep_utils.h create mode 100644 sql/wsrep_var.cc create mode 100644 sql/wsrep_var.h create mode 100644 storage/innobase/wsrep/md5.cc create mode 100644 storage/innobase/wsrep/wsrep_md5.h create mode 100644 storage/xtradb/wsrep/md5.cc create mode 100644 storage/xtradb/wsrep/wsrep_md5.h create mode 100644 support-files/wsrep.cnf create mode 100644 support-files/wsrep.cnf.sh create mode 100644 support-files/wsrep.cnf.sh.moved create mode 100644 support-files/wsrep_notify create mode 100644 support-files/wsrep_notify.sh create mode 100644 wsrep/CMakeLists.txt create mode 100644 wsrep/wsrep_api.h create mode 100644 wsrep/wsrep_dummy.c create mode 100644 wsrep/wsrep_gtid.c create mode 100644 wsrep/wsrep_loader.c create mode 100644 wsrep/wsrep_uuid.c diff --git a/.bzrignore b/.bzrignore index d5874ebf0f2..ba23211d3a3 100644 --- a/.bzrignore +++ b/.bzrignore @@ -12,6 +12,7 @@ *.dll *.dsp *.dylib +*.diff *.exe *.exp *.gcda diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index bde095b0aa8..860560767a7 100755 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -215,7 +215,7 @@ all_configs="$SSL_LIBRARY --with-plugins=max --with-plugin-ndbcluster --with-emb alpha_cflags="$check_cpu_cflags -Wa,-m$cpu_flag" amd64_cflags="$check_cpu_cflags" amd64_cxxflags="" # If dropping '--with-big-tables', add here "-DBIG_TABLES" -pentium_cflags="$check_cpu_cflags" +pentium_cflags="$check_cpu_cflags -m32" pentium64_cflags="$check_cpu_cflags -m64" ppc_cflags="$check_cpu_cflags" sparc_cflags="" diff --git a/BUILD/compile-amd64-debug-wsrep b/BUILD/compile-amd64-debug-wsrep new file mode 100644 index 00000000000..995a8afcca9 --- /dev/null +++ b/BUILD/compile-amd64-debug-wsrep @@ -0,0 +1,11 @@ +#! /bin/sh + +path=`dirname $0` +. "$path/SETUP.sh" + +extra_flags="$amd64_cflags $debug_cflags -g -O0 $wsrep_cflags" +c_warnings="$c_warnings $debug_extra_warnings" +cxx_warnings="$cxx_warnings $debug_extra_warnings" +extra_configs="$amd64_configs $debug_configs $wsrep_configs --with-wsrep" + +. "$path/FINISH.sh" diff --git a/BUILD/compile-amd64-wsrep b/BUILD/compile-amd64-wsrep new file mode 100644 index 00000000000..57dfbdd6da2 --- /dev/null +++ b/BUILD/compile-amd64-wsrep @@ -0,0 +1,9 @@ +#! /bin/sh + +path=`dirname $0` +. "$path/SETUP.sh" + +extra_flags="$amd64_cflags $fast_cflags -g $wsrep_cflags" +extra_configs="$amd64_configs $wsrep_configs --with-wsrep" + +. "$path/FINISH.sh" diff --git a/BUILD/compile-pentium-debug-wsrep b/BUILD/compile-pentium-debug-wsrep new file mode 100644 index 00000000000..ee68e3fd0c1 --- /dev/null +++ b/BUILD/compile-pentium-debug-wsrep @@ -0,0 +1,12 @@ +#! /bin/sh -x + +path=`dirname $0` +set -- "$@" --with-debug=full +. "$path/SETUP.sh" + +extra_flags="$pentium_cflags $debug_cflags -g -O0 $wsrep_cflags" +c_warnings="$c_warnings $debug_extra_warnings" +cxx_warnings="$cxx_warnings $debug_extra_warnings" +extra_configs="$pentium_configs $debug_configs $wsrep_configs --with-wsrep" + +. "$path/FINISH.sh" diff --git a/BUILD/compile-pentium-wsrep b/BUILD/compile-pentium-wsrep new file mode 100644 index 00000000000..eeb14310e4e --- /dev/null +++ b/BUILD/compile-pentium-wsrep @@ -0,0 +1,11 @@ +#! /bin/sh + +path=`dirname $0` +. "$path/SETUP.sh" + +extra_flags="$pentium_cflags $fast_cflags $wsrep_cflags" +extra_configs="$pentium_configs $wsrep_configs --with-wsrep" + +#strip=yes + +. "$path/FINISH.sh" diff --git a/BUILD/compile-pentium64-wsrep b/BUILD/compile-pentium64-wsrep new file mode 100644 index 00000000000..0bccb34e753 --- /dev/null +++ b/BUILD/compile-pentium64-wsrep @@ -0,0 +1,28 @@ +#! /bin/sh + +# Copyright (C) 2006, 2007 MySQL AB +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +# MA 02111-1307, USA + +path=`dirname $0` +. "$path/SETUP.sh" + +extra_flags="$pentium64_cflags $fast_cflags -g $wsrep_cflags" +extra_configs="$pentium_configs $static_link $wsrep_configs --with-wsrep" +CC="$CC --pipe" +strip=yes + +. "$path/FINISH.sh" diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b5c73b6e6c..68f3b01eb28 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -158,6 +158,7 @@ INCLUDE(ctest) INCLUDE(plugin) INCLUDE(install_macros) INCLUDE(mysql_add_executable) +INCLUDE(wsrep) # Handle options OPTION(DISABLE_SHARED @@ -235,6 +236,12 @@ OPTION(ENABLED_LOCAL_INFILE OPTION(WITH_FAST_MUTEXES "Compile with fast mutexes" OFF) MARK_AS_ADVANCED(WITH_FAST_MUTEXES) +OPTION(WITH_INNODB_DISALLOW_WRITES "InnoDB freeze writes patch from Google" ${WITH_WSREP}) +IF (WITH_INNODB_DISALLOW_WRITES) + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWITH_INNODB_DISALLOW_WRITES") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWITH_INNODB_DISALLOW_WRITES") +ENDIF() + # Set DBUG_OFF and other optional release-only flags for non-debug project types FOREACH(BUILD_TYPE RELEASE RELWITHDEBINFO MINSIZEREL) FOREACH(LANG C CXX) @@ -369,6 +376,9 @@ ADD_SUBDIRECTORY(vio) ADD_SUBDIRECTORY(mysys) ADD_SUBDIRECTORY(mysys_ssl) ADD_SUBDIRECTORY(libmysql) +IF(WITH_WSREP) + ADD_SUBDIRECTORY(wsrep) +ENDIF() ADD_SUBDIRECTORY(client) ADD_SUBDIRECTORY(extra) ADD_SUBDIRECTORY(libservices) @@ -447,6 +457,7 @@ INSTALL_DOCUMENTATION(${CMAKE_BINARY_DIR}/Docs/INFO_SRC IF(UNIX) INSTALL_DOCUMENTATION(Docs/INSTALL-BINARY COMPONENT Readme) + INSTALL_DOCUMENTATION(Docs/INSTALL-BINARY Docs/README-wsrep COMPONENT Readme) ENDIF() INCLUDE(CPack) diff --git a/Docs/README-wsrep b/Docs/README-wsrep new file mode 100644 index 00000000000..422ec52f48a --- /dev/null +++ b/Docs/README-wsrep @@ -0,0 +1,488 @@ +Codership Oy +http://www.codership.com + + +DISCLAIMER + +THIS SOFTWARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER +EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +IN NO EVENT SHALL CODERSHIP OY BE HELD LIABLE TO ANY PARTY FOR ANY DAMAGES +RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE. + +Trademark Information. + +MySQL is a trademark or registered trademark of Oracle and/or its affiliates. +Other trademarks are the property of their respective owners. + +Licensing Information. + +Please see file COPYING that came with this distribution + +Source code can be found at +wsrep API: https://launchpad.net/wsrep +MySQL patch: https://launchpad.net/codership-mysql + + +ABOUT THIS DOCUMENT + +This document covers installation and configuration issues specific to this +wsrep-patched MySQL distribution by Codership. It does not cover the use or +administration of MySQL server per se. The reader is assumed to know how to +install, configure, administer and use standard MySQL server version 5.1.xx. + + + MYSQL-5.5.x/wsrep-23.x + +CONTENTS: +========= +1. WHAT IS WSREP PATCH FOR MYSQL +2. INSTALLATION +3. FIRST TIME SETUP + 3.1 CONFIGURATION FILES + 3.2 DATABASE PRIVILEGES + 3.3 CHECK AND CORRECT FIREWALL SETTINGS + 3.4 SELINUX + 3.5 APPARMOR + 3.6 CONNECT TO CLUSTER +4. UPGRADING FROM MySQL 5.1.x +5. CONFIGURATION OPTIONS + 5.1 MANDATORY MYSQL OPTIONS + 5.2 WSREP OPTIONS +6. ONLINE SCHEMA UPGRADE + 6.1 TOTAL ORDER ISOLATION (TOI) + 6.2 ROLLING SCHEMA UPGRADE (RSU) +7. LIMITATIONS + + +1. WHAT IS WSREP PATCH FOR MYSQL/INNODB + +Wsrep API developed by Codership Oy is a modern generic (database-agnostic) +replication API for transactional databases with a goal to make database +replication/logging subsystem completely modular and pluggable. It is developed +with flexibility and completeness in mind to satisfy broad range of modern +replication scenarios. It is equally suitable for synchronous and asynchronous, +master-slave and multi-master replication. + +wsrep stands for Write Set REPlication. + +Wsrep patch for MySQL/InnoDB allows MySQL server to load and use various wsrep +API implementations ("wsrep providers") with different qualities of service. +Without wsrep provider MySQL-wsrep server will function like a regular +standalone server. + + +2. INSTALLATION + +In the examples below mysql authentication options are omitted for brevity. + +2.1 Download and install mysql-wsrep package. + +Download binary package for your Linux distribution from +https://launchpad.net/codership-mysql/ + +2.1.1 On Debian and Debian-derived distributions. + +Upgrade from mysql-server-5.0 to mysql-wsrep is not supported yet, please +upgrade to mysql-server-5.1 first. + +If you're installing over an existing mysql installation, mysql-server-wsrep +will conflict with mysql-server-5.1 package, so remove it first: + +$ sudo apt-get remove mysql-server-5.1 mysql-server-core-5.1 + +mysql-server-wsrep requires psmisc and mysql-client-5.1.47 (or later). +MySQL 5.1 packages can be found from backports repositories. +For further information about configuring and using Debian or Ubuntu +backports, see: + +* http://backports.debian.org + +* https://help.ubuntu.com/community/UbuntuBackports + +For example, installation of required packages on Debian Lenny: + +$ sudo apt-get install psmisc +$ sudo apt-get -t lenny-backports install mysql-client-5.1 + +Now you should be able to install mysql-wsrep package: + +$ sudo dpkg -i + +2.1.2 On CentOS and similar RPM-based distributions. + +If you're migrating from existing MySQL installation, there are two variants: + + a) If you're already using official MySQL-server-community 5.1.x RPM from + Oracle: + + # rpm -e mysql-server + + b) If you're upgrading from the stock mysql-5.0.77 on CentOS: + + 1) Make sure that the following packages are not installed: + # rpm --nodeps --allmatches -e mysql-server mysql-test mysql-bench + + 2) Install *official* MySQL-shared-compat-5.1.x from + http://dev.mysql.com/downloads/mysql/5.1.html + +Actual installation: + + # rpm -Uvh + + If this fails due to unsatisfied dependencies, install missing packages + (e.g. yum install perl-DBI) and retry. + +Additional packages to consider (if not yet installed): + * galera (multi-master replication provider, https://launchpad.net/galera) + * MySQL-client-community (for connecting to server and mysqldump-based SST) + * rsync (for rsync-based SST) + * xtrabackup and nc (for xtrabackup-based SST) + +2.2 Upgrade system tables. + +If you're upgrading a previous MySQL installation, it might be advisable to +upgrade system tables. To do that start mysqld and run mysql_upgrade command. +Consult MySQL documentation in case of errors. Normally they are not critical +and can be ignored unless specific functionality is needed. + + +3. FIRST TIME SETUP + +Unless you're upgrading an already installed mysql-wsrep package, you will need +to set up a few things to prepare server for operation. + +3.1 CONFIGURATION FILES + +* Make sure system-wide my.cnf does not bind mysqld to 127.0.0.1. That is, if + you have the following line in [mysqld] section, comment it out: + + #bind-address = 127.0.0.1 + +* Make sure system-wide my.cnf contains "!includedir /etc/mysql/conf.d/" line. + +* Edit /etc/mysql/conf.d/wsrep.cnf and set wsrep_provider option by specifying + a path to provider library. If you don't have a provider, leave it as it is. + +* When a new node joins the cluster it'll have to receive a state snapshot from + one of the peers. This requires a privileged MySQL account with access from + the rest of the cluster. Edit /etc/mysql/conf.d/wsrep.cnf and set mysql + login/password pair for SST, for example: + + wsrep_sst_auth=wsrep_sst:wspass + +* See CONFIGURATION section below about other configuration parameters that you + might want to change at this point. + +3.2 DATABASE PRIVILEGES + +Restart MySQL server and connect to it as root to grant privileges to SST +account (empty users confuse MySQL authentication matching rules, we need to +delete them too): + +$ mysql -e "SET wsrep_on=OFF; DELETE FROM mysql.user WHERE user='';" +$ mysql -e "SET wsrep_on=OFF; GRANT ALL ON *.* TO wsrep_sst@'%' IDENTIFIED BY 'wspass'"; + +3.3 CHECK AND CORRECT FIREWALL SETTINGS. + +MySQL-wsrep server needs to be accessible from other cluster members through +its client listening socket and through wsrep provider socket. See your +distribution and wsrep provider documentation for details. For example on +CentOS you might need to do something along these lines: + +# iptables --insert RH-Firewall-1-INPUT 1 --proto tcp --source /24 --destination /32 --dport 3306 -j ACCEPT +# iptables --insert RH-Firewall-1-INPUT 1 --proto tcp --source /24 --destination /32 --dport 4567 -j ACCEPT + +If there is a NAT firewall between the nodes, it must be configured to allow +direct connections between the nodes (e.g. via port forwarding). + +3.4 SELINUX + +If you have SELinux enabled, it may block mysqld from doing required operations. +You'll need to either disable it or configure to allow mysqld to run external +programs and open listen sockets at unprivileged ports (i.e. things that +an unprivileged user can do). See SELinux documentation about it. + +To quickly disable SELinux: +1) run 'setenforce 0' as root. +2) set 'SELINUX=permissive' in /etc/selinux/config + +3.5 APPARMOR + +AppArmor automatically comes with Ubuntu and may also prevent mysqld to from +opening additional ports or run scripts. See AppArmor documentation about its +configuration. To disable AppArmor for mysqld: + +$ cd /etc/apparmor.d/disable/ +$ sudo ln -s /etc/apparmor.d/usr.sbin.mysqld +$ sudo service apparmor restart + + +3.6 CONNECT TO CLUSTER + +Now you're ready to connect to cluster by setting wsrep_cluster_address variable +and monitor status of wsrep provider: + +mysql> SET GLOBAL wsrep_cluster_address=''; +mysql> SHOW STATUS LIKE 'wsrep%'; + + +4 UPGRADING FROM MySQL 5.1.x + +!!! THESE INSTRUCTIONS ARE PRELIMINARY AND INCOMPLETE !!! + +1) BEFORE UPGRADE (while running 5.1.x): + - comment out 'wsrep_provider' setting from configuration files + (my.cnf and/or wsrep.cnf) + - If performing a rolling upgrade on a running cluster, set + wsrep_sst_method=mysqldump. + You might also need to configure wsrep_sst_receive_address and + wsrep_sst_auth appropriately. mysqldump is the only way to transfer data + from 5.1.x to 5.5.x reliably. + - remove innodb_plugin settings from configuration files. + +2) Perform upgrade as usual: + http://dev.mysql.com/doc/refman/5.5/en/upgrading-from-previous-series.html + Don't forget to run 'mysql_upgrade' command. + +3) AFTER UPGRADING individual node: + - uncomment 'wsrep_provider' line in configuration file. + - restart the server and join the cluster. + +4) AFTER UPGRADING the whole cluster: + - revert to usual wsrep SST settings if not 'mysqldump'. + + +5. CONFIGURATION OPTIONS + +5.1 MANDATORY MYSQL OPTIONS + +binlog_format=ROW + This option is required to use row-level replication as opposed to + statement-level. For performance and consistency considerations don't change + that. As a side effect, binlog, if turned on, can be ROW only. In future this + option won't have special meaning. + +innodb_autoinc_lock_mode=2 + This is a required parameter. Without it INSERTs into tables with + AUTO_INCREMENT column may fail. + autoinc lock modes 0 and 1 can cause unresolved deadlock, and make + system unresponsive. + +innodb_locks_unsafe_for_binlog=1 + This option is required for parallel applying. + +5.2 WSREP OPTIONS + +All options are optional except for wsrep_provider, wsrep_cluster_address, and +wsrep_sst_auth. + +wsrep_provider=none + A full path to the library that implements WSREP interface. If none is + specified, the server behaves like a regular mysqld. + +wsrep_provider_options= + Provider-specific option string. Check wsrep provider documentation or + http://www.codership.com/wiki + +wsrep_cluster_address= + Provider-specific cluster address string. This is used to connect a node to + the desired cluster. This option can be given either on mysqld startup or set + during runtime. See wsrep provider documentation for possible values. + +wsrep_cluster_name="my_wsrep_cluster" + Logical cluster name, must be the same for all nodes of the cluster. + +wsrep_node_address= + An option to explicitly specify the network address of the node in the form +
[:port] if autoguessing for some reason does not produce desirable + results (multiple network interfaces, NAT, etc.) + If not explicitly overridden by wsrep_sst_receive_address, the
part + will be used to listen for SST (see below). And the whole
[:port] + will be passed to wsrep provider to be used as a base address in its + communications. + +wsrep_node_name= + Human readable node name (for easier log reading only). Defaults to hostname. + +wsrep_slave_threads=1 + Number of threads dedicated to processing of writesets from other nodes. + For best performance should be few per CPU core. + +wsrep_dbug_option + Options for the built-in DBUG library (independent from what MySQL uses). + Empty by default. Not currently in use. + +wsrep_debug=0 + Enable debug-level logging. + +wsrep_convert_LOCK_to_trx=0 + Implicitly convert locking sessions into transactions inside mysqld. By + itself it does not mean support for locking sessions, but it prevents the + database from going into logically inconsistent state. Note however, that + loading large database dump with LOCK statements might result in abnormally + large transactions and cause an out-of-memory condition + +wsrep_retry_autocommit=1 + Retry autocommit queries and single statement transactions should they fail + certification test. This is analogous to rescheduling an autocommit query + should it go into deadlock with other transactions in the database lock + manager. + +wsrep_auto_increment_control=1 + Automatically adjust auto_increment_increment and auto_increment_offset + variables based on the number of nodes in the cluster. Significantly reduces + certification conflict rate for INSERTS. + +wsrep_drupal_282555_workaround=1 + MySQL seems to have an obscure bug when INSERT into table with + AUTO_INCREMENT column with NULL value for that column can fail with a + duplicate key error. When this option is on, it retries such INSERTs. + Required for stable Drupal operation. Documented at: + http://bugs.mysql.com/bug.php?id=41984 + http://drupal.org/node/282555 + +wsrep_causal_reads=0 + Enforce strict READ COMMITTED semantics on reads and transactions. May + result in additional latencies. It is a session variable. + +wsrep_OSU_method=TOI + Online Schema Upgrade (OSU) can be performed with two alternative methods: + Total Order Isolation (TOI) runs DDL statement in all cluster nodes in + same total order sequence locking the affected table for the duration of the + operation. This may result in the whole cluster being blocked for the + duration of the operation. + Rolling Schema Upgrade (RSU) executes the DDL statement only locally, thus + blocking only one cluster node. During the DDL processing, the node + is not replicating and may be unable to process replication events (due to + table lock). Once DDL operation is complete, the node will catch up and sync + with the cluster to become fully operational again. The DDL statement or + its effects are not replicated, so it is user's responsibility to manually + perform this operation on each of the nodes. + +wsrep_forced_binlog_format=none + Force every transaction to use given binlog format. When this variable is + set to something else than NONE, all transactions will use the given forced + format, regardless of what the client session has specified in binlog_format. + Valid choices for wsrep_forced_binlog_format are: ROW, STATEMENT, MIXED and + special value NONE, meaning that there is no forced binlog format in effect. + This variable was intruduced to support STATEMENT format replication during + rolling schema upgrade processing. However, in most cases ROW replication + is valid for asymmetrict schema replication. + +State snapshot transfer options. + +When a new node joins the cluster it has to synchronize its initial state with +the other cluster members by transferring state snapshot from one of them. +The options below govern how this happens and should be set up before attempting +to join or start a cluster. + +wsrep_sst_method=rsync + What method to use to copy database state to a newly joined node. Supported + methods: + - mysqldump: slow (except for small datasets) but allows for upgrade + between major MySQL versions or InnoDB features. + - rsync: much faster on large datasets (default). + - rsync_wan: same as rsync but with deltaxfer to minimize network traffic. + - xtrabackup: very fast and practically non-blocking SST method based on + Percona's xtrabackup tool. + + (for xtrabackup to work the following settings must be present in my.cnf + on all nodes: + [mysqld] + wsrep_sst_auth=root: + datadir= + [client] + socket= + ) + +wsrep_sst_receive_address= + Address (hostname:port) at which this node wants to receive state snapshot. + Defaults to mysqld bind address, and if that is not specified (0.0.0.0) - + to the first IP of eth0 + mysqld bind port. + NOTE: check that your firewall allows connections to this address from other + cluster nodes. + +wsrep_sst_auth= + Authentication information needed for state transfer. Depends on the state + transfer method. For mysqldump-based SST it is + : + and should be the same on all nodes - it is used to authenticate with both + state snapshot receiver and state snapshot donor. + +wsrep_sst_donor= + A name of the node which should serve as state snapshot donor. This allows + to control which node will serve state snapshot request. By default the + most suitable node is chosen by wsrep provider. This is the same as given in + wsrep_node_name. + + +6. ONLINE SCHEMA UPGRADE + + Schema upgrades mean any data definition statements (DDL statemnents) run + for the database. They change the database structure and are non- + transactional. + + Release 22.3 brings a new method for performing schema upgrades. User can + now choose whether to use the traditional total order isolation or new + rolling schema upgrade method. The OSU method choice is done by global + parameter: 'wsrep_OSU_method'. + +6.1 Total Order Isolation (TOI) + + With earlier releases, DDL processing happened always by Total Order + Isolation (TOI) method. With TOI, the DDL was scheduled to be processed in + same transaction seqeuncing 'slot' in each cluster node. + The processing is secured by locking the affected table from any other use. + With TOI method, the whole cluster has part of the database locked for the + duration of the DDL processing. + +6.2 Rolling Schema Upgrade (RSU) + + Rolling schema upgrade is new DDL processing method, where DDL will be + processed locally for the node. The node is disconnected of the replication + for the duration of the DDL processing, so that there is only DDL statement + processing in the node and it does not block the rest of the cluster. When + the DDL processing is complete, the node applies delayed replication events + and synchronizes back with the cluster. + The DDL can then be executed cluster-wide by running the same DDL statement + for each node in turn. When this rolling schema upgrade proceeds, part of + the cluster will have old schema structure and part of the cluster will have + new schema structure. + + +7. LIMITATIONS + +1) Currently replication works only with InnoDB storage engine. Any writes to + tables of other types, including system (mysql.*) tables are not replicated. + However, DDL statements are replicated in statement level, and changes + to mysql.* tables will get replicated that way. + So, you can safely issue: CREATE USER..., + but issuing: INSERT INTO mysql.user..., will not be replicated. + +2) DELETE operation is unsupported on tables without primary key. Also rows in + tables without primary key may appear in different order on different nodes. + As a result SELECT...LIMIT... may return slightly different sets. + +3) Unsupported queries: + * LOCK/UNLOCK TABLES cannot be supported in multi-master setups. + * lock functions (GET_LOCK(), RELEASE_LOCK()... ) + +4) Query log cannot be directed to table. If you enable query logging, + you must forward the log to a file: + log_output = FILE + Use general_log and general_log_file to choose query logging and the + log file name + +5) Maximum allowed transaction size is defined by wsrep_max_ws_rows and + wsrep_max_ws_size. Anything bigger (e.g. huge LOAD DATA) will be rejected. + +6) Due to cluster level optimistic concurrency control, transaction issuing + COMMIT may still be aborted at that stage. There can be two transactions. + writing to same rows and committing in separate cluster nodes, and only one + of the them can successfully commit. The failing one will be aborted. + For cluster level aborts, MySQL/galera cluster gives back deadlock error. + code (Error: 1213 SQLSTATE: 40001 (ER_LOCK_DEADLOCK)). + +7) XA transactions can not be supported due to possible rollback on commit. + diff --git a/client/client_priv.h b/client/client_priv.h index 656c8fcf32a..dddf934e509 100644 --- a/client/client_priv.h +++ b/client/client_priv.h @@ -92,6 +92,9 @@ enum options_client OPT_REPORT_PROGRESS, OPT_SKIP_ANNOTATE_ROWS_EVENTS, OPT_SSL_CRL, OPT_SSL_CRLPATH, +#ifdef WITH_WSREP + OPT_GALERA_SST_MODE, +#endif OPT_MAX_CLIENT_OPTION /* should be always the last */ }; diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index 80d57ce9faa..bf33397efdb 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -523,7 +523,12 @@ static int run_query(const char *query, DYNAMIC_STRING *ds_res, int ret; File fd; char query_file_path[FN_REFLEN]; +#ifdef WITH_WSREP + /* Note: wsrep_on=ON implicitly enables binary logging. */ + const uchar sql_log_bin[]= "SET SQL_LOG_BIN=0, WSREP_ON=OFF;"; +#else const uchar sql_log_bin[]= "SET SQL_LOG_BIN=0;"; +#endif /* WITH_WSREP */ DBUG_ENTER("run_query"); DBUG_PRINT("enter", ("query: %s", query)); diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index 57b7ce09ab5..f7ae0783e5e 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -731,9 +731,15 @@ static int use_db(char *database) DBUG_RETURN(0); } /* use_db */ +/* Do not send commands to replication slaves. */ static int disable_binlog() { +#ifdef WITH_WSREP + /* Additionally turn off @@wsrep_on to disable implicit binary logging. */ + const char *stmt= "SET SQL_LOG_BIN=0, WSREP_ON=OFF"; +#else const char *stmt= "SET SQL_LOG_BIN=0"; +#endif /* WITH_WSREP */ return run_query(stmt); } diff --git a/client/mysqldump.c b/client/mysqldump.c index cb4fa022d4f..3485f9cbd47 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -111,6 +111,9 @@ static my_bool verbose= 0, opt_no_create_info= 0, opt_no_data= 0, opt_slave_apply= 0, opt_include_master_host_port= 0, opt_events= 0, opt_comments_used= 0, +#ifdef WITH_WSREP + opt_galera_sst_mode= 0, +#endif opt_alltspcs=0, opt_notspcs= 0; static my_bool insert_pat_inited= 0, debug_info_flag= 0, debug_check_flag= 0; static ulong opt_max_allowed_packet, opt_net_buffer_length; @@ -346,6 +349,14 @@ static struct my_option my_long_options[] = {"force", 'f', "Continue even if we get an SQL error.", &ignore_errors, &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, +#ifdef WITH_WSREP + {"galera-sst-mode", OPT_GALERA_SST_MODE, "This mode is normally used " + "in mysqldump snapshot-state transfer in a Galera cluster. If enabled, " + "mysqldump additionally emits statements to turn off binary logging and " + "set global gtid_binlog_state with the current value.", + &opt_galera_sst_mode, &opt_galera_sst_mode, 0, GET_BOOL, NO_ARG, 0, 0, 0, + 0, 0, 0}, +#endif {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"hex-blob", OPT_HEXBLOB, "Dump binary strings (BINARY, " @@ -4799,6 +4810,44 @@ static int dump_selected_tables(char *db, char **table_names, int tables) } /* dump_selected_tables */ +#ifdef WITH_WSREP +/** + Additionally emit the following statements : + a) SET @@session.sql_log_bin=OFF; + b) SET @@global.gtid_binlog_state='[N-N-N,...]' +*/ +static int wsrep_add_sst_mode_cmds(MYSQL *mysql) { + MYSQL_RES *res; + MYSQL_ROW row; + + if (mysql_get_server_version(mysql) < 100005) { + /* @@gtid_binlog_state does not exist. */ + return 0; + } + + if (mysql_query_with_error_report(mysql, &res, "SELECT " + "@@global.gtid_binlog_state")) + return 1; + + if (mysql_num_rows(res) != 1) + /* No entry for @@global.gtid_binlog_state, nothing needs to be done. */ + return 0; + + if (!(row= mysql_fetch_row(res)) || !(char *)row[0]) + return 1; + + /* first, add a command to turn off binary logging, */ + fprintf(md_result_file, "SET @@session.sql_log_bin=OFF;\n"); + + /* followed by, a command to set global gtid_binlog_state. */ + fprintf(md_result_file, "SET @@global.gtid_binlog_state='%s';\n", + (char*)row[0]); + + mysql_free_result(res); + return 0; +} +#endif + static int do_show_master_status(MYSQL *mysql_con, int consistent_binlog_pos) { MYSQL_ROW row; @@ -5743,6 +5792,12 @@ int main(int argc, char **argv) /* Add 'STOP SLAVE to beginning of dump */ if (opt_slave_apply && add_stop_slave()) goto err; + +#ifdef WITH_WSREP + if (opt_galera_sst_mode && wsrep_add_sst_mode_cmds(mysql)) + goto err; +#endif + if (opt_master_data && do_show_master_status(mysql, consistent_binlog_pos)) goto err; if (opt_slave_data && do_show_slave_status(mysql)) diff --git a/cmake/cpack_rpm.cmake b/cmake/cpack_rpm.cmake index 30924120526..d8f659ec5ea 100644 --- a/cmake/cpack_rpm.cmake +++ b/cmake/cpack_rpm.cmake @@ -147,9 +147,10 @@ SETA(CPACK_RPM_test_PACKAGE_OBSOLETES SETA(CPACK_RPM_test_PACKAGE_PROVIDES "MySQL-test") -SETA(CPACK_RPM_server_PACKAGE_REQUIRES - ${CPACK_RPM_PACKAGE_REQUIRES} - "MariaDB-client") +SETA(CPACK_RPM_server_PACKAGE_REQUIRES + "${CPACK_RPM_PACKAGE_REQUIRES}" + "MariaDB-client" "galera" "rsync" "lsof" "socat" "grep" "gawk" "iproute" + "coreutils" "findutils") SET(CPACK_RPM_server_PRE_INSTALL_SCRIPT_FILE ${CMAKE_SOURCE_DIR}/support-files/rpm/server-prein.sh) SET(CPACK_RPM_server_PRE_UNINSTALL_SCRIPT_FILE ${CMAKE_SOURCE_DIR}/support-files/rpm/server-preun.sh) diff --git a/cmake/plugin.cmake b/cmake/plugin.cmake index b550695b796..2dc88782937 100644 --- a/cmake/plugin.cmake +++ b/cmake/plugin.cmake @@ -153,6 +153,14 @@ MACRO(MYSQL_ADD_PLUGIN) ADD_DEPENDENCIES(${target}_embedded GenError) ENDIF() ENDIF() + + IF (WITH_WSREP) + # Set compile definitions for non-embedded plugins + LIST(APPEND wsrep_definitions "WITH_WSREP") + LIST(APPEND wsrep_definitions "WSREP_PROC_INFO") + SET_TARGET_PROPERTIES(${target} PROPERTIES + COMPILE_DEFINITIONS "${wsrep_definitions}") + ENDIF() IF(ARG_STATIC_OUTPUT_NAME) SET_TARGET_PROPERTIES(${target} PROPERTIES @@ -185,8 +193,17 @@ MACRO(MYSQL_ADD_PLUGIN) ADD_VERSION_INFO(${target} MODULE SOURCES) ADD_LIBRARY(${target} MODULE ${SOURCES}) DTRACE_INSTRUMENT(${target}) + + LIST(APPEND dyn_compile_definitions "MYSQL_DYNAMIC_PLUGIN") + + IF (WITH_WSREP) + LIST(APPEND dyn_compile_definitions "WITH_WSREP") + LIST(APPEND dyn_compile_definitions "WSREP_PROC_INFO") + ENDIF() + SET_TARGET_PROPERTIES (${target} PROPERTIES PREFIX "" - COMPILE_DEFINITIONS "MYSQL_DYNAMIC_PLUGIN") + COMPILE_DEFINITIONS "${dyn_compile_definitions}") + TARGET_LINK_LIBRARIES (${target} mysqlservices ${ARG_LINK_LIBRARIES}) # Plugin uses symbols defined in mysqld executable. @@ -207,7 +224,8 @@ MACRO(MYSQL_ADD_PLUGIN) OUTPUT_NAME "${ARG_MODULE_OUTPUT_NAME}") # Install dynamic library IF(ARG_COMPONENT) - IF(CPACK_COMPONENTS_ALL AND NOT CPACK_COMPONENTS_ALL MATCHES ${ARG_COMPONENT}) + IF(CPACK_COMPONENTS_ALL AND + NOT CPACK_COMPONENTS_ALL MATCHES ${ARG_COMPONENT}) SET(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} ${ARG_COMPONENT} PARENT_SCOPE) SET(CPACK_RPM_${ARG_COMPONENT}_PACKAGE_REQUIRES "MariaDB-server" PARENT_SCOPE) diff --git a/cmake/wsrep.cmake b/cmake/wsrep.cmake new file mode 100644 index 00000000000..349c8ace9a8 --- /dev/null +++ b/cmake/wsrep.cmake @@ -0,0 +1,76 @@ +# Copyright (c) 2011, Codership Oy . +# Copyright (c) 2013, Monty Program Ab. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +# We need to generate a proper spec file even without --with-wsrep flag, +# so WSREP_VERSION is produced regardless + +# Set the patch version +SET(WSREP_PATCH_VERSION "10") + +# MariaDB addition: Revision number of the last revision merged from +# codership branch visible in @@visible_comment. +# Branch : codership-mysql/5.5 +SET(WSREP_PATCH_REVNO "4002") # Should be updated on every merge. + +# MariaDB addition: Revision number of the last revision merged from +# Branch : lp:maria/maria-10.0-galera +SET(WSREP_PATCH_REVNO2 "3867") # Should be updated on every merge. + +# MariaDB: Obtain patch revision number: +# Update WSREP_PATCH_REVNO if WSREP_REV environment variable is set. +IF (DEFINED ENV{WSREP_REV}) + SET(WSREP_PATCH_REVNO $ENV{WSREP_REV}) +ENDIF() + +# Obtain wsrep API version +EXECUTE_PROCESS( + COMMAND sh -c "grep WSREP_INTERFACE_VERSION ${MySQL_SOURCE_DIR}/wsrep/wsrep_api.h | cut -d '\"' -f 2" + OUTPUT_VARIABLE WSREP_API_VERSION + RESULT_VARIABLE RESULT +) +#FILE(WRITE "wsrep_config" "Debug: WSREP_API_VERSION result: ${RESULT}\n") +STRING(REGEX REPLACE "(\r?\n)+$" "" WSREP_API_VERSION "${WSREP_API_VERSION}") + +IF(NOT WSREP_PATCH_REVNO) + MESSAGE(WARNING "Could not determine bzr revision number, WSREP_VERSION will " + "not contain the revision number.") + SET(WSREP_VERSION + "${WSREP_API_VERSION}.${WSREP_PATCH_VERSION}" + ) +ELSE() + SET(WSREP_VERSION + "${WSREP_API_VERSION}.${WSREP_PATCH_VERSION}.r${WSREP_PATCH_REVNO}" + ) +ENDIF() + +# +# Galera library does not compile with windows and solaris +# +IF(UNIX) +OPTION(WITH_WSREP "WSREP replication API (to use, e.g. Galera Replication library)" ON) +ELSE() +OPTION(WITH_WSREP "WSREP replication API (to use, e.g. Galera Replication library)" OFF) +ENDIF() + +MACRO (BUILD_WITH_WSREP) + SET(WSREP_C_FLAGS "-DWITH_WSREP -DWSREP_PROC_INFO -DMYSQL_MAX_VARIABLE_VALUE_LEN=2048") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WSREP_C_FLAGS}") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WSREP_C_FLAGS}") + SET(COMPILATION_COMMENT "${COMPILATION_COMMENT}, wsrep_${WSREP_VERSION}") + #SET(WITH_EMBEDDED_SERVER OFF CACHE INTERNAL "" FORCE) +ENDMACRO() + +# diff --git a/debian/dist/Debian/control b/debian/dist/Debian/control index bbee264ffc3..869e9be032c 100644 --- a/debian/dist/Debian/control +++ b/debian/dist/Debian/control @@ -192,7 +192,7 @@ Architecture: any Suggests: tinyca, mailx, mariadb-test Recommends: libhtml-template-perl Pre-Depends: mariadb-common, adduser (>= 3.40), debconf -Depends: mariadb-client-10.1 (>= ${source:Version}), libdbi-perl, perl (>= 5.6), ${shlibs:Depends}, ${misc:Depends}, psmisc, passwd, lsb-base (>= 3.0-10), mariadb-server-core-10.1 (>= ${binary:Version}) +Depends: mariadb-client-10.1 (>= ${source:Version}), libdbi-perl, perl (>= 5.6), ${shlibs:Depends}, ${misc:Depends}, psmisc, passwd, lsb-base (>= 3.0-10), mariadb-server-core-10.1 (>= ${binary:Version}), galera (>=25.2) rsync, lsof, socat, grep, gawk, iproute, coreutils, findutils Provides: mariadb-server, mysql-server, virtual-mysql-server Conflicts: mariadb-server (<< ${source:Version}), mysql-server (<< ${source:Version}), mysql-server-4.1, mysql-server-5.0, mysql-server-5.1, mysql-server-5.5, diff --git a/debian/dist/Ubuntu/control b/debian/dist/Ubuntu/control index ffcd1e5dca6..941f756ea3c 100644 --- a/debian/dist/Ubuntu/control +++ b/debian/dist/Ubuntu/control @@ -186,7 +186,7 @@ Architecture: any Suggests: tinyca, mailx, mariadb-test Recommends: libhtml-template-perl Pre-Depends: mariadb-common, adduser (>= 3.40), debconf -Depends: mariadb-client-10.1 (>= ${source:Version}), libdbi-perl, perl (>= 5.6), ${shlibs:Depends}, ${misc:Depends}, psmisc, passwd, lsb-base (>= 3.0-10), mariadb-server-core-10.1 (>= ${binary:Version}) +Depends: mariadb-client-10.1 (>= ${source:Version}), libdbi-perl, perl (>= 5.6), ${shlibs:Depends}, ${misc:Depends}, psmisc, passwd, lsb-base (>= 3.0-10), mariadb-server-core-10.1 (>= ${binary:Version}), galera (>=25.2) rsync, lsof, socat, grep, gawk, iproute, coreutils, findutils Provides: mariadb-server, mysql-server, virtual-mysql-server Conflicts: mariadb-server (<< ${source:Version}), mysql-server (<< ${source:Version}), mysql-server-4.1, mysql-server-5.0, mysql-server-5.1, mysql-server-5.5, diff --git a/include/mysql/service_logger.h b/include/mysql/service_logger.h index 962ab2fbc0b..d14b28da712 100644 --- a/include/mysql/service_logger.h +++ b/include/mysql/service_logger.h @@ -71,7 +71,7 @@ extern struct logger_service_st { int (*rotate)(LOGGER_HANDLE *log); } *logger_service; -#if MYSQL_DYNAMIC_PLUGIN +#ifdef MYSQL_DYNAMIC_PLUGIN #define logger_init_mutexes logger_service->logger_init_mutexes #define logger_open(path, size_limit, rotations) \ diff --git a/include/mysqld_default_groups.h b/include/mysqld_default_groups.h index a2e94ddd854..30dfdae1338 100644 --- a/include/mysqld_default_groups.h +++ b/include/mysqld_default_groups.h @@ -5,4 +5,7 @@ const char *load_default_groups[]= { "mysqld", "server", MYSQL_BASE_VERSION, "mariadb", MARIADB_BASE_VERSION, "client-server", +#ifdef WITH_WSREP +"galera", +#endif 0, 0}; diff --git a/include/thr_lock.h b/include/thr_lock.h index 3f7a5ca988f..f05db666da9 100644 --- a/include/thr_lock.h +++ b/include/thr_lock.h @@ -20,6 +20,15 @@ #ifdef __cplusplus extern "C" { #endif +#ifdef WITH_WSREP +#include + typedef my_bool (* wsrep_thd_is_brute_force_fun)(void *, my_bool); + typedef int (* wsrep_abort_thd_fun)(void *, void *, my_bool); + typedef int (* wsrep_on_fun)(void *); + void wsrep_thr_lock_init( + wsrep_thd_is_brute_force_fun bf_fun, wsrep_abort_thd_fun abort_fun, + my_bool debug, my_bool convert_LOCK_to_trx, wsrep_on_fun on_fun); +#endif #include #include @@ -95,6 +104,10 @@ typedef struct st_thr_lock_info { pthread_t thread; my_thread_id thread_id; +#ifdef WITH_WSREP + void *mysql_thd; // THD pointer + my_bool in_lock_tables; // true, if inside locking session +#endif } THR_LOCK_INFO; diff --git a/mysql-test/extra/binlog_tests/binlog.test b/mysql-test/extra/binlog_tests/binlog.test index ce5dde97894..831c6c886d5 100644 --- a/mysql-test/extra/binlog_tests/binlog.test +++ b/mysql-test/extra/binlog_tests/binlog.test @@ -372,7 +372,8 @@ dfLtTBcBAAAAIgAAAPkAAAAAABcAAAAAAAcAAf/+AQAAAA== SELECT * FROM t1; --echo # Their values should be ON -SHOW SESSION VARIABLES LIKE "%_checks"; +SHOW SESSION VARIABLES LIKE "foreign_key_checks"; +SHOW SESSION VARIABLES LIKE "unique_checks"; --echo SET @@SESSION.foreign_key_checks= OFF; @@ -387,7 +388,8 @@ dfLtTBcBAAAAIgAAAM0BAAAAABcAAAAAAAEAAf/+AgAAAA== SELECT * FROM t1; --echo # Their values should be OFF -SHOW SESSION VARIABLES LIKE "%_checks"; +SHOW SESSION VARIABLES LIKE "foreign_key_checks"; +SHOW SESSION VARIABLES LIKE "unique_checks"; --echo # INSERT INTO t1 VALUES(2) --echo # foreign_key_checks=1 and unique_checks=1 @@ -401,7 +403,8 @@ dfLtTBcBAAAAIgAAAM0BAAAAABcAAAAAAAEAAf/+AgAAAA== SELECT * FROM t1; --echo # Their values should be OFF -SHOW SESSION VARIABLES LIKE "%_checks"; +SHOW SESSION VARIABLES LIKE "foreign_key_checks"; +SHOW SESSION VARIABLES LIKE "unique_checks"; DROP TABLE t1; diff --git a/mysql-test/include/galera_cluster.inc b/mysql-test/include/galera_cluster.inc new file mode 100644 index 00000000000..bc652225722 --- /dev/null +++ b/mysql-test/include/galera_cluster.inc @@ -0,0 +1,10 @@ +# galera_cluster.inc +# ================== +# +# Description +# ----------- +# Configure galera cluster with 2 nodes. +# + +--let $galera_cluster_size = 2 +--source include/galera_init.inc diff --git a/mysql-test/include/galera_connect.inc b/mysql-test/include/galera_connect.inc new file mode 100644 index 00000000000..bfd9b188667 --- /dev/null +++ b/mysql-test/include/galera_connect.inc @@ -0,0 +1,45 @@ +# galera_connect.inc +# ================== +# +# Description +# ----------- +# Open a connection to the specified server number ($galera_server_number). +# The connection itself would be identified by $galera_connection_name. +# +# Parameters +# ---------- +# $galera_connection_name +# Name of the resulting connection. +# +# $galera_server_number +# Sequence number of the node in the galera cluster. +# +# $galera_debug +# Print debug information. +# + +if (!$galera_connection_name) +{ + --die ERROR IN TEST: $galera_connection_name must be set before sourcing include/galera_connect.inc +} + +if (!$galera_server_number) +{ + --die ERROR IN TEST: $galera_server_number must be set before sourcing include/galera_connect.inc +} + +--let $_galera_port= \$NODE_MYPORT_$galera_server_number +if (!$_galera_port) +{ + --echo Bug in test case: '\$NODE_MYPORT_$galera_server_number' not initialized. Check the test's .cfg file. + --die Not all NODE_MYPORT_* environment variables are setup correctly. +} + +if ($galera_debug) +{ + --echo connect($galera_connection_name,127.0.0.1,root,,test,$_galera_port,) +} + +# Open a connection +--connect($galera_connection_name,127.0.0.1,root,,test,$_galera_port,) + diff --git a/mysql-test/include/galera_diff.inc b/mysql-test/include/galera_diff.inc new file mode 100644 index 00000000000..6043b582647 --- /dev/null +++ b/mysql-test/include/galera_diff.inc @@ -0,0 +1,100 @@ +# galera_diff.inc +# =============== +# +# Description +# ----------- +# Compare the output of the given statement on all the nodes of the cluster. +# +# Parameters +# ---------- +# $galera_diff_statement +# Statement for which the output would be compared. +# +# $galera_diff_database +# Database against which the above statement would be executed. +# (Default : test) +# +# $galera_diff_servers +# Comma separated list of servers to executed the diff statement on. If not +# set, a list of servers will be generated based on $galera_cluster_size. +# +# $galerra_debug +# Print debug information. +# + +if (!$galera_diff_statement) +{ + --die ERROR IN TEST: $galera_diff_statement must be set before sourcing include/galera_diff.inc +} + +--let $_galera_diff_database = $galera_diff_database +if (!$_galera_diff_database) +{ + --let $_galera_diff_database = test +} + +--let $_galera_diff_servers= $galera_diff_servers +if (!$_galera_diff_servers) +{ + --let $_i= $galera_cluster_size + --let $_galera_diff_servers= + while ($_i) + { + --let $_galera_diff_servers= $_i,$_galera_diff_servers + --dec $_i + } +} +if ($galera_debug) +{ + --echo \$galera_diff_servers= '$_galera_diff_servers' +} + +if (!$galera_debug) +{ + --disable_query_log +} + +# Generate file containing $galera_diff_statement. We don't pass the +# statement on the command line, because it would be subject to shell +# substitutions. +--let $write_to_file= GENERATE +--let $write_var= $galera_diff_statement +--source include/write_var_to_file.inc +--let $_galera_diff_statement_file= $write_to_file + +if (!$galera_debug) +{ + --enable_query_log +} + +# Compare all servers. +--let $_galera_diff_first= 1 +while ($_galera_diff_servers) +{ + # Set $_galera_diff_server_i to the first number in the list + --let $_galera_diff_server_i= `SELECT SUBSTRING_INDEX('$_galera_diff_servers', ',', 1)` + # Remove $_galera_diff_server_i from the list + --let $_galera_diff_servers= `SELECT SUBSTRING('$_galera_diff_servers', LENGTH('$_galera_diff_server_i') + 2)` + + # Execute statement + --let $_galera_diff_file= $MYSQLTEST_VARDIR/tmp/_galera_diff_server-$_galera_diff_server_i.tmp + --exec $MYSQL --defaults-group-suffix=.$_galera_diff_server_i $_galera_diff_database < $_galera_diff_statement_file > $_galera_diff_file + + # Compare + if (!$_galera_diff_first) + { + if ($galera_debug) + { + --echo diffing $_galera_diff_file and $_galera_diff_prev_file + } + --diff_files $_galera_diff_file $_galera_diff_prev_file + --remove_file $_galera_diff_prev_file + } + --let $_galera_diff_prev_file= $_galera_diff_file + --let $_galera_diff_first= 0 +} + +# Cleanup +--remove_file $_galera_diff_prev_file +--remove_file $_galera_diff_statement_file + diff --git a/mysql-test/include/galera_end.inc b/mysql-test/include/galera_end.inc new file mode 100644 index 00000000000..0fb5479844e --- /dev/null +++ b/mysql-test/include/galera_end.inc @@ -0,0 +1,25 @@ +# galera_end.inc +# ============== +# +# Description +# ----------- +# Closes the connections opened via include/galera_init.inc +# +# Parameters +# ---------- +# $galera_cluster_size +# Number of nodes in the cluster. +# + +--let $_galera_node= $galera_cluster_size + +while ($_galera_node) +{ + if ($galera_debug) + { + --echo Disconnecting node_$_galera_node + } + --disconnect node_$_galera_node + --dec $_galera_node +} + diff --git a/mysql-test/include/galera_init.inc b/mysql-test/include/galera_init.inc new file mode 100644 index 00000000000..79591973862 --- /dev/null +++ b/mysql-test/include/galera_init.inc @@ -0,0 +1,26 @@ +# galera_init.inc +# =============== +# +# Description +# ----------- +# Set up a Galera cluster with $wsrep_cluster_size nodes. +# +# Parameters +# ---------- +# $galera_cluster_size +# Number of nodes in the cluster. +# + +--source include/have_wsrep_enabled.inc + +--let $_galera_node= $galera_cluster_size + +while ($_galera_node) +{ + --let $galera_connection_name= node_$_galera_node + --let $galera_server_number= $_galera_node + --source include/galera_connect.inc + + --dec $_galera_node +} + diff --git a/mysql-test/include/have_wsrep.inc b/mysql-test/include/have_wsrep.inc new file mode 100644 index 00000000000..a3ceae41d40 --- /dev/null +++ b/mysql-test/include/have_wsrep.inc @@ -0,0 +1,8 @@ +# To be used in a test which requires server to be compiled with wsrep support +# (-DWITH_WSREP=ON) and wsrep plugin is ACTIVE. + +if (`SELECT COUNT(*)=0 FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = 'wsrep' AND PLUGIN_STATUS='ACTIVE'`) +{ + --skip Test required wsrep plugin. +} + diff --git a/mysql-test/include/have_wsrep_enabled.inc b/mysql-test/include/have_wsrep_enabled.inc new file mode 100644 index 00000000000..edb919fd852 --- /dev/null +++ b/mysql-test/include/have_wsrep_enabled.inc @@ -0,0 +1,9 @@ +# To be used in a test which requires wsrep plugin to be ACTIVE and enabled +# (i.e. wsrep_on=ON). It includes have_wsrep.inc. + +--source include/have_wsrep.inc + +--require r/have_wsrep.require +disable_query_log; +SHOW VARIABLES LIKE 'wsrep_on'; +enable_query_log; diff --git a/mysql-test/include/mtr_check.sql b/mysql-test/include/mtr_check.sql index e34e32ad1a6..edc15850d97 100644 --- a/mysql-test/include/mtr_check.sql +++ b/mysql-test/include/mtr_check.sql @@ -34,6 +34,7 @@ BEGIN AND variable_name != 'INNODB_USE_NATIVE_AIO' AND variable_name not like 'GTID%POS' AND variable_name != 'GTID_BINLOG_STATE' + AND variable_name != 'WSREP_DATA_HOME_DIR' ORDER BY variable_name; -- Dump all databases, there should be none diff --git a/mysql-test/include/mtr_warnings.sql b/mysql-test/include/mtr_warnings.sql index 0ad1079cd92..06a7b49e979 100644 --- a/mysql-test/include/mtr_warnings.sql +++ b/mysql-test/include/mtr_warnings.sql @@ -226,6 +226,14 @@ INSERT INTO global_suppressions VALUES ("Slave I/O: Notifying master by SET @master_binlog_checksum= @@global.binlog_checksum failed with error.*"), ("Slave I/O: Setting master-side filtering of @@skip_replication failed with error:.*"), ("Slave I/O: Setting @mariadb_slave_capability failed with error:.*"), + + /* + Galera-related warnings. + */ + ("WSREP: Could not open saved state file for reading: .*"), + ("WSREP: last inactive check more than .* skipping check"), + ("WSREP: Gap in state sequence. Need state transfer."), + ("WSREP: Failed to prepare for incremental state transfer: .*"), ("THE_LAST_SUPPRESSION")|| diff --git a/mysql-test/include/not_wsrep.inc b/mysql-test/include/not_wsrep.inc new file mode 100644 index 00000000000..3314b5c8717 --- /dev/null +++ b/mysql-test/include/not_wsrep.inc @@ -0,0 +1,7 @@ +# To be used in a test which should be skipped if server is compiled with wsrep +# support (-DWITH_WSREP=ON) and wsrep plugin is ACTIVE. + +-- require r/not_wsrep.require +disable_query_log; +SELECT VERSION() LIKE '%wsrep%' AS 'HAVE_WSREP'; +enable_query_log; diff --git a/mysql-test/lib/My/ConfigFactory.pm b/mysql-test/lib/My/ConfigFactory.pm index 4e8507a5c4a..488b0823763 100644 --- a/mysql-test/lib/My/ConfigFactory.pm +++ b/mysql-test/lib/My/ConfigFactory.pm @@ -238,6 +238,9 @@ my @mysqld_rules= { 'pid-file' => \&fix_pidfile }, { '#host' => \&fix_host }, { 'port' => \&fix_port }, + # galera base_port and port used during SST + { '#galera_port' => \&fix_port }, + { '#sst_port' => \&fix_port }, { 'socket' => \&fix_socket }, { '#log-error' => \&fix_log_error }, { 'general-log' => 1 }, diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm index 441fd6e6559..7415b229862 100644 --- a/mysql-test/lib/mtr_cases.pm +++ b/mysql-test/lib/mtr_cases.pm @@ -861,6 +861,8 @@ sub collect_one_test_case { # Suite has no config, autodetect which one to use if ($tinfo->{rpl_test}) { $config= "suite/rpl/my.cnf"; + } elsif ($tinfo->{galera_test}) { + $config= "suite/galera/my.cnf"; } else { $config= "include/default_my.cnf"; } @@ -981,6 +983,7 @@ my $tags_map= {'big_test' => ['big_test', 1], 'master-slave' => ['rpl_test', 1], 'ndb_master-slave' => ['rpl_test', 1, 'ndb_test', 1], 'long_test' => ['long_test', 1], + 'galera_init' => ['galera_test', 1], }; my $tags_regex_string= join('|', keys %$tags_map); my $tags_regex= qr:include/($tags_regex_string)\.inc:o; diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index c2d44bf4db1..61f9538c1b4 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -135,6 +135,7 @@ my $opt_start; my $opt_start_dirty; my $opt_start_exit; my $start_only; +my $file_wsrep_provider; END { if ( defined $opt_tmpdir_pid and $opt_tmpdir_pid == $$ ) @@ -412,6 +413,7 @@ sub main { check_ndbcluster_support(); check_ssl_support(); check_debug_support(); + check_wsrep_support(); if (!$opt_suites) { $opt_suites= join ',', collect_default_suites(@DEFAULT_SUITES); @@ -2397,6 +2399,24 @@ sub environment_setup { $ENV{'NDB_EXAMPLES_OUTPUT'}= $path_ndb_testrun_log; } + # ---------------------------------------------------- + # Setup env for wsrep + # ---------------------------------------------------- + if (have_wsrep()) { + if (defined $ENV{'WSREP_PROVIDER'} ) { + # Nothing needs to be done! WSREP_PROVIDER env is already set & checked; + # will be used. + } else { + $ENV{'WSREP_PROVIDER'}= $file_wsrep_provider; + } + + if ($ENV{'WSREP_PROVIDER'} ne "") { + mtr_verbose("WSREP_PROVIDER set to $ENV{'WSREP_PROVIDER'}"); + } else { + mtr_verbose("WSREP_PROVIDER isn't available"); + } + } + # ---------------------------------------------------- # mysql clients # ---------------------------------------------------- @@ -3174,6 +3194,40 @@ sub ndbcluster_start ($) { return 0; } +sub have_wsrep() { + my $wsrep_on= $mysqld_variables{'wsrep-on'}; + return defined $wsrep_on +} + +sub check_wsrep_provider_env { + if (defined $ENV{'WSREP_PROVIDER'}) { + if (mtr_file_exists($ENV{'WSREP_PROVIDER'}) eq "") { + mtr_error("WSREP_PROVIDER env set to an invalid path"); + return 0; # error + } + # Ok, WSREP_PROVIDER set to a valid path. + return 1; + } + # Ok, WSREP_PROVIDER not defined. + return 2; +} + +sub check_wsrep_support() { + if (have_wsrep()) + { + mtr_report(" - binaries built with wsrep patch"); + + $file_wsrep_provider= + mtr_file_exists("/usr/lib/galera/libgalera_smm.so", + "/usr/lib64/galera/libgalera_smm.so"); + + if ((check_wsrep_provider_env() == 1) || ($file_wsrep_provider ne "")) { + # Add galera test suites + mtr_report(" - adding wsrep, galera to default test suites"); + push @DEFAULT_SUITES, qw(wsrep galera); + } + } +} sub mysql_server_start($) { my ($mysqld, $tinfo) = @_; @@ -4837,6 +4891,10 @@ sub extract_warning_lines ($$) { qr|Plugin 'FEEDBACK' registration as a INFORMATION SCHEMA failed|, qr|'log-bin-use-v1-row-events' is MySQL 5.6 compatible option|, qr|InnoDB: Setting thread \d+ nice to \d+ failed, current nice \d+, errno 13|, # setpriority() fails under valgrind + # Galera-related warnings. + qr|WSREP:.*down context.*|, + qr|WSREP: Failed to send state UUID:.*|, + qr|WSREP: wsrep_sst_receive_address.*|, ); my $matched_lines= []; diff --git a/mysql-test/r/have_wsrep.require b/mysql-test/r/have_wsrep.require new file mode 100644 index 00000000000..af32ac7dca7 --- /dev/null +++ b/mysql-test/r/have_wsrep.require @@ -0,0 +1,2 @@ +Variable_name Value +wsrep_on ON diff --git a/mysql-test/r/mysql_tzinfo_to_sql_symlink.result b/mysql-test/r/mysql_tzinfo_to_sql_symlink.result index dda732937ee..484f71a4c2e 100644 --- a/mysql-test/r/mysql_tzinfo_to_sql_symlink.result +++ b/mysql-test/r/mysql_tzinfo_to_sql_symlink.result @@ -1,6 +1,7 @@ # # MDEV-5226 mysql_tzinfo_to_sql errors with tzdata 2013f and above # +SET SESSION wsrep_replicate_myisam=ON; # Verbose run TRUNCATE TABLE time_zone; TRUNCATE TABLE time_zone_name; diff --git a/mysql-test/r/mysqld--help.result b/mysql-test/r/mysqld--help.result index 5a2142c402c..3dd58891455 100644 --- a/mysql-test/r/mysqld--help.result +++ b/mysql-test/r/mysqld--help.result @@ -1065,6 +1065,88 @@ The following options may be given as the first argument: -V, --version Output version information and exit. --wait-timeout=# The number of seconds the server waits for activity on a connection before closing it + --wsrep-OSU-method[=name] + Method for Online Schema Upgrade + --wsrep-auto-increment-control + To automatically control the assignment of autoincrement + variables + (Defaults to on; use --skip-wsrep-auto-increment-control to disable.) + --wsrep-causal-reads + Enable "strictly synchronous" semantics for read + operations + --wsrep-certify-nonPK + Certify tables with no primary key + (Defaults to on; use --skip-wsrep-certify-nonPK to disable.) + --wsrep-cluster-address=name + Address to initially connect to cluster + --wsrep-cluster-name=name + Name for the cluster + --wsrep-convert-LOCK-to-trx + To convert locking sessions into transactions + --wsrep-data-home-dir=name + home directory for wsrep provider + --wsrep-dbug-option=name + DBUG options to provider library + --wsrep-debug To enable debug level logging + --wsrep-desync To desynchronize the node from the cluster + --wsrep-drupal-282555-workaround + To use a workaround forbad autoincrement value + --wsrep-forced-binlog-format=name + binlog format to take effect over user's choice + --wsrep-load-data-splitting + To commit LOAD DATA transaction after every 10K rows + inserted + (Defaults to on; use --skip-wsrep-load-data-splitting to disable.) + --wsrep-log-conflicts + To log multi-master conflicts + --wsrep-max-ws-rows=# + Max number of rows in write set + --wsrep-max-ws-size=# + Max write set size (bytes) + --wsrep-mysql-replication-bundle=# + mysql replication group commit + --wsrep-node-address=name + Node address + --wsrep-node-incoming-address=name + Client connection address + --wsrep-node-name=name + Node name + --wsrep-notify-cmd=name + --wsrep-on To enable wsrep replication + (Defaults to on; use --skip-wsrep-on to disable.) + --wsrep-provider=name + Path to replication provider library + --wsrep-provider-options=name + provider specific options + --wsrep-recover Recover database state after crash and exit + --wsrep-replicate-myisam + To enable myisam replication + --wsrep-restart-slave + Should MySQL slave be restarted automatically, when node + joins back to cluster + --wsrep-retry-autocommit=# + Max number of times to retry a failed autocommit + statement + --wsrep-slave-FK-checks + Should slave thread do foreign key constraint checks + (Defaults to on; use --skip-wsrep-slave-FK-checks to disable.) + --wsrep-slave-UK-checks + Should slave thread do secondary index uniqueness checks + --wsrep-slave-threads=# + Number of slave appliers to launch + --wsrep-sst-auth=name + Authentication for SST connection + --wsrep-sst-donor=name + preferred donor node for the SST + --wsrep-sst-donor-rejects-queries + Reject client queries when donating state snapshot + transfer + --wsrep-sst-method=name + State snapshot transfer method + --wsrep-sst-receive-address=name + Address where node is waiting for SST contact + --wsrep-start-position=name + global transaction position to start from Variables (--variable-name=value) allow-suspicious-udfs FALSE @@ -1364,6 +1446,43 @@ use-stat-tables NEVER userstat FALSE verbose TRUE wait-timeout 28800 +wsrep-OSU-method TOI +wsrep-auto-increment-control TRUE +wsrep-causal-reads FALSE +wsrep-certify-nonPK TRUE +wsrep-cluster-address +wsrep-cluster-name my_wsrep_cluster +wsrep-convert-LOCK-to-trx FALSE +wsrep-data-home-dir +wsrep-dbug-option +wsrep-debug FALSE +wsrep-desync FALSE +wsrep-drupal-282555-workaround FALSE +wsrep-forced-binlog-format NONE +wsrep-load-data-splitting TRUE +wsrep-log-conflicts FALSE +wsrep-max-ws-rows 131072 +wsrep-max-ws-size 1073741824 +wsrep-mysql-replication-bundle 0 +wsrep-node-address +wsrep-node-incoming-address AUTO +wsrep-notify-cmd +wsrep-on FALSE +wsrep-provider none +wsrep-provider-options +wsrep-recover FALSE +wsrep-replicate-myisam FALSE +wsrep-restart-slave FALSE +wsrep-retry-autocommit 1 +wsrep-slave-FK-checks TRUE +wsrep-slave-UK-checks FALSE +wsrep-slave-threads 1 +wsrep-sst-auth (No default value) +wsrep-sst-donor +wsrep-sst-donor-rejects-queries FALSE +wsrep-sst-method rsync +wsrep-sst-receive-address AUTO +wsrep-start-position 00000000-0000-0000-0000-000000000000:-1 To see what values a running MySQL server is using, type 'mysqladmin variables' instead of 'mysqld --verbose --help'. diff --git a/mysql-test/r/not_wsrep.require b/mysql-test/r/not_wsrep.require new file mode 100644 index 00000000000..7c8e74af144 --- /dev/null +++ b/mysql-test/r/not_wsrep.require @@ -0,0 +1,2 @@ +HAVE_WSREP +0 diff --git a/mysql-test/suite/binlog/r/binlog_row_binlog.result b/mysql-test/suite/binlog/r/binlog_row_binlog.result index 20a4b52f1a7..05009c5a570 100644 --- a/mysql-test/suite/binlog/r/binlog_row_binlog.result +++ b/mysql-test/suite/binlog/r/binlog_row_binlog.result @@ -806,9 +806,11 @@ SELECT * FROM t1; c1 1 # Their values should be ON -SHOW SESSION VARIABLES LIKE "%_checks"; +SHOW SESSION VARIABLES LIKE "foreign_key_checks"; Variable_name Value foreign_key_checks ON +SHOW SESSION VARIABLES LIKE "unique_checks"; +Variable_name Value unique_checks ON SET @@SESSION.foreign_key_checks= OFF; @@ -824,9 +826,11 @@ c1 1 2 # Their values should be OFF -SHOW SESSION VARIABLES LIKE "%_checks"; +SHOW SESSION VARIABLES LIKE "foreign_key_checks"; Variable_name Value foreign_key_checks OFF +SHOW SESSION VARIABLES LIKE "unique_checks"; +Variable_name Value unique_checks OFF # INSERT INTO t1 VALUES(2) # foreign_key_checks=1 and unique_checks=1 @@ -842,8 +846,10 @@ c1 1 2 # Their values should be OFF -SHOW SESSION VARIABLES LIKE "%_checks"; +SHOW SESSION VARIABLES LIKE "foreign_key_checks"; Variable_name Value foreign_key_checks OFF +SHOW SESSION VARIABLES LIKE "unique_checks"; +Variable_name Value unique_checks OFF DROP TABLE t1; diff --git a/mysql-test/suite/binlog/r/binlog_stm_binlog.result b/mysql-test/suite/binlog/r/binlog_stm_binlog.result index 824bf3ed2a0..3a6af15e88a 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_binlog.result +++ b/mysql-test/suite/binlog/r/binlog_stm_binlog.result @@ -618,9 +618,11 @@ SELECT * FROM t1; c1 1 # Their values should be ON -SHOW SESSION VARIABLES LIKE "%_checks"; +SHOW SESSION VARIABLES LIKE "foreign_key_checks"; Variable_name Value foreign_key_checks ON +SHOW SESSION VARIABLES LIKE "unique_checks"; +Variable_name Value unique_checks ON SET @@SESSION.foreign_key_checks= OFF; @@ -636,9 +638,11 @@ c1 1 2 # Their values should be OFF -SHOW SESSION VARIABLES LIKE "%_checks"; +SHOW SESSION VARIABLES LIKE "foreign_key_checks"; Variable_name Value foreign_key_checks OFF +SHOW SESSION VARIABLES LIKE "unique_checks"; +Variable_name Value unique_checks OFF # INSERT INTO t1 VALUES(2) # foreign_key_checks=1 and unique_checks=1 @@ -654,8 +658,10 @@ c1 1 2 # Their values should be OFF -SHOW SESSION VARIABLES LIKE "%_checks"; +SHOW SESSION VARIABLES LIKE "foreign_key_checks"; Variable_name Value foreign_key_checks OFF +SHOW SESSION VARIABLES LIKE "unique_checks"; +Variable_name Value unique_checks OFF DROP TABLE t1; diff --git a/mysql-test/suite/galera/galera_2nodes.cnf b/mysql-test/suite/galera/galera_2nodes.cnf new file mode 100644 index 00000000000..5a08125089a --- /dev/null +++ b/mysql-test/suite/galera/galera_2nodes.cnf @@ -0,0 +1,24 @@ +# Use default setting for mysqld processes +!include include/default_mysqld.cnf + +[mysqld.1] +binlog-format=row +wsrep_provider=@ENV.WSREP_PROVIDER +wsrep_cluster_address='gcomm://' +wsrep_provider_options='base_port=@mysqld.1.#galera_port' +wsrep_sst_receive_address='127.0.0.1:@mysqld.1.#sst_port' + +[mysqld.2] +binlog-format=row +wsrep_provider=@ENV.WSREP_PROVIDER +wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port' +wsrep_provider_options='base_port=@mysqld.2.#galera_port' +wsrep_sst_receive_address='127.0.0.1:@mysqld.2.#sst_port' + +[ENV] +NODE_MYPORT_1= @mysqld.1.port +NODE_MYSOCK_1= @mysqld.1.socket + +NODE_MYPORT_2= @mysqld.2.port +NODE_MYSOCK_2= @mysqld.2.socket + diff --git a/mysql-test/suite/galera/my.cnf b/mysql-test/suite/galera/my.cnf new file mode 100644 index 00000000000..ca163a540d9 --- /dev/null +++ b/mysql-test/suite/galera/my.cnf @@ -0,0 +1 @@ +!include galera_2nodes.cnf diff --git a/mysql-test/suite/galera/r/basic.result b/mysql-test/suite/galera/r/basic.result new file mode 100644 index 00000000000..d4efe348b61 --- /dev/null +++ b/mysql-test/suite/galera/r/basic.result @@ -0,0 +1,30 @@ +USE test; +CREATE TABLE t1(c1 INT PRIMARY KEY) ENGINE=INNODB; +INSERT INTO t1 VALUES (1), (2), (3), (4), (5); +SELECT * FROM t1; +c1 +1 +2 +3 +4 +5 + +# On node_1 +SELECT * FROM test.t1; +c1 +1 +2 +3 +4 +5 + +# On node_2 +SELECT * FROM test.t1; +c1 +1 +2 +3 +4 +5 +DROP TABLE t1; +# End of test diff --git a/mysql-test/suite/galera/r/grant.result b/mysql-test/suite/galera/r/grant.result new file mode 100644 index 00000000000..8d257e7e8e2 --- /dev/null +++ b/mysql-test/suite/galera/r/grant.result @@ -0,0 +1,17 @@ +# +# MDEV#6266: Changing password fails on galera cluster +# + +# On node_1 +GRANT SELECT ON *.* TO 'user_6266'@'localhost' IDENTIFIED BY 'pass'; + +# Now, try changing password for 'user_6266'. This command should also +# execute successfully on the other node. +SET PASSWORD FOR 'user_6266'@'localhost' = PASSWORD('newpass'); + +# On node_2 +SELECT user FROM mysql.user WHERE user='user_6266'; +user +user_6266 +DROP USER 'user_6266'@'localhost'; +# End of test diff --git a/mysql-test/suite/galera/r/partition.result b/mysql-test/suite/galera/r/partition.result new file mode 100644 index 00000000000..60fb2ed298d --- /dev/null +++ b/mysql-test/suite/galera/r/partition.result @@ -0,0 +1,23 @@ +# +# MDEV#4953 Galera: DELETE from a partitioned table is not replicated +# +USE test; +CREATE TABLE t1 (pk INT PRIMARY KEY, i INT) ENGINE=INNODB PARTITION BY HASH(pk) PARTITIONS 2; +INSERT INTO t1 VALUES (1,100), (2,200); +SELECT * FROM t1; +pk i +2 200 +1 100 +DELETE FROM t1; +SELECT * FROM t1; +pk i + +# On node_1 +SELECT * FROM t1; +pk i + +# On node_2 +SELECT * FROM t1; +pk i +DROP TABLE t1; +# End of test diff --git a/mysql-test/suite/galera/r/unique_key.result b/mysql-test/suite/galera/r/unique_key.result new file mode 100644 index 00000000000..ffb4f01c1f8 --- /dev/null +++ b/mysql-test/suite/galera/r/unique_key.result @@ -0,0 +1,47 @@ +# +# MDEV#5552 Deadlock when inserting NULL column value in column with +# UNIQUE index +# +USE test; + +# On node_1 +CREATE TABLE t1(c1 INT DEFAULT NULL, UNIQUE KEY c1(c1)) ENGINE=INNODB; +INSERT INTO t1 VALUES (NULL); +INSERT INTO t1 VALUES (NULL); +SELECT * FROM test.t1; +c1 +NULL +NULL + +# On node_2 +SELECT * FROM test.t1; +c1 +NULL +NULL + +# On node_1 +INSERT INTO t1 VALUES (1); +UPDATE t1 SET c1=NULL WHERE c1=1; +SELECT * FROM test.t1; +c1 +NULL +NULL +NULL + +# On node_2 +SELECT * FROM test.t1; +c1 +NULL +NULL +NULL + +# On node_1 +DELETE FROM t1 WHERE c1<=>NULL; +SELECT * FROM test.t1; +c1 + +# On node_2 +SELECT * FROM test.t1; +c1 +DROP TABLE t1; +# End of test diff --git a/mysql-test/suite/galera/t/basic.test b/mysql-test/suite/galera/t/basic.test new file mode 100644 index 00000000000..8fc6eee3b3b --- /dev/null +++ b/mysql-test/suite/galera/t/basic.test @@ -0,0 +1,26 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +USE test; +CREATE TABLE t1(c1 INT PRIMARY KEY) ENGINE=INNODB; +INSERT INTO t1 VALUES (1), (2), (3), (4), (5); +SELECT * FROM t1; + +--echo +--echo # On node_1 +--connection node_1 +SELECT * FROM test.t1; + +--echo +--echo # On node_2 +--connection node_2 +SELECT * FROM test.t1; + +--let $galera_diff_statement = SELECT * FROM t1 +--source include/galera_diff.inc + +# Cleanup +DROP TABLE t1; + +--source include/galera_end.inc +--echo # End of test diff --git a/mysql-test/suite/galera/t/grant.test b/mysql-test/suite/galera/t/grant.test new file mode 100644 index 00000000000..de1c202cfbb --- /dev/null +++ b/mysql-test/suite/galera/t/grant.test @@ -0,0 +1,25 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +--echo # +--echo # MDEV#6266: Changing password fails on galera cluster +--echo # + +--echo +--echo # On node_1 +--connection node_1 +GRANT SELECT ON *.* TO 'user_6266'@'localhost' IDENTIFIED BY 'pass'; +--echo +--echo # Now, try changing password for 'user_6266'. This command should also +--echo # execute successfully on the other node. +SET PASSWORD FOR 'user_6266'@'localhost' = PASSWORD('newpass'); + +--echo +--echo # On node_2 +--connection node_2 +SELECT user FROM mysql.user WHERE user='user_6266'; +# cleanup +DROP USER 'user_6266'@'localhost'; + +--source include/galera_end.inc +--echo # End of test diff --git a/mysql-test/suite/galera/t/partition.test b/mysql-test/suite/galera/t/partition.test new file mode 100644 index 00000000000..048f35a9282 --- /dev/null +++ b/mysql-test/suite/galera/t/partition.test @@ -0,0 +1,31 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc +--source include/have_partition.inc + +--echo # +--echo # MDEV#4953 Galera: DELETE from a partitioned table is not replicated +--echo # + +USE test; +CREATE TABLE t1 (pk INT PRIMARY KEY, i INT) ENGINE=INNODB PARTITION BY HASH(pk) PARTITIONS 2; +INSERT INTO t1 VALUES (1,100), (2,200); +SELECT * FROM t1; + +DELETE FROM t1; +SELECT * FROM t1; + +--echo +--echo # On node_1 +--connection node_1 +SELECT * FROM t1; + +--echo +--echo # On node_2 +--connection node_2 +SELECT * FROM t1; + +# Cleanup +DROP TABLE t1; + +--source include/galera_end.inc +--echo # End of test diff --git a/mysql-test/suite/galera/t/unique_key.test b/mysql-test/suite/galera/t/unique_key.test new file mode 100644 index 00000000000..00b85d57165 --- /dev/null +++ b/mysql-test/suite/galera/t/unique_key.test @@ -0,0 +1,54 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +--echo # +--echo # MDEV#5552 Deadlock when inserting NULL column value in column with +--echo # UNIQUE index +--echo # + +USE test; +--echo +--echo # On node_1 +--connection node_1 +CREATE TABLE t1(c1 INT DEFAULT NULL, UNIQUE KEY c1(c1)) ENGINE=INNODB; +INSERT INTO t1 VALUES (NULL); +INSERT INTO t1 VALUES (NULL); +SELECT * FROM test.t1; + +--echo +--echo # On node_2 +--connection node_2 +SELECT * FROM test.t1; + + +--echo +--echo # On node_1 +--connection node_1 +INSERT INTO t1 VALUES (1); +UPDATE t1 SET c1=NULL WHERE c1=1; +SELECT * FROM test.t1; + +--echo +--echo # On node_2 +--connection node_2 +SELECT * FROM test.t1; + +--echo +--echo # On node_1 +--connection node_1 +DELETE FROM t1 WHERE c1<=>NULL; +SELECT * FROM test.t1; + +--echo +--echo # On node_2 +--connection node_2 +SELECT * FROM test.t1; + +--let $galera_diff_statement = SELECT * FROM t1 +--source include/galera_diff.inc + +# Cleanup +DROP TABLE t1; + +--source include/galera_end.inc +--echo # End of test diff --git a/mysql-test/suite/innodb/r/innodb-autoinc.result b/mysql-test/suite/innodb/r/innodb-autoinc.result index d5ad06e861f..6ecb6055f26 100644 --- a/mysql-test/suite/innodb/r/innodb-autoinc.result +++ b/mysql-test/suite/innodb/r/innodb-autoinc.result @@ -197,7 +197,7 @@ c1 c2 5 9 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 100 auto_increment_offset 10 @@ -230,7 +230,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -269,7 +269,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -282,7 +282,7 @@ SELECT * FROM t1; c1 -1 SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 100 auto_increment_offset 10 @@ -315,7 +315,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -330,7 +330,7 @@ SELECT * FROM t1; c1 1 SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 100 auto_increment_offset 10 @@ -370,7 +370,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -385,7 +385,7 @@ SELECT * FROM t1; c1 1 SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 100 auto_increment_offset 10 @@ -419,7 +419,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -434,7 +434,7 @@ c1 1 9223372036854775794 SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 2 auto_increment_offset 10 @@ -452,7 +452,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -467,7 +467,7 @@ c1 1 18446744073709551603 SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 2 auto_increment_offset 10 @@ -480,7 +480,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -495,7 +495,7 @@ c1 1 18446744073709551603 SET @@SESSION.AUTO_INCREMENT_INCREMENT=5, @@SESSION.AUTO_INCREMENT_OFFSET=7; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 5 auto_increment_offset 7 @@ -508,7 +508,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -527,7 +527,7 @@ c1 -9223372036854775806 1 SET @@SESSION.AUTO_INCREMENT_INCREMENT=3, @@SESSION.AUTO_INCREMENT_OFFSET=3; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 3 auto_increment_offset 3 @@ -544,7 +544,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -562,7 +562,7 @@ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1152921504606846976, @@SESSION.AUTO_INCRE Warnings: Warning 1292 Truncated incorrect auto_increment_increment value: '1152921504606846976' Warning 1292 Truncated incorrect auto_increment_offset value: '1152921504606846976' -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 65535 auto_increment_offset 65535 @@ -575,7 +575,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -862,7 +862,7 @@ ERROR 22003: Out of range value for column 'c1' at row 1 DROP TABLE t1; DROP TABLE t2; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -1252,7 +1252,7 @@ t1 CREATE TABLE `t1` ( ) ENGINE=InnoDB AUTO_INCREMENT=18446744073709551615 DEFAULT CHARSET=latin1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=256; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 256 @@ -1270,7 +1270,7 @@ c1 c2 1 NULL DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 diff --git a/mysql-test/suite/innodb/t/innodb-autoinc.test b/mysql-test/suite/innodb/t/innodb-autoinc.test index fd40b50ebbc..415ada2939a 100644 --- a/mysql-test/suite/innodb/t/innodb-autoinc.test +++ b/mysql-test/suite/innodb/t/innodb-autoinc.test @@ -161,7 +161,7 @@ DROP TABLE t1; # # Test changes to AUTOINC next value calculation SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; INSERT INTO t1 VALUES (NULL),(5),(NULL); @@ -178,7 +178,7 @@ DROP TABLE t1; # Reset the AUTOINC session variables SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; INSERT INTO t1 VALUES(0); @@ -198,13 +198,13 @@ DROP TABLE t1; # Reset the AUTOINC session variables SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; INSERT INTO t1 VALUES(-1); SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; INSERT INTO t1 VALUES (-2), (NULL),(2),(NULL); INSERT INTO t1 VALUES (250),(NULL); SELECT * FROM t1; @@ -219,13 +219,13 @@ DROP TABLE t1; # Reset the AUTOINC session variables SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 INT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; INSERT INTO t1 VALUES(-1); SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; INSERT INTO t1 VALUES (-2); INSERT INTO t1 VALUES (NULL); INSERT INTO t1 VALUES (2); @@ -245,13 +245,13 @@ DROP TABLE t1; # Reset the AUTOINC session variables SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 INT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; INSERT INTO t1 VALUES(-1); SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; INSERT INTO t1 VALUES (-2),(NULL),(2),(NULL); INSERT INTO t1 VALUES (250),(NULL); SELECT * FROM t1; @@ -267,7 +267,7 @@ DROP TABLE t1; # Check for overflow handling when increment is > 1 SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 BIGINT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; # TODO: Fix the autoinc init code @@ -276,7 +276,7 @@ INSERT INTO t1 VALUES(NULL); INSERT INTO t1 VALUES (9223372036854775794); #-- 2^63 - 14 SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; # This should just fit INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); SELECT * FROM t1; @@ -286,7 +286,7 @@ DROP TABLE t1; # Check for overflow handling when increment and offser are > 1 SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; # TODO: Fix the autoinc init code @@ -295,7 +295,7 @@ INSERT INTO t1 VALUES(NULL); INSERT INTO t1 VALUES (18446744073709551603); #-- 2^64 - 13 SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; --error ER_AUTOINC_READ_FAILED INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL); SELECT * FROM t1; @@ -305,7 +305,7 @@ DROP TABLE t1; # Check for overflow handling when increment and offset are odd numbers SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; # TODO: Fix the autoinc init code @@ -314,7 +314,7 @@ INSERT INTO t1 VALUES(NULL); INSERT INTO t1 VALUES (18446744073709551603); #-- 2^64 - 13 SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=5, @@SESSION.AUTO_INCREMENT_OFFSET=7; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; --error ER_AUTOINC_READ_FAILED INSERT INTO t1 VALUES (NULL),(NULL), (NULL); SELECT * FROM t1; @@ -324,7 +324,7 @@ DROP TABLE t1; # and check for large -ve numbers SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 BIGINT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; # TODO: Fix the autoinc init code @@ -335,7 +335,7 @@ INSERT INTO t1 VALUES(-9223372036854775807); #-- -2^63 + 1 INSERT INTO t1 VALUES(-9223372036854775808); #-- -2^63 SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=3, @@SESSION.AUTO_INCREMENT_OFFSET=3; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; INSERT INTO t1 VALUES (NULL),(NULL), (NULL); SELECT * FROM t1; DROP TABLE t1; @@ -344,7 +344,7 @@ DROP TABLE t1; # large numbers 2^60 SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; # TODO: Fix the autoinc init code @@ -353,7 +353,7 @@ INSERT INTO t1 VALUES(NULL); INSERT INTO t1 VALUES (18446744073709551610); #-- 2^64 - 2 SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1152921504606846976, @@SESSION.AUTO_INCREMENT_OFFSET=1152921504606846976; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; --error 167 INSERT INTO t1 VALUES (NULL),(NULL); SELECT * FROM t1; @@ -364,7 +364,7 @@ DROP TABLE t1; # SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; CREATE TABLE t1 (c1 DOUBLE NOT NULL AUTO_INCREMENT, c2 INT, PRIMARY KEY (c1)) ENGINE=InnoDB; INSERT INTO t1 VALUES(NULL, 1); INSERT INTO t1 VALUES(NULL, 2); @@ -450,7 +450,7 @@ DROP TABLE t2; # If the user has specified negative values for an AUTOINC column then # InnoDB should ignore those values when setting the table's max value. SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; # TINYINT CREATE TABLE t1 (c1 TINYINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; INSERT INTO t1 VALUES (1, NULL); @@ -646,7 +646,7 @@ DROP TABLE t1; # Check if we handle offset > column max value properly SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=256; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; # TINYINT CREATE TABLE t1 (c1 TINYINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; INSERT INTO t1 VALUES (1, NULL); @@ -658,7 +658,7 @@ DROP TABLE t1; # of the column. IMO, this should not be allowed and the assertion that fails # is actually an invariant. SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; # TINYINT CREATE TABLE t1 (c1 INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; INSERT INTO t1 VALUES (2147483648, 'a'); diff --git a/mysql-test/suite/parts/r/partition_exch_qa_10.result b/mysql-test/suite/parts/r/partition_exch_qa_10.result old mode 100755 new mode 100644 index 77b91f19e8f..7193a6c99a1 --- a/mysql-test/suite/parts/r/partition_exch_qa_10.result +++ b/mysql-test/suite/parts/r/partition_exch_qa_10.result @@ -23,7 +23,7 @@ a b DROP PROCEDURE test_p1; SET @save_autocommit= @@autocommit; SET @@autocommit= OFF; -SHOW VARIABLES LIKE '%autocommit%'; +SHOW VARIABLES LIKE 'autocommit%'; Variable_name Value autocommit OFF CREATE TRIGGER test_trg_1 BEFORE UPDATE ON tp FOR EACH ROW diff --git a/mysql-test/suite/parts/t/partition_exch_qa_10.test b/mysql-test/suite/parts/t/partition_exch_qa_10.test index 4f569605f5f..a87d658cfb6 100644 --- a/mysql-test/suite/parts/t/partition_exch_qa_10.test +++ b/mysql-test/suite/parts/t/partition_exch_qa_10.test @@ -37,7 +37,7 @@ DROP PROCEDURE test_p1; SET @save_autocommit= @@autocommit; SET @@autocommit= OFF; -SHOW VARIABLES LIKE '%autocommit%'; +SHOW VARIABLES LIKE 'autocommit%'; DELIMITER |; --error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG CREATE TRIGGER test_trg_1 BEFORE UPDATE ON tp FOR EACH ROW diff --git a/mysql-test/suite/percona/innodb_sys_index.result b/mysql-test/suite/percona/innodb_sys_index.result index 67604236366..1c4cc63c467 100644 --- a/mysql-test/suite/percona/innodb_sys_index.result +++ b/mysql-test/suite/percona/innodb_sys_index.result @@ -3,7 +3,7 @@ Warnings: Note 1051 Unknown table 'test.t1' select @@version_comment limit 1 ; @@version_comment -Source distribution +Source distribution, wsrep_25.10.r3991 SELECT COUNT(*) FROM `information_schema`.`INNODB_SYS_INDEXES` ; CREATE TABLE test.t1 ( `a` SERIAL NOT NULL , `b` VARCHAR( 255 ) NOT NULL , INDEX ( `b` ) ) ENGINE = InnoDB ; SHOW TABLE STATUS FROM `information_schema` LIKE 'INNODB\_SYS\_INDEXES%' ; diff --git a/mysql-test/suite/percona/innodb_sys_index.test b/mysql-test/suite/percona/innodb_sys_index.test index 212baeda663..a5a79611815 100644 --- a/mysql-test/suite/percona/innodb_sys_index.test +++ b/mysql-test/suite/percona/innodb_sys_index.test @@ -5,7 +5,8 @@ drop table if exists t1; # # test for bug LP#875797 "Using 'innodb_sys_indexes' causes core dump" # -select @@version_comment limit 1 ; +# disable version_commit as it could contain wsrep +#select @@version_comment limit 1 ; --disable_result_log SELECT COUNT(*) FROM `information_schema`.`INNODB_SYS_INDEXES` ; CREATE TABLE test.t1 ( `a` SERIAL NOT NULL , `b` VARCHAR( 255 ) NOT NULL , INDEX ( `b` ) ) ENGINE = InnoDB ; diff --git a/mysql-test/suite/perfschema/r/rpl_statements.result b/mysql-test/suite/perfschema/r/rpl_statements.result index e271cd2a7fa..211a7d3398d 100644 --- a/mysql-test/suite/perfschema/r/rpl_statements.result +++ b/mysql-test/suite/perfschema/r/rpl_statements.result @@ -11,9 +11,10 @@ include/master-slave.inc *** Create test tables -show variables like '%binlog_format%'; +show variables like 'binlog_format%'; Variable_name Value binlog_format MIXED +wsrep_forced_binlog_format NONE drop table if exists test.marker; select thread_id into @my_thread_id from performance_schema.threads @@ -55,9 +56,10 @@ Expect 1 *** MASTER *** ************** -show variables like '%binlog_format%'; +show variables like 'binlog_format%'; Variable_name Value binlog_format MIXED +wsrep_forced_binlog_format NONE *** Clear statement events *** Create/drop table, create/drop database diff --git a/mysql-test/suite/perfschema/t/rpl_statements.test b/mysql-test/suite/perfschema/t/rpl_statements.test index fa429cd2aa3..479805edccc 100644 --- a/mysql-test/suite/perfschema/t/rpl_statements.test +++ b/mysql-test/suite/perfschema/t/rpl_statements.test @@ -64,7 +64,7 @@ connection master; --echo *** Create test tables --echo -show variables like '%binlog_format%'; +show variables like 'binlog_format%'; --disable_warnings drop table if exists test.marker; @@ -129,7 +129,7 @@ connection master; --echo *** MASTER *** --echo ************** --echo -show variables like '%binlog_format%'; +show variables like 'binlog_format%'; --echo *** Clear statement events --source ../include/rpl_statements_truncate.inc diff --git a/mysql-test/suite/sys_vars/r/wsrep_auto_increment_control_basic.result b/mysql-test/suite/sys_vars/r/wsrep_auto_increment_control_basic.result new file mode 100644 index 00000000000..d5affeaf5e4 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_auto_increment_control_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_auto_increment_control; +set @@global.wsrep_auto_increment_control=ON; +set @@global.wsrep_auto_increment_control=OFF; +set @@global.wsrep_auto_increment_control=1; +set @@global.wsrep_auto_increment_control=0; +SET @@global.wsrep_auto_increment_control = -1; +ERROR 42000: Variable 'wsrep_auto_increment_control' can't be set to the value of '-1' +set @@global.wsrep_auto_increment_control = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_causal_reads_basic.result b/mysql-test/suite/sys_vars/r/wsrep_causal_reads_basic.result new file mode 100644 index 00000000000..3b96654f8c7 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_causal_reads_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_causal_reads; +set @@global.wsrep_causal_reads=ON; +set @@global.wsrep_causal_reads=OFF; +set @@global.wsrep_causal_reads=1; +set @@global.wsrep_causal_reads=0; +SET @@global.wsrep_causal_reads = -1; +ERROR 42000: Variable 'wsrep_causal_reads' can't be set to the value of '-1' +set @@global.wsrep_causal_reads = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_certify_nonpk_basic.result b/mysql-test/suite/sys_vars/r/wsrep_certify_nonpk_basic.result new file mode 100644 index 00000000000..4b02f9fb61e --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_certify_nonpk_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_certify_nonpk; +set @@global.wsrep_certify_nonpk=ON; +set @@global.wsrep_certify_nonpk=OFF; +set @@global.wsrep_certify_nonpk=1; +set @@global.wsrep_certify_nonpk=0; +SET @@global.wsrep_certify_nonpk = -1; +ERROR 42000: Variable 'wsrep_certify_nonPK' can't be set to the value of '-1' +set @@global.wsrep_certify_nonpk = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_cluster_address_basic.result b/mysql-test/suite/sys_vars/r/wsrep_cluster_address_basic.result new file mode 100644 index 00000000000..734908d42e5 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_cluster_address_basic.result @@ -0,0 +1,45 @@ +SELECT COUNT(@@GLOBAL.wsrep_cluster_address); +COUNT(@@GLOBAL.wsrep_cluster_address) +1 +1 Expected +SELECT COUNT(@@GLOBAL.wsrep_cluster_address); +COUNT(@@GLOBAL.wsrep_cluster_address) +1 +1 Expected +SELECT @@GLOBAL.wsrep_cluster_address = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_cluster_address'; +@@GLOBAL.wsrep_cluster_address = VARIABLE_VALUE +1 +1 Expected +SELECT COUNT(@@GLOBAL.wsrep_cluster_address); +COUNT(@@GLOBAL.wsrep_cluster_address) +1 +1 Expected +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_cluster_address'; +COUNT(VARIABLE_VALUE) +1 +1 Expected +SELECT @@wsrep_cluster_address = @@GLOBAL.wsrep_cluster_address; +@@wsrep_cluster_address = @@GLOBAL.wsrep_cluster_address +1 +1 Expected +SELECT COUNT(@@wsrep_cluster_address); +COUNT(@@wsrep_cluster_address) +1 +1 Expected +SELECT COUNT(@@local.wsrep_cluster_address); +ERROR HY000: Variable 'wsrep_cluster_address' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@SESSION.wsrep_cluster_address); +ERROR HY000: Variable 'wsrep_cluster_address' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@GLOBAL.wsrep_cluster_address); +COUNT(@@GLOBAL.wsrep_cluster_address) +1 +1 Expected +SELECT wsrep_cluster_address = @@SESSION.wsrep_cluster_address; +ERROR 42S22: Unknown column 'wsrep_cluster_address' in 'field list' +Expected error 'Readonly variable' diff --git a/mysql-test/suite/sys_vars/r/wsrep_cluster_name_basic.result b/mysql-test/suite/sys_vars/r/wsrep_cluster_name_basic.result new file mode 100644 index 00000000000..59c3b9381d1 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_cluster_name_basic.result @@ -0,0 +1,7 @@ +set @start_value = @@wsrep_cluster_name; +set @@global.wsrep_cluster_name='test'; +set @@global.wsrep_cluster_name=NULL; +ERROR 42000: Variable 'wsrep_cluster_name' can't be set to the value of 'NULL' +SET @@global.wsrep_cluster_name = 1; +ERROR 42000: Incorrect argument type to variable 'wsrep_cluster_name' +set @@global.wsrep_cluster_name = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_convert_lock_to_trx_basic.result b/mysql-test/suite/sys_vars/r/wsrep_convert_lock_to_trx_basic.result new file mode 100644 index 00000000000..10043812289 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_convert_lock_to_trx_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_convert_lock_to_trx; +set @@global.wsrep_convert_lock_to_trx=ON; +set @@global.wsrep_convert_lock_to_trx=OFF; +set @@global.wsrep_convert_lock_to_trx=1; +set @@global.wsrep_convert_lock_to_trx=0; +SET @@global.wsrep_convert_lock_to_trx = -1; +ERROR 42000: Variable 'wsrep_convert_LOCK_to_trx' can't be set to the value of '-1' +set @@global.wsrep_convert_lock_to_trx = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_data_home_dir_basic.result b/mysql-test/suite/sys_vars/r/wsrep_data_home_dir_basic.result new file mode 100644 index 00000000000..668aebe30f1 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_data_home_dir_basic.result @@ -0,0 +1,48 @@ +SELECT COUNT(@@GLOBAL.wsrep_data_home_dir); +COUNT(@@GLOBAL.wsrep_data_home_dir) +1 +1 Expected +SET @@GLOBAL.wsrep_data_home_dir=1; +ERROR HY000: Variable 'wsrep_data_home_dir' is a read only variable +Expected error 'Read only variable' +SELECT COUNT(@@GLOBAL.wsrep_data_home_dir); +COUNT(@@GLOBAL.wsrep_data_home_dir) +1 +1 Expected +SELECT @@GLOBAL.wsrep_data_home_dir = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_data_home_dir'; +@@GLOBAL.wsrep_data_home_dir = VARIABLE_VALUE +1 +1 Expected +SELECT COUNT(@@GLOBAL.wsrep_data_home_dir); +COUNT(@@GLOBAL.wsrep_data_home_dir) +1 +1 Expected +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_data_home_dir'; +COUNT(VARIABLE_VALUE) +1 +1 Expected +SELECT @@wsrep_data_home_dir = @@GLOBAL.wsrep_data_home_dir; +@@wsrep_data_home_dir = @@GLOBAL.wsrep_data_home_dir +1 +1 Expected +SELECT COUNT(@@wsrep_data_home_dir); +COUNT(@@wsrep_data_home_dir) +1 +1 Expected +SELECT COUNT(@@local.wsrep_data_home_dir); +ERROR HY000: Variable 'wsrep_data_home_dir' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@SESSION.wsrep_data_home_dir); +ERROR HY000: Variable 'wsrep_data_home_dir' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@GLOBAL.wsrep_data_home_dir); +COUNT(@@GLOBAL.wsrep_data_home_dir) +1 +1 Expected +SELECT wsrep_data_home_dir = @@SESSION.wsrep_data_home_dir; +ERROR 42S22: Unknown column 'wsrep_data_home_dir' in 'field list' +Expected error 'Readonly variable' diff --git a/mysql-test/suite/sys_vars/r/wsrep_dbug_option_basic.result b/mysql-test/suite/sys_vars/r/wsrep_dbug_option_basic.result new file mode 100644 index 00000000000..36ebcb17002 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_dbug_option_basic.result @@ -0,0 +1,6 @@ +set @start_value = @@wsrep_dbug_option; +set @@global.wsrep_dbug_option='foo:bar'; +set @@global.wsrep_dbug_option=NULL; +SET @@global.wsrep_dbug_option = -1; +ERROR 42000: Incorrect argument type to variable 'wsrep_dbug_option' +set @@global.wsrep_dbug_option = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_debug_basic.result b/mysql-test/suite/sys_vars/r/wsrep_debug_basic.result new file mode 100644 index 00000000000..6bbe780316b --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_debug_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_debug; +set @@global.wsrep_debug=ON; +set @@global.wsrep_debug=OFF; +set @@global.wsrep_debug=1; +set @@global.wsrep_debug=0; +SET @@global.wsrep_debug = -1; +ERROR 42000: Variable 'wsrep_debug' can't be set to the value of '-1' +set @@global.wsrep_debug = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_desync_basic.result b/mysql-test/suite/sys_vars/r/wsrep_desync_basic.result new file mode 100644 index 00000000000..a61367ca200 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_desync_basic.result @@ -0,0 +1,3 @@ +select @@global.wsrep_desync; +@@global.wsrep_desync +0 diff --git a/mysql-test/suite/sys_vars/r/wsrep_drupal_282555_workaround_basic.result b/mysql-test/suite/sys_vars/r/wsrep_drupal_282555_workaround_basic.result new file mode 100644 index 00000000000..5a8d5a8abee --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_drupal_282555_workaround_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_drupal_282555_workaround; +set @@global.wsrep_drupal_282555_workaround=ON; +set @@global.wsrep_drupal_282555_workaround=OFF; +set @@global.wsrep_drupal_282555_workaround=1; +set @@global.wsrep_drupal_282555_workaround=0; +SET @@global.wsrep_drupal_282555_workaround = -1; +ERROR 42000: Variable 'wsrep_drupal_282555_workaround' can't be set to the value of '-1' +set @@global.wsrep_drupal_282555_workaround = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_forced_binlog_format_basic.result b/mysql-test/suite/sys_vars/r/wsrep_forced_binlog_format_basic.result new file mode 100644 index 00000000000..58bdb45c8de --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_forced_binlog_format_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_forced_binlog_format; +set @@global.wsrep_forced_binlog_format = ROW; +set @@global.wsrep_forced_binlog_format = MIXED; +set @@global.wsrep_forced_binlog_format = STATEMENT; +set @@global.wsrep_forced_binlog_format = NONE; +set @@global.wsrep_forced_binlog_format = FOO; +ERROR 42000: Variable 'wsrep_forced_binlog_format' can't be set to the value of 'FOO' +set @@global.wsrep_forced_binlog_format = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_load_data_splitting_basic.result b/mysql-test/suite/sys_vars/r/wsrep_load_data_splitting_basic.result new file mode 100644 index 00000000000..be73397f35e --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_load_data_splitting_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_load_data_splitting; +set @@global.wsrep_load_data_splitting=ON; +set @@global.wsrep_load_data_splitting=OFF; +set @@global.wsrep_load_data_splitting=1; +set @@global.wsrep_load_data_splitting=0; +SET @@global.wsrep_load_data_splitting = -1; +ERROR 42000: Variable 'wsrep_load_data_splitting' can't be set to the value of '-1' +set @@global.wsrep_load_data_splitting = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_log_conflicts_basic.result b/mysql-test/suite/sys_vars/r/wsrep_log_conflicts_basic.result new file mode 100644 index 00000000000..22d8cbb568a --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_log_conflicts_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_log_conflicts; +set @@global.wsrep_log_conflicts=ON; +set @@global.wsrep_log_conflicts=OFF; +set @@global.wsrep_log_conflicts=1; +set @@global.wsrep_log_conflicts=0; +SET @@global.wsrep_log_conflicts = -1; +ERROR 42000: Variable 'wsrep_log_conflicts' can't be set to the value of '-1' +set @@global.wsrep_log_conflicts = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_max_ws_rows_basic.result b/mysql-test/suite/sys_vars/r/wsrep_max_ws_rows_basic.result new file mode 100644 index 00000000000..fc4dd38ade3 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_max_ws_rows_basic.result @@ -0,0 +1,17 @@ +set @start_value = @@wsrep_max_ws_rows; +set @@global.wsrep_max_ws_rows=256000; +set @@global.wsrep_max_ws_rows=0; +Warnings: +Warning 1292 Truncated incorrect wsrep_max_ws_rows value: '0' +show warnings; +Level Code Message +Warning 1292 Truncated incorrect wsrep_max_ws_rows value: '0' +set @@global.wsrep_max_ws_rows=-1; +Warnings: +Warning 1292 Truncated incorrect wsrep_max_ws_rows value: '-1' +show warnings; +Level Code Message +Warning 1292 Truncated incorrect wsrep_max_ws_rows value: '-1' +SET @@global.wsrep_max_ws_rows = r; +ERROR 42000: Incorrect argument type to variable 'wsrep_max_ws_rows' +set @@global.wsrep_max_ws_rows = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_max_ws_size_basic.result b/mysql-test/suite/sys_vars/r/wsrep_max_ws_size_basic.result new file mode 100644 index 00000000000..292fd4e02d8 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_max_ws_size_basic.result @@ -0,0 +1,17 @@ +set @start_value = @@wsrep_max_ws_size; +set @@global.wsrep_max_ws_size=256000; +set @@global.wsrep_max_ws_size=0; +Warnings: +Warning 1292 Truncated incorrect wsrep_max_ws_size value: '0' +show warnings; +Level Code Message +Warning 1292 Truncated incorrect wsrep_max_ws_size value: '0' +set @@global.wsrep_max_ws_size=-1; +Warnings: +Warning 1292 Truncated incorrect wsrep_max_ws_size value: '-1' +show warnings; +Level Code Message +Warning 1292 Truncated incorrect wsrep_max_ws_size value: '-1' +SET @@global.wsrep_max_ws_size = r; +ERROR 42000: Incorrect argument type to variable 'wsrep_max_ws_size' +set @@global.wsrep_max_ws_size = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_mysql_replication_bundle_basic.result b/mysql-test/suite/sys_vars/r/wsrep_mysql_replication_bundle_basic.result new file mode 100644 index 00000000000..ad435a2c05f --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_mysql_replication_bundle_basic.result @@ -0,0 +1,18 @@ +set @start_value = @@wsrep_mysql_replication_bundle; +set @@global.wsrep_mysql_replication_bundle=0; +set @@global.wsrep_mysql_replication_bundle=1000; +set @@global.wsrep_mysql_replication_bundle=-1; +Warnings: +Warning 1292 Truncated incorrect wsrep_mysql_replication_bundle value: '-1' +show warnings; +Level Code Message +Warning 1292 Truncated incorrect wsrep_mysql_replication_bundle value: '-1' +set @@global.wsrep_mysql_replication_bundle=1001; +Warnings: +Warning 1292 Truncated incorrect wsrep_mysql_replication_bundle value: '1001' +show warnings; +Level Code Message +Warning 1292 Truncated incorrect wsrep_mysql_replication_bundle value: '1001' +SET @@global.wsrep_mysql_replication_bundle = r; +ERROR 42000: Incorrect argument type to variable 'wsrep_mysql_replication_bundle' +set @@global.wsrep_mysql_replication_bundle = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_node_address_basic.result b/mysql-test/suite/sys_vars/r/wsrep_node_address_basic.result new file mode 100644 index 00000000000..96ae51cc70f --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_node_address_basic.result @@ -0,0 +1,45 @@ +SELECT COUNT(@@GLOBAL.wsrep_node_address); +COUNT(@@GLOBAL.wsrep_node_address) +1 +1 Expected +SET @@GLOBAL.wsrep_node_address=1; +ERROR 42000: Incorrect argument type to variable 'wsrep_node_address' +Expected error 'Read only variable' +SELECT COUNT(@@GLOBAL.wsrep_node_address); +COUNT(@@GLOBAL.wsrep_node_address) +1 +1 Expected +SELECT @@GLOBAL.wsrep_node_address = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_node_address'; +@@GLOBAL.wsrep_node_address = VARIABLE_VALUE +1 +1 Expected +SELECT COUNT(@@GLOBAL.wsrep_node_address); +COUNT(@@GLOBAL.wsrep_node_address) +1 +1 Expected +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_node_address'; +COUNT(VARIABLE_VALUE) +1 +1 Expected +SELECT @@wsrep_node_address = @@GLOBAL.wsrep_node_address; +@@wsrep_node_address = @@GLOBAL.wsrep_node_address +1 +1 Expected +SELECT COUNT(@@wsrep_node_address); +COUNT(@@wsrep_node_address) +1 +1 Expected +SELECT COUNT(@@local.wsrep_node_address); +ERROR HY000: Variable 'wsrep_node_address' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@SESSION.wsrep_node_address); +ERROR HY000: Variable 'wsrep_node_address' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@GLOBAL.wsrep_node_address); +COUNT(@@GLOBAL.wsrep_node_address) +1 +1 Expected diff --git a/mysql-test/suite/sys_vars/r/wsrep_node_incoming_address_basic.result b/mysql-test/suite/sys_vars/r/wsrep_node_incoming_address_basic.result new file mode 100644 index 00000000000..9ccf9706484 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_node_incoming_address_basic.result @@ -0,0 +1,45 @@ +SELECT COUNT(@@GLOBAL.wsrep_node_incoming_address); +COUNT(@@GLOBAL.wsrep_node_incoming_address) +1 +1 Expected +SET @@GLOBAL.wsrep_node_incoming_address=1; +ERROR 42000: Incorrect argument type to variable 'wsrep_node_incoming_address' +Expected error 'Read only variable' +SELECT COUNT(@@GLOBAL.wsrep_node_incoming_address); +COUNT(@@GLOBAL.wsrep_node_incoming_address) +1 +1 Expected +SELECT @@GLOBAL.wsrep_node_incoming_address = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_node_incoming_address'; +@@GLOBAL.wsrep_node_incoming_address = VARIABLE_VALUE +1 +1 Expected +SELECT COUNT(@@GLOBAL.wsrep_node_incoming_address); +COUNT(@@GLOBAL.wsrep_node_incoming_address) +1 +1 Expected +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_node_incoming_address'; +COUNT(VARIABLE_VALUE) +1 +1 Expected +SELECT @@wsrep_node_incoming_address = @@GLOBAL.wsrep_node_incoming_address; +@@wsrep_node_incoming_address = @@GLOBAL.wsrep_node_incoming_address +1 +1 Expected +SELECT COUNT(@@wsrep_node_incoming_address); +COUNT(@@wsrep_node_incoming_address) +1 +1 Expected +SELECT COUNT(@@local.wsrep_node_incoming_address); +ERROR HY000: Variable 'wsrep_node_incoming_address' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@SESSION.wsrep_node_incoming_address); +ERROR HY000: Variable 'wsrep_node_incoming_address' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@GLOBAL.wsrep_node_incoming_address); +COUNT(@@GLOBAL.wsrep_node_incoming_address) +1 +1 Expected diff --git a/mysql-test/suite/sys_vars/r/wsrep_node_name_basic.result b/mysql-test/suite/sys_vars/r/wsrep_node_name_basic.result new file mode 100644 index 00000000000..f3c03570b7b --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_node_name_basic.result @@ -0,0 +1,6 @@ +set @start_value = @@wsrep_node_name; +set @@global.wsrep_node_name='test'; +set @@global.wsrep_node_name=NULL; +SET @@global.wsrep_node_name = 1; +ERROR 42000: Incorrect argument type to variable 'wsrep_node_name' +set @@global.wsrep_node_name = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_notify_cmd_basic.result b/mysql-test/suite/sys_vars/r/wsrep_notify_cmd_basic.result new file mode 100644 index 00000000000..d1d68ea036b --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_notify_cmd_basic.result @@ -0,0 +1,6 @@ +set @start_value = @@wsrep_notify_cmd; +set @@global.wsrep_notify_cmd='test'; +set @@global.wsrep_notify_cmd=NULL; +SET @@global.wsrep_notify_cmd = 1; +ERROR 42000: Incorrect argument type to variable 'wsrep_notify_cmd' +set @@global.wsrep_notify_cmd = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_on_basic.result b/mysql-test/suite/sys_vars/r/wsrep_on_basic.result new file mode 100644 index 00000000000..629c0e866cb --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_on_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_on; +set @@global.wsrep_on=ON; +set @@global.wsrep_on=OFF; +set @@global.wsrep_on=1; +set @@global.wsrep_on=0; +SET @@global.wsrep_on = -1; +ERROR 42000: Variable 'wsrep_on' can't be set to the value of '-1' +set @@global.wsrep_on = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_osu_method_basic.result b/mysql-test/suite/sys_vars/r/wsrep_osu_method_basic.result new file mode 100644 index 00000000000..84c828e5965 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_osu_method_basic.result @@ -0,0 +1,12 @@ +set @start_value = @@wsrep_osu_method; +set @@global.wsrep_osu_method='TOI'; +set @@global.wsrep_osu_method='RSU'; +set @@global.wsrep_osu_method=TOI; +set @@global.wsrep_osu_method=RSU; +set @@global.wsrep_osu_method=TSU; +ERROR 42000: Variable 'wsrep_OSU_method' can't be set to the value of 'TSU' +set @@global.wsrep_osu_method='TSU'; +ERROR 42000: Variable 'wsrep_OSU_method' can't be set to the value of 'TSU' +SET @@global.wsrep_on = -1; +ERROR 42000: Variable 'wsrep_on' can't be set to the value of '-1' +set @@global.wsrep_osu_method = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_provider_basic.result b/mysql-test/suite/sys_vars/r/wsrep_provider_basic.result new file mode 100644 index 00000000000..2de1e84e6c0 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_provider_basic.result @@ -0,0 +1,4 @@ +SELECT COUNT(@@GLOBAL.wsrep_provider); +COUNT(@@GLOBAL.wsrep_provider) +1 +1 Expected diff --git a/mysql-test/suite/sys_vars/r/wsrep_provider_options_basic.result b/mysql-test/suite/sys_vars/r/wsrep_provider_options_basic.result new file mode 100644 index 00000000000..28b55e782bc --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_provider_options_basic.result @@ -0,0 +1,4 @@ +SELECT COUNT(@@GLOBAL.wsrep_provider_options); +COUNT(@@GLOBAL.wsrep_provider_options) +1 +1 Expected diff --git a/mysql-test/suite/sys_vars/r/wsrep_recover_basic.result b/mysql-test/suite/sys_vars/r/wsrep_recover_basic.result new file mode 100644 index 00000000000..b9f7e41047e --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_recover_basic.result @@ -0,0 +1,49 @@ +SELECT COUNT(@@GLOBAL.wsrep_recover); +COUNT(@@GLOBAL.wsrep_recover) +1 +1 Expected +set @@global.wsrep_recover=ON; +ERROR HY000: Variable 'wsrep_recover' is a read only variable +Expected error 'Readonly variable' +set @@global.wsrep_recover=OFF; +ERROR HY000: Variable 'wsrep_recover' is a read only variable +Expected error 'Readonly variable' +SELECT @@GLOBAL.wsrep_recover = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_recover'; +@@GLOBAL.wsrep_recover = VARIABLE_VALUE +1 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'OFF' +1 Expected +SELECT COUNT(@@GLOBAL.wsrep_recover); +COUNT(@@GLOBAL.wsrep_recover) +1 +1 Expected +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_recover'; +COUNT(VARIABLE_VALUE) +1 +1 Expected +SELECT @@wsrep_recover = @@GLOBAL.wsrep_recover; +@@wsrep_recover = @@GLOBAL.wsrep_recover +1 +1 Expected +SELECT COUNT(@@wsrep_recover); +COUNT(@@wsrep_recover) +1 +1 Expected +SELECT COUNT(@@local.wsrep_recover); +ERROR HY000: Variable 'wsrep_recover' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@SESSION.wsrep_recover); +ERROR HY000: Variable 'wsrep_recover' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@GLOBAL.wsrep_recover); +COUNT(@@GLOBAL.wsrep_recover) +1 +1 Expected +SELECT wsrep_recover = @@SESSION.wsrep_recover; +ERROR 42S22: Unknown column 'wsrep_recover' in 'field list' +Expected error 'Readonly variable' diff --git a/mysql-test/suite/sys_vars/r/wsrep_replicate_myisam_basic.result b/mysql-test/suite/sys_vars/r/wsrep_replicate_myisam_basic.result new file mode 100644 index 00000000000..644258206a5 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_replicate_myisam_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_replicate_myisam; +set @@global.wsrep_replicate_myisam=ON; +set @@global.wsrep_replicate_myisam=OFF; +set @@global.wsrep_replicate_myisam=1; +set @@global.wsrep_replicate_myisam=0; +SET @@global.wsrep_replicate_myisam = -1; +ERROR 42000: Variable 'wsrep_replicate_myisam' can't be set to the value of '-1' +set @@global.wsrep_replicate_myisam = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_restart_slave_basic.result b/mysql-test/suite/sys_vars/r/wsrep_restart_slave_basic.result new file mode 100644 index 00000000000..811981b6a37 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_restart_slave_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_restart_slave; +set @@global.wsrep_restart_slave=ON; +set @@global.wsrep_restart_slave=OFF; +set @@global.wsrep_restart_slave=1; +set @@global.wsrep_restart_slave=0; +SET @@global.wsrep_restart_slave = -1; +ERROR 42000: Variable 'wsrep_restart_slave' can't be set to the value of '-1' +set @@global.wsrep_restart_slave = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_retry_autocommit_basic.result b/mysql-test/suite/sys_vars/r/wsrep_retry_autocommit_basic.result new file mode 100644 index 00000000000..811981b6a37 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_retry_autocommit_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_restart_slave; +set @@global.wsrep_restart_slave=ON; +set @@global.wsrep_restart_slave=OFF; +set @@global.wsrep_restart_slave=1; +set @@global.wsrep_restart_slave=0; +SET @@global.wsrep_restart_slave = -1; +ERROR 42000: Variable 'wsrep_restart_slave' can't be set to the value of '-1' +set @@global.wsrep_restart_slave = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_slave_threads_basic.result b/mysql-test/suite/sys_vars/r/wsrep_slave_threads_basic.result new file mode 100644 index 00000000000..f8105660c6e --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_slave_threads_basic.result @@ -0,0 +1,20 @@ +set @start_value = @@wsrep_slave_threads; +set @@global.wsrep_slave_threads=1; +set @@global.wsrep_slave_threads=4; +show warnings; +Level Code Message +set @@global.wsrep_slave_threads=0; +Warnings: +Warning 1292 Truncated incorrect wsrep_slave_threads value: '0' +show warnings; +Level Code Message +Warning 1292 Truncated incorrect wsrep_slave_threads value: '0' +set @@global.wsrep_slave_threads=-1; +Warnings: +Warning 1292 Truncated incorrect wsrep_slave_threads value: '-1' +show warnings; +Level Code Message +Warning 1292 Truncated incorrect wsrep_slave_threads value: '-1' +SET @@global.wsrep_slave_threads = r; +ERROR 42000: Incorrect argument type to variable 'wsrep_slave_threads' +set @@global.wsrep_slave_threads = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_sst_auth_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sst_auth_basic.result new file mode 100644 index 00000000000..a8a31dbea61 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_sst_auth_basic.result @@ -0,0 +1,3 @@ +SELECT COUNT(@@wsrep_sst_auth); +COUNT(@@wsrep_sst_auth) +0 diff --git a/mysql-test/suite/sys_vars/r/wsrep_sst_donor_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sst_donor_basic.result new file mode 100644 index 00000000000..fc359690275 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_sst_donor_basic.result @@ -0,0 +1,10 @@ +SELECT COUNT(@@wsrep_sst_donor); +COUNT(@@wsrep_sst_donor) +1 +set @start_value = @@wsrep_sst_donor; +set @@global.wsrep_sst_donor='foo'; +set @@global.wsrep_sst_donor=NULL; +set @@global.wsrep_sst_donor=r; +set @@global.wsrep_sst_donor=1; +ERROR 42000: Incorrect argument type to variable 'wsrep_sst_donor' +set @@global.wsrep_sst_donor = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_sst_donor_rejects_queries_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sst_donor_rejects_queries_basic.result new file mode 100644 index 00000000000..55aa56f27ed --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_sst_donor_rejects_queries_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_sst_donor_rejects_queries; +set @@global.wsrep_sst_donor_rejects_queries=ON; +set @@global.wsrep_sst_donor_rejects_queries=OFF; +set @@global.wsrep_sst_donor_rejects_queries=1; +set @@global.wsrep_sst_donor_rejects_queries=0; +SET @@global.wsrep_sst_donor_rejects_queries = -1; +ERROR 42000: Variable 'wsrep_sst_donor_rejects_queries' can't be set to the value of '-1' +set @@global.wsrep_sst_donor_rejects_queries = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_sst_method_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sst_method_basic.result new file mode 100644 index 00000000000..682a5683026 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_sst_method_basic.result @@ -0,0 +1,12 @@ +set @start_value = @@wsrep_sst_method; +set @@global.wsrep_sst_method='xtrabackup'; +set @@global.wsrep_sst_method='xtrabackup-v2'; +set @@global.wsrep_sst_method='rsync'; +set @@global.wsrep_sst_method='mysqldump'; +set @@global.wsrep_sst_method='myscript'; +set @@global.wsrep_sst_method='skip'; +set @@global.wsrep_sst_method=NULL; +ERROR 42000: Variable 'wsrep_sst_method' can't be set to the value of 'NULL' +SET @@global.wsrep_sst_method = -1; +ERROR 42000: Incorrect argument type to variable 'wsrep_sst_method' +set @@global.wsrep_sst_method = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_sst_receive_address_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sst_receive_address_basic.result new file mode 100644 index 00000000000..a23b7efafa8 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_sst_receive_address_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_sst_receive_address; +set @@global.wsrep_sst_receive_address='128.0.2.1'; +set @@global.wsrep_sst_receive_address=AUTO; +set @@global.wsrep_sst_receive_address='AUTO'; +set @@global.wsrep_sst_receive_address=NULL; +SET @@global.wsrep_sst_receive_address = -1; +ERROR 42000: Incorrect argument type to variable 'wsrep_sst_receive_address' +set @@global.wsrep_sst_receive_address = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_start_position_basic.result b/mysql-test/suite/sys_vars/r/wsrep_start_position_basic.result new file mode 100644 index 00000000000..ad3606d6d55 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_start_position_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_start_position; +set @@global.wsrep_start_position='foo:bar'; +ERROR 42000: Variable 'wsrep_start_position' can't be set to the value of 'foo:bar' +set @@global.wsrep_start_position=NULL; +ERROR 42000: Variable 'wsrep_start_position' can't be set to the value of 'NULL' +SET @@global.wsrep_start_position = -1; +ERROR 42000: Incorrect argument type to variable 'wsrep_start_position' +set @@global.wsrep_start_position = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_auto_increment_control_basic.test b/mysql-test/suite/sys_vars/t/wsrep_auto_increment_control_basic.test new file mode 100644 index 00000000000..91d3c578a2c --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_auto_increment_control_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_auto_increment_control; + +set @@global.wsrep_auto_increment_control=ON; +set @@global.wsrep_auto_increment_control=OFF; +set @@global.wsrep_auto_increment_control=1; +set @@global.wsrep_auto_increment_control=0; +--Error 1231 +SET @@global.wsrep_auto_increment_control = -1; + +set @@global.wsrep_auto_increment_control = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_causal_reads_basic.test b/mysql-test/suite/sys_vars/t/wsrep_causal_reads_basic.test new file mode 100644 index 00000000000..2fb597e842e --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_causal_reads_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_causal_reads; + +set @@global.wsrep_causal_reads=ON; +set @@global.wsrep_causal_reads=OFF; +set @@global.wsrep_causal_reads=1; +set @@global.wsrep_causal_reads=0; +--Error 1231 +SET @@global.wsrep_causal_reads = -1; + +set @@global.wsrep_causal_reads = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_certify_nonpk b/mysql-test/suite/sys_vars/t/wsrep_certify_nonpk new file mode 100644 index 00000000000..f4512aeb5da --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_certify_nonpk @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_certify_nonpk; + +set @@global.wsrep_certify_nonpk=ON; +set @@global.wsrep_certify_nonpk=OFF; +set @@global.wsrep_certify_nonpk=1; +set @@global.wsrep_certify_nonpk=0; +--Error ER_WRONG_TYPE_FOR_VAR +SET @@global.wsrep_certify_nonpk = -1; + +set @@global.wsrep_certify_nonpk = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_certify_nonpk_basic.test b/mysql-test/suite/sys_vars/t/wsrep_certify_nonpk_basic.test new file mode 100644 index 00000000000..b623d8eb073 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_certify_nonpk_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_certify_nonpk; + +set @@global.wsrep_certify_nonpk=ON; +set @@global.wsrep_certify_nonpk=OFF; +set @@global.wsrep_certify_nonpk=1; +set @@global.wsrep_certify_nonpk=0; +--Error 1231 +SET @@global.wsrep_certify_nonpk = -1; + +set @@global.wsrep_certify_nonpk = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_cluster_address_basic.test b/mysql-test/suite/sys_vars/t/wsrep_cluster_address_basic.test new file mode 100644 index 00000000000..b61d5ea60c3 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_cluster_address_basic.test @@ -0,0 +1,44 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +SELECT COUNT(@@GLOBAL.wsrep_cluster_address); +--echo 1 Expected + +SELECT COUNT(@@GLOBAL.wsrep_cluster_address); +--echo 1 Expected + +SELECT @@GLOBAL.wsrep_cluster_address = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_cluster_address'; +--echo 1 Expected + +SELECT COUNT(@@GLOBAL.wsrep_cluster_address); +--echo 1 Expected + +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_cluster_address'; +--echo 1 Expected + +SELECT @@wsrep_cluster_address = @@GLOBAL.wsrep_cluster_address; +--echo 1 Expected + +SELECT COUNT(@@wsrep_cluster_address); +--echo 1 Expected + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@local.wsrep_cluster_address); +--echo Expected error 'Variable is a GLOBAL variable' + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@SESSION.wsrep_cluster_address); +--echo Expected error 'Variable is a GLOBAL variable' + +SELECT COUNT(@@GLOBAL.wsrep_cluster_address); +--echo 1 Expected + +--Error ER_BAD_FIELD_ERROR +SELECT wsrep_cluster_address = @@SESSION.wsrep_cluster_address; +--echo Expected error 'Readonly variable' + + diff --git a/mysql-test/suite/sys_vars/t/wsrep_cluster_name_basic.test b/mysql-test/suite/sys_vars/t/wsrep_cluster_name_basic.test new file mode 100644 index 00000000000..104c342bfe4 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_cluster_name_basic.test @@ -0,0 +1,12 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_cluster_name; + +set @@global.wsrep_cluster_name='test'; +--Error 1231 +set @@global.wsrep_cluster_name=NULL; +--Error 1232 +SET @@global.wsrep_cluster_name = 1; + +set @@global.wsrep_cluster_name = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_convert_lock_to_trx_basic.test b/mysql-test/suite/sys_vars/t/wsrep_convert_lock_to_trx_basic.test new file mode 100644 index 00000000000..84b92085238 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_convert_lock_to_trx_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_convert_lock_to_trx; + +set @@global.wsrep_convert_lock_to_trx=ON; +set @@global.wsrep_convert_lock_to_trx=OFF; +set @@global.wsrep_convert_lock_to_trx=1; +set @@global.wsrep_convert_lock_to_trx=0; +--Error 1231 +SET @@global.wsrep_convert_lock_to_trx = -1; + +set @@global.wsrep_convert_lock_to_trx = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_data_home_dir_basic.test b/mysql-test/suite/sys_vars/t/wsrep_data_home_dir_basic.test new file mode 100644 index 00000000000..fccf685193e --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_data_home_dir_basic.test @@ -0,0 +1,48 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +SELECT COUNT(@@GLOBAL.wsrep_data_home_dir); +--echo 1 Expected + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@GLOBAL.wsrep_data_home_dir=1; +--echo Expected error 'Read only variable' + +SELECT COUNT(@@GLOBAL.wsrep_data_home_dir); +--echo 1 Expected + +SELECT @@GLOBAL.wsrep_data_home_dir = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_data_home_dir'; +--echo 1 Expected + +SELECT COUNT(@@GLOBAL.wsrep_data_home_dir); +--echo 1 Expected + +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_data_home_dir'; +--echo 1 Expected + +SELECT @@wsrep_data_home_dir = @@GLOBAL.wsrep_data_home_dir; +--echo 1 Expected + +SELECT COUNT(@@wsrep_data_home_dir); +--echo 1 Expected + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@local.wsrep_data_home_dir); +--echo Expected error 'Variable is a GLOBAL variable' + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@SESSION.wsrep_data_home_dir); +--echo Expected error 'Variable is a GLOBAL variable' + +SELECT COUNT(@@GLOBAL.wsrep_data_home_dir); +--echo 1 Expected + +--Error ER_BAD_FIELD_ERROR +SELECT wsrep_data_home_dir = @@SESSION.wsrep_data_home_dir; +--echo Expected error 'Readonly variable' + + diff --git a/mysql-test/suite/sys_vars/t/wsrep_dbug_option_basic.test b/mysql-test/suite/sys_vars/t/wsrep_dbug_option_basic.test new file mode 100644 index 00000000000..0a559fe8d27 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_dbug_option_basic.test @@ -0,0 +1,11 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_dbug_option; + +set @@global.wsrep_dbug_option='foo:bar'; +set @@global.wsrep_dbug_option=NULL; +--Error 1232 +SET @@global.wsrep_dbug_option = -1; + +set @@global.wsrep_dbug_option = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_debug_basic.test b/mysql-test/suite/sys_vars/t/wsrep_debug_basic.test new file mode 100644 index 00000000000..194c163baa6 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_debug_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_debug; + +set @@global.wsrep_debug=ON; +set @@global.wsrep_debug=OFF; +set @@global.wsrep_debug=1; +set @@global.wsrep_debug=0; +--Error 1231 +SET @@global.wsrep_debug = -1; + +set @@global.wsrep_debug = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_debug_option_basic.test b/mysql-test/suite/sys_vars/t/wsrep_debug_option_basic.test new file mode 100644 index 00000000000..060e721b676 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_debug_option_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_debug_option; + +--error 1231 +set @@global.wsrep_debug_option='foo:bar'; +--error 1231 +set @@global.wsrep_debug_option=NULL; +--Error 1232 +SET @@global.wsrep_debug_option = -1; + +set @@global.wsrep_debug_option = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_desync_basic.test b/mysql-test/suite/sys_vars/t/wsrep_desync_basic.test new file mode 100644 index 00000000000..3c64d8cb30f --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_desync_basic.test @@ -0,0 +1,4 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +select @@global.wsrep_desync; diff --git a/mysql-test/suite/sys_vars/t/wsrep_drupal_282555_workaround_basic.test b/mysql-test/suite/sys_vars/t/wsrep_drupal_282555_workaround_basic.test new file mode 100644 index 00000000000..ada08bb125d --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_drupal_282555_workaround_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_drupal_282555_workaround; + +set @@global.wsrep_drupal_282555_workaround=ON; +set @@global.wsrep_drupal_282555_workaround=OFF; +set @@global.wsrep_drupal_282555_workaround=1; +set @@global.wsrep_drupal_282555_workaround=0; +--Error 1231 +SET @@global.wsrep_drupal_282555_workaround = -1; + +set @@global.wsrep_drupal_282555_workaround = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_forced_binlog_format_basic.test b/mysql-test/suite/sys_vars/t/wsrep_forced_binlog_format_basic.test new file mode 100644 index 00000000000..5e5530a8f64 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_forced_binlog_format_basic.test @@ -0,0 +1,14 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_forced_binlog_format; + +set @@global.wsrep_forced_binlog_format = ROW; +set @@global.wsrep_forced_binlog_format = MIXED; +set @@global.wsrep_forced_binlog_format = STATEMENT; +set @@global.wsrep_forced_binlog_format = NONE; + +--error 1231 +set @@global.wsrep_forced_binlog_format = FOO; + +set @@global.wsrep_forced_binlog_format = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_load_data_splitting_basic.test b/mysql-test/suite/sys_vars/t/wsrep_load_data_splitting_basic.test new file mode 100644 index 00000000000..61ff27d6894 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_load_data_splitting_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_load_data_splitting; + +set @@global.wsrep_load_data_splitting=ON; +set @@global.wsrep_load_data_splitting=OFF; +set @@global.wsrep_load_data_splitting=1; +set @@global.wsrep_load_data_splitting=0; +--Error 1231 +SET @@global.wsrep_load_data_splitting = -1; + +set @@global.wsrep_load_data_splitting = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_log_conflicts_basic.test b/mysql-test/suite/sys_vars/t/wsrep_log_conflicts_basic.test new file mode 100644 index 00000000000..dbd696c45a2 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_log_conflicts_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_log_conflicts; + +set @@global.wsrep_log_conflicts=ON; +set @@global.wsrep_log_conflicts=OFF; +set @@global.wsrep_log_conflicts=1; +set @@global.wsrep_log_conflicts=0; +--Error 1231 +SET @@global.wsrep_log_conflicts = -1; + +set @@global.wsrep_log_conflicts = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_max_ws_rows_basic.test b/mysql-test/suite/sys_vars/t/wsrep_max_ws_rows_basic.test new file mode 100644 index 00000000000..f607a567d80 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_max_ws_rows_basic.test @@ -0,0 +1,14 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_max_ws_rows; + +set @@global.wsrep_max_ws_rows=256000; +set @@global.wsrep_max_ws_rows=0; +show warnings; +set @@global.wsrep_max_ws_rows=-1; +show warnings; +--Error 1232 +SET @@global.wsrep_max_ws_rows = r; + +set @@global.wsrep_max_ws_rows = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_max_ws_size_basic.test b/mysql-test/suite/sys_vars/t/wsrep_max_ws_size_basic.test new file mode 100644 index 00000000000..6b1d1f71090 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_max_ws_size_basic.test @@ -0,0 +1,14 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_max_ws_size; + +set @@global.wsrep_max_ws_size=256000; +set @@global.wsrep_max_ws_size=0; +show warnings; +set @@global.wsrep_max_ws_size=-1; +show warnings; +--Error 1232 +SET @@global.wsrep_max_ws_size = r; + +set @@global.wsrep_max_ws_size = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_mysql_replication_bundle_basic.test b/mysql-test/suite/sys_vars/t/wsrep_mysql_replication_bundle_basic.test new file mode 100644 index 00000000000..20a0dc9bf9f --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_mysql_replication_bundle_basic.test @@ -0,0 +1,16 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_mysql_replication_bundle; + +set @@global.wsrep_mysql_replication_bundle=0; +set @@global.wsrep_mysql_replication_bundle=1000; + +set @@global.wsrep_mysql_replication_bundle=-1; +show warnings; +set @@global.wsrep_mysql_replication_bundle=1001; +show warnings; +--Error 1232 +SET @@global.wsrep_mysql_replication_bundle = r; + +set @@global.wsrep_mysql_replication_bundle = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_node_address_basic.test b/mysql-test/suite/sys_vars/t/wsrep_node_address_basic.test new file mode 100644 index 00000000000..feace325044 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_node_address_basic.test @@ -0,0 +1,42 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +SELECT COUNT(@@GLOBAL.wsrep_node_address); +--echo 1 Expected + +--error 1232 +SET @@GLOBAL.wsrep_node_address=1; +--echo Expected error 'Read only variable' + +SELECT COUNT(@@GLOBAL.wsrep_node_address); +--echo 1 Expected + +SELECT @@GLOBAL.wsrep_node_address = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_node_address'; +--echo 1 Expected + +SELECT COUNT(@@GLOBAL.wsrep_node_address); +--echo 1 Expected + +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_node_address'; +--echo 1 Expected + +SELECT @@wsrep_node_address = @@GLOBAL.wsrep_node_address; +--echo 1 Expected + +SELECT COUNT(@@wsrep_node_address); +--echo 1 Expected + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@local.wsrep_node_address); +--echo Expected error 'Variable is a GLOBAL variable' + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@SESSION.wsrep_node_address); +--echo Expected error 'Variable is a GLOBAL variable' + +SELECT COUNT(@@GLOBAL.wsrep_node_address); +--echo 1 Expected diff --git a/mysql-test/suite/sys_vars/t/wsrep_node_incoming_address_basic.test b/mysql-test/suite/sys_vars/t/wsrep_node_incoming_address_basic.test new file mode 100644 index 00000000000..188a5960eb9 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_node_incoming_address_basic.test @@ -0,0 +1,42 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +SELECT COUNT(@@GLOBAL.wsrep_node_incoming_address); +--echo 1 Expected + +--error 1232 +SET @@GLOBAL.wsrep_node_incoming_address=1; +--echo Expected error 'Read only variable' + +SELECT COUNT(@@GLOBAL.wsrep_node_incoming_address); +--echo 1 Expected + +SELECT @@GLOBAL.wsrep_node_incoming_address = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_node_incoming_address'; +--echo 1 Expected + +SELECT COUNT(@@GLOBAL.wsrep_node_incoming_address); +--echo 1 Expected + +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_node_incoming_address'; +--echo 1 Expected + +SELECT @@wsrep_node_incoming_address = @@GLOBAL.wsrep_node_incoming_address; +--echo 1 Expected + +SELECT COUNT(@@wsrep_node_incoming_address); +--echo 1 Expected + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@local.wsrep_node_incoming_address); +--echo Expected error 'Variable is a GLOBAL variable' + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@SESSION.wsrep_node_incoming_address); +--echo Expected error 'Variable is a GLOBAL variable' + +SELECT COUNT(@@GLOBAL.wsrep_node_incoming_address); +--echo 1 Expected diff --git a/mysql-test/suite/sys_vars/t/wsrep_node_name_basic.test b/mysql-test/suite/sys_vars/t/wsrep_node_name_basic.test new file mode 100644 index 00000000000..3220ae373e2 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_node_name_basic.test @@ -0,0 +1,11 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_node_name; + +set @@global.wsrep_node_name='test'; +set @@global.wsrep_node_name=NULL; +--Error 1232 +SET @@global.wsrep_node_name = 1; + +set @@global.wsrep_node_name = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_notify_cmd_basic.test b/mysql-test/suite/sys_vars/t/wsrep_notify_cmd_basic.test new file mode 100644 index 00000000000..d816453f8a3 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_notify_cmd_basic.test @@ -0,0 +1,11 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_notify_cmd; + +set @@global.wsrep_notify_cmd='test'; +set @@global.wsrep_notify_cmd=NULL; +--Error 1232 +SET @@global.wsrep_notify_cmd = 1; + +set @@global.wsrep_notify_cmd = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_on_basic.test b/mysql-test/suite/sys_vars/t/wsrep_on_basic.test new file mode 100644 index 00000000000..5afe5c4451f --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_on_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_on; + +set @@global.wsrep_on=ON; +set @@global.wsrep_on=OFF; +set @@global.wsrep_on=1; +set @@global.wsrep_on=0; +--Error 1231 +SET @@global.wsrep_on = -1; + +set @@global.wsrep_on = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_osu_method_basic.test b/mysql-test/suite/sys_vars/t/wsrep_osu_method_basic.test new file mode 100644 index 00000000000..9e1adde76a3 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_osu_method_basic.test @@ -0,0 +1,18 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_osu_method; + +set @@global.wsrep_osu_method='TOI'; +set @@global.wsrep_osu_method='RSU'; +set @@global.wsrep_osu_method=TOI; +set @@global.wsrep_osu_method=RSU; + +--Error 1231 +set @@global.wsrep_osu_method=TSU; +--Error 1231 +set @@global.wsrep_osu_method='TSU'; +--Error 1231 +SET @@global.wsrep_on = -1; + +set @@global.wsrep_osu_method = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_provider_basic.test b/mysql-test/suite/sys_vars/t/wsrep_provider_basic.test new file mode 100644 index 00000000000..aae122c42fe --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_provider_basic.test @@ -0,0 +1,5 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +SELECT COUNT(@@GLOBAL.wsrep_provider); +--echo 1 Expected diff --git a/mysql-test/suite/sys_vars/t/wsrep_provider_options_basic.test b/mysql-test/suite/sys_vars/t/wsrep_provider_options_basic.test new file mode 100644 index 00000000000..e2d8b63b2fd --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_provider_options_basic.test @@ -0,0 +1,5 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +SELECT COUNT(@@GLOBAL.wsrep_provider_options); +--echo 1 Expected diff --git a/mysql-test/suite/sys_vars/t/wsrep_recover_basic.test b/mysql-test/suite/sys_vars/t/wsrep_recover_basic.test new file mode 100644 index 00000000000..f4e1707a434 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_recover_basic.test @@ -0,0 +1,47 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +SELECT COUNT(@@GLOBAL.wsrep_recover); +--echo 1 Expected + +--Error 1238 +set @@global.wsrep_recover=ON; +--echo Expected error 'Readonly variable' +--Error 1238 +set @@global.wsrep_recover=OFF; +--echo Expected error 'Readonly variable' + +SELECT @@GLOBAL.wsrep_recover = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_recover'; +--echo 1 Expected + +SELECT COUNT(@@GLOBAL.wsrep_recover); +--echo 1 Expected + +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_recover'; +--echo 1 Expected + +SELECT @@wsrep_recover = @@GLOBAL.wsrep_recover; +--echo 1 Expected + +SELECT COUNT(@@wsrep_recover); +--echo 1 Expected + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@local.wsrep_recover); +--echo Expected error 'Variable is a GLOBAL variable' + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@SESSION.wsrep_recover); +--echo Expected error 'Variable is a GLOBAL variable' + +SELECT COUNT(@@GLOBAL.wsrep_recover); +--echo 1 Expected + +--Error ER_BAD_FIELD_ERROR +SELECT wsrep_recover = @@SESSION.wsrep_recover; +--echo Expected error 'Readonly variable' + diff --git a/mysql-test/suite/sys_vars/t/wsrep_replicate_myisam_basic.test b/mysql-test/suite/sys_vars/t/wsrep_replicate_myisam_basic.test new file mode 100644 index 00000000000..c03d76b5123 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_replicate_myisam_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_replicate_myisam; + +set @@global.wsrep_replicate_myisam=ON; +set @@global.wsrep_replicate_myisam=OFF; +set @@global.wsrep_replicate_myisam=1; +set @@global.wsrep_replicate_myisam=0; +--Error 1231 +SET @@global.wsrep_replicate_myisam = -1; + +set @@global.wsrep_replicate_myisam = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_restart_slave_basic.test b/mysql-test/suite/sys_vars/t/wsrep_restart_slave_basic.test new file mode 100644 index 00000000000..82f5a97327d --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_restart_slave_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_restart_slave; + +set @@global.wsrep_restart_slave=ON; +set @@global.wsrep_restart_slave=OFF; +set @@global.wsrep_restart_slave=1; +set @@global.wsrep_restart_slave=0; +--Error 1231 +SET @@global.wsrep_restart_slave = -1; + +set @@global.wsrep_restart_slave = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_retry_autocommit_basic.test b/mysql-test/suite/sys_vars/t/wsrep_retry_autocommit_basic.test new file mode 100644 index 00000000000..82f5a97327d --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_retry_autocommit_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_restart_slave; + +set @@global.wsrep_restart_slave=ON; +set @@global.wsrep_restart_slave=OFF; +set @@global.wsrep_restart_slave=1; +set @@global.wsrep_restart_slave=0; +--Error 1231 +SET @@global.wsrep_restart_slave = -1; + +set @@global.wsrep_restart_slave = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_slave_threads_basic.test b/mysql-test/suite/sys_vars/t/wsrep_slave_threads_basic.test new file mode 100644 index 00000000000..cff4f433846 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_slave_threads_basic.test @@ -0,0 +1,16 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_slave_threads; + +set @@global.wsrep_slave_threads=1; +set @@global.wsrep_slave_threads=4; +show warnings; +set @@global.wsrep_slave_threads=0; +show warnings; +set @@global.wsrep_slave_threads=-1; +show warnings; +--Error 1232 +SET @@global.wsrep_slave_threads = r; + +set @@global.wsrep_slave_threads = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_sst_auth_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sst_auth_basic.test new file mode 100644 index 00000000000..6db2a4cd844 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_sst_auth_basic.test @@ -0,0 +1,12 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +SELECT COUNT(@@wsrep_sst_auth); + +# Cause crash, fix later +#set @start_value = @@wsrep_sst_auth; +#set @@global.wsrep_sst_auth='root:pass'; +#set @@global.wsrep_sst_auth=NULL; +#set @@global.wsrep_sst_auth=r; +#set @@global.wsrep_sst_auth=1; +#set @@global.wsrep_sst_auth = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_sst_donor_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sst_donor_basic.test new file mode 100644 index 00000000000..58d005282a0 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_sst_donor_basic.test @@ -0,0 +1,12 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +SELECT COUNT(@@wsrep_sst_donor); + +set @start_value = @@wsrep_sst_donor; +set @@global.wsrep_sst_donor='foo'; +set @@global.wsrep_sst_donor=NULL; +set @@global.wsrep_sst_donor=r; +--error 1232 +set @@global.wsrep_sst_donor=1; +set @@global.wsrep_sst_donor = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_sst_donor_rejects_queries_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sst_donor_rejects_queries_basic.test new file mode 100644 index 00000000000..fc8633ce00f --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_sst_donor_rejects_queries_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_sst_donor_rejects_queries; + +set @@global.wsrep_sst_donor_rejects_queries=ON; +set @@global.wsrep_sst_donor_rejects_queries=OFF; +set @@global.wsrep_sst_donor_rejects_queries=1; +set @@global.wsrep_sst_donor_rejects_queries=0; +--Error 1231 +SET @@global.wsrep_sst_donor_rejects_queries = -1; + +set @@global.wsrep_sst_donor_rejects_queries = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_sst_method_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sst_method_basic.test new file mode 100644 index 00000000000..dab5831ff01 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_sst_method_basic.test @@ -0,0 +1,17 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_sst_method; + +set @@global.wsrep_sst_method='xtrabackup'; +set @@global.wsrep_sst_method='xtrabackup-v2'; +set @@global.wsrep_sst_method='rsync'; +set @@global.wsrep_sst_method='mysqldump'; +set @@global.wsrep_sst_method='myscript'; +set @@global.wsrep_sst_method='skip'; +--error 1231 +set @@global.wsrep_sst_method=NULL; +--Error 1232 +SET @@global.wsrep_sst_method = -1; + +set @@global.wsrep_sst_method = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_sst_receive_address_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sst_receive_address_basic.test new file mode 100644 index 00000000000..0a18098d77f --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_sst_receive_address_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_sst_receive_address; + +set @@global.wsrep_sst_receive_address='128.0.2.1'; +set @@global.wsrep_sst_receive_address=AUTO; +set @@global.wsrep_sst_receive_address='AUTO'; +set @@global.wsrep_sst_receive_address=NULL; +--Error 1232 +SET @@global.wsrep_sst_receive_address = -1; + +set @@global.wsrep_sst_receive_address = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_start_position_basic.test b/mysql-test/suite/sys_vars/t/wsrep_start_position_basic.test new file mode 100644 index 00000000000..3e30d10c016 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_start_position_basic.test @@ -0,0 +1,14 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_start_position; + +--error 1231 +set @@global.wsrep_start_position='foo:bar'; +--error 1231 +set @@global.wsrep_start_position=NULL; +--Error 1232 +SET @@global.wsrep_start_position = -1; + +set @@global.wsrep_start_position = @start_value; + diff --git a/mysql-test/suite/sys_vars/t/wsrep_wsrep_provider_basic.test b/mysql-test/suite/sys_vars/t/wsrep_wsrep_provider_basic.test new file mode 100644 index 00000000000..f4faaccc6a7 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_wsrep_provider_basic.test @@ -0,0 +1,11 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_provider; + +set @@global.wsrep_provider=none; + +--Error 1231 +SET @@global.wsrep_provider = -1; + +set @@global.wsrep_provider = @start_value; diff --git a/mysql-test/suite/wsrep/README b/mysql-test/suite/wsrep/README new file mode 100644 index 00000000000..988096071a4 --- /dev/null +++ b/mysql-test/suite/wsrep/README @@ -0,0 +1,7 @@ +* 'wsrep' suite is designated for tests which do not require a multi-node + galera cluster. + +* As these tests are specific to wsrep-related functionalities, they must skip + on server built without wsrep patch (vanilla). (-DWITH_WSREP=OFF) + See : include/have_wsrep.inc, include/have_wsrep_enabled.inc, not_wsrep.inc + diff --git a/mysql-test/suite/wsrep/r/binlog_format.result b/mysql-test/suite/wsrep/r/binlog_format.result new file mode 100644 index 00000000000..5b8da51f829 --- /dev/null +++ b/mysql-test/suite/wsrep/r/binlog_format.result @@ -0,0 +1,35 @@ +call mtr.add_suppression("WSREP: cannot get fake InnoDB transaction ID"); +call mtr.add_suppression("WSREP: Could not open saved state file for reading:.*"); +SHOW VARIABLES LIKE 'binlog_format'; +Variable_name Value +binlog_format ROW +SET binlog_format=STATEMENT; +ERROR 42000: Variable 'binlog_format' can't be set to the value of 'STATEMENT' +SHOW WARNINGS; +Level Code Message +Warning 1105 MariaDB Galera does not support binlog format: STATEMENT +Error 1231 Variable 'binlog_format' can't be set to the value of 'STATEMENT' +SHOW VARIABLES LIKE 'binlog_format'; +Variable_name Value +binlog_format ROW +CREATE TABLE IF NOT EXISTS test.t1 AS SELECT * FROM information_schema.routines WHERE 1 = 0; +SET binlog_format=MIXED; +ERROR 42000: Variable 'binlog_format' can't be set to the value of 'MIXED' +SHOW WARNINGS; +Level Code Message +Warning 1105 MariaDB Galera does not support binlog format: MIXED +Error 1231 Variable 'binlog_format' can't be set to the value of 'MIXED' +SHOW VARIABLES LIKE 'binlog_format'; +Variable_name Value +binlog_format ROW +CREATE TABLE IF NOT EXISTS test.t2 AS SELECT * FROM information_schema.routines WHERE 1 = 0; +SET binlog_format=ROW; +SHOW WARNINGS; +Level Code Message +SHOW VARIABLES LIKE 'binlog_format'; +Variable_name Value +binlog_format ROW +CREATE TABLE IF NOT EXISTS test.t3 AS SELECT * FROM information_schema.routines WHERE 1 = 0; +DROP TABLE IF EXISTS test.t1; +DROP TABLE IF EXISTS test.t2; +DROP TABLE IF EXISTS test.t3; diff --git a/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink.result b/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink.result new file mode 100644 index 00000000000..f77a655773a --- /dev/null +++ b/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink.result @@ -0,0 +1,70 @@ +# +# MDEV-5226 mysql_tzinfo_to_sql errors with tzdata 2013f and above +# +# Verbose run +SET GLOBAL wsrep_replicate_myisam= ON; +TRUNCATE TABLE time_zone; +TRUNCATE TABLE time_zone_name; +TRUNCATE TABLE time_zone_transition; +TRUNCATE TABLE time_zone_transition_type; +INSERT INTO time_zone (Use_leap_seconds) VALUES ('N'); +SET @time_zone_id= LAST_INSERT_ID(); +INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('GMT', @time_zone_id); +INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, Is_DST, Abbreviation) VALUES + (@time_zone_id, 0, 0, 0, 'GMT') +; +Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/garbage' as time zone. Skipping it. +Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/ignored.tab' as time zone. Skipping it. +INSERT INTO time_zone (Use_leap_seconds) VALUES ('N'); +SET @time_zone_id= LAST_INSERT_ID(); +INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('posix/GMT', @time_zone_id); +INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, Is_DST, Abbreviation) VALUES + (@time_zone_id, 0, 0, 0, 'GMT') +; +Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/garbage' as time zone. Skipping it. +Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/ignored.tab' as time zone. Skipping it. +Warning: Skipping directory 'MYSQLTEST_VARDIR/zoneinfo/posix/posix': to avoid infinite symlink recursion. +ALTER TABLE time_zone_transition ORDER BY Time_zone_id, Transition_time; +ALTER TABLE time_zone_transition_type ORDER BY Time_zone_id, Transition_type_id; +SET GLOBAL wsrep_replicate_myisam= OFF; +# Silent run +SET GLOBAL wsrep_replicate_myisam= ON; +TRUNCATE TABLE time_zone; +TRUNCATE TABLE time_zone_name; +TRUNCATE TABLE time_zone_transition; +TRUNCATE TABLE time_zone_transition_type; +INSERT INTO time_zone (Use_leap_seconds) VALUES ('N'); +SET @time_zone_id= LAST_INSERT_ID(); +INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('GMT', @time_zone_id); +INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, Is_DST, Abbreviation) VALUES + (@time_zone_id, 0, 0, 0, 'GMT') +; +Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/garbage' as time zone. Skipping it. +INSERT INTO time_zone (Use_leap_seconds) VALUES ('N'); +SET @time_zone_id= LAST_INSERT_ID(); +INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('posix/GMT', @time_zone_id); +INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, Is_DST, Abbreviation) VALUES + (@time_zone_id, 0, 0, 0, 'GMT') +; +Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/garbage' as time zone. Skipping it. +ALTER TABLE time_zone_transition ORDER BY Time_zone_id, Transition_time; +ALTER TABLE time_zone_transition_type ORDER BY Time_zone_id, Transition_type_id; +SET GLOBAL wsrep_replicate_myisam= OFF; +# +# Testing with explicit timezonefile +# +SET GLOBAL wsrep_replicate_myisam= ON; +INSERT INTO time_zone (Use_leap_seconds) VALUES ('N'); +SET @time_zone_id= LAST_INSERT_ID(); +INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('XXX', @time_zone_id); +INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, Is_DST, Abbreviation) VALUES + (@time_zone_id, 0, 0, 0, 'GMT') +; +SET GLOBAL wsrep_replicate_myisam= OFF; +# +# Testing --leap +# +SET GLOBAL wsrep_replicate_myisam= ON; +TRUNCATE TABLE time_zone_leap_second; +ALTER TABLE time_zone_leap_second ORDER BY Transition_time; +SET GLOBAL wsrep_replicate_myisam= OFF; diff --git a/mysql-test/suite/wsrep/r/pool_of_threads.result b/mysql-test/suite/wsrep/r/pool_of_threads.result new file mode 100644 index 00000000000..ffe309f2580 --- /dev/null +++ b/mysql-test/suite/wsrep/r/pool_of_threads.result @@ -0,0 +1,8 @@ + +# +# MDEV#5687: Maria doesn't shutdown following upgrade to 5.5.35-galera +# +SELECT @@GLOBAL.thread_handling; +@@GLOBAL.thread_handling +pool-of-threads +# End of test. diff --git a/mysql-test/suite/wsrep/r/trans.result b/mysql-test/suite/wsrep/r/trans.result new file mode 100644 index 00000000000..bc225897103 --- /dev/null +++ b/mysql-test/suite/wsrep/r/trans.result @@ -0,0 +1,9 @@ +# +# MDEV-4222 : Assertion `( ((global_system_variables.wsrep_on) && +# (thd && thd->variables.wsrep_on)) && srep_emulate_bin_log) +# || mysql_bin_log .is_open()' fails on SAVEPOINT with +# disabled wsrep_provider +# +START TRANSACTION WITH CONSISTENT SNAPSHOT; +SAVEPOINT A; +End of test. diff --git a/mysql-test/suite/wsrep/r/variables.result b/mysql-test/suite/wsrep/r/variables.result new file mode 100644 index 00000000000..bd762f916bc --- /dev/null +++ b/mysql-test/suite/wsrep/r/variables.result @@ -0,0 +1,222 @@ + +# MDEV#5534: mysql_tzinfo_to_sql generates wrong query +# +# Testing wsrep_replicate_myisam variable. +SELECT @@session.wsrep_replicate_myisam; +ERROR HY000: Variable 'wsrep_replicate_myisam' is a GLOBAL variable +SELECT @@global.wsrep_replicate_myisam; +@@global.wsrep_replicate_myisam +0 +SET SESSION wsrep_replicate_myisam= ON; +ERROR HY000: Variable 'wsrep_replicate_myisam' is a GLOBAL variable and should be set with SET GLOBAL +SET GLOBAL wsrep_replicate_myisam= ON; +SET GLOBAL wsrep_replicate_myisam= OFF; +SET GLOBAL wsrep_provider=none; +# +# MDEV#5790: SHOW GLOBAL STATUS LIKE does not show the correct list of +# variables when using "_" +# +CALL mtr.add_suppression("WSREP: Could not open saved state file for reading.*"); +SHOW GLOBAL STATUS LIKE 'wsrep%'; +Variable_name Value +wsrep_local_state_uuid # +wsrep_protocol_version # +wsrep_last_committed # +wsrep_replicated # +wsrep_replicated_bytes # +wsrep_repl_keys # +wsrep_repl_keys_bytes # +wsrep_repl_data_bytes # +wsrep_repl_other_bytes # +wsrep_received # +wsrep_received_bytes # +wsrep_local_commits # +wsrep_local_cert_failures # +wsrep_local_replays # +wsrep_local_send_queue # +wsrep_local_send_queue_avg # +wsrep_local_recv_queue # +wsrep_local_recv_queue_avg # +wsrep_local_cached_downto # +wsrep_flow_control_paused_ns # +wsrep_flow_control_paused # +wsrep_flow_control_sent # +wsrep_flow_control_recv # +wsrep_cert_deps_distance # +wsrep_apply_oooe # +wsrep_apply_oool # +wsrep_apply_window # +wsrep_commit_oooe # +wsrep_commit_oool # +wsrep_commit_window # +wsrep_local_state # +wsrep_local_state_comment # +wsrep_cert_index_size # +wsrep_causal_reads # +wsrep_cert_interval # +wsrep_incoming_addresses # +wsrep_cluster_conf_id # +wsrep_cluster_size # +wsrep_cluster_state_uuid # +wsrep_cluster_status # +wsrep_connected # +wsrep_local_bf_aborts # +wsrep_local_index # +wsrep_provider_name # +wsrep_provider_vendor # +wsrep_provider_version # +wsrep_ready # +wsrep_thread_count # + +SHOW GLOBAL STATUS LIKE 'wsrep_%'; +Variable_name Value +wsrep_local_state_uuid # +wsrep_protocol_version # +wsrep_last_committed # +wsrep_replicated # +wsrep_replicated_bytes # +wsrep_repl_keys # +wsrep_repl_keys_bytes # +wsrep_repl_data_bytes # +wsrep_repl_other_bytes # +wsrep_received # +wsrep_received_bytes # +wsrep_local_commits # +wsrep_local_cert_failures # +wsrep_local_replays # +wsrep_local_send_queue # +wsrep_local_send_queue_avg # +wsrep_local_recv_queue # +wsrep_local_recv_queue_avg # +wsrep_local_cached_downto # +wsrep_flow_control_paused_ns # +wsrep_flow_control_paused # +wsrep_flow_control_sent # +wsrep_flow_control_recv # +wsrep_cert_deps_distance # +wsrep_apply_oooe # +wsrep_apply_oool # +wsrep_apply_window # +wsrep_commit_oooe # +wsrep_commit_oool # +wsrep_commit_window # +wsrep_local_state # +wsrep_local_state_comment # +wsrep_cert_index_size # +wsrep_causal_reads # +wsrep_cert_interval # +wsrep_incoming_addresses # +wsrep_cluster_conf_id # +wsrep_cluster_size # +wsrep_cluster_state_uuid # +wsrep_cluster_status # +wsrep_connected # +wsrep_local_bf_aborts # +wsrep_local_index # +wsrep_provider_name # +wsrep_provider_vendor # +wsrep_provider_version # +wsrep_ready # +wsrep_thread_count # +SHOW GLOBAL STATUS LIKE 'wsrep_local_state_comment'; +Variable_name Value +wsrep_local_state_comment # +# Should show nothing. +SHOW STATUS LIKE 'x'; +Variable_name Value +SET GLOBAL wsrep_provider=none; +# +# MDEV#6079: xtrabackup SST failing with maria-10.0-galera +# + +SHOW STATUS LIKE 'wsrep_local_state_uuid'; +Variable_name Value +wsrep_local_state_uuid # + +SHOW STATUS LIKE 'wsrep_last_committed'; +Variable_name Value +wsrep_last_committed # +SET GLOBAL wsrep_provider=none; + +# +# MDEV#6206: wsrep_slave_threads subtracts from max_connections +# +call mtr.add_suppression("safe_mutex: Found wrong usage of mutex 'LOCK_wsrep_slave_threads' and 'LOCK_global_system_variables'"); +call mtr.add_suppression("WSREP: Failed to get provider options"); +SELECT @@global.wsrep_provider; +@@global.wsrep_provider +libgalera_smm.so +SELECT @@global.wsrep_slave_threads; +@@global.wsrep_slave_threads +1 +SELECT @@global.wsrep_cluster_address; +@@global.wsrep_cluster_address +NULL +SHOW STATUS LIKE 'threads_connected'; +Variable_name Value +Threads_connected 1 +SHOW STATUS LIKE 'wsrep_thread_count'; +Variable_name Value +wsrep_thread_count 0 + +SELECT @@global.wsrep_provider; +@@global.wsrep_provider +libgalera_smm.so +SELECT @@global.wsrep_cluster_address; +@@global.wsrep_cluster_address +NULL +SHOW STATUS LIKE 'threads_connected'; +Variable_name Value +Threads_connected 1 +SHOW STATUS LIKE 'wsrep_thread_count'; +Variable_name Value +wsrep_thread_count 0 + +# Setting wsrep_cluster_address triggers the creation of +# applier/rollbacker threads. +SET GLOBAL wsrep_cluster_address= 'gcomm://'; +# Wait for applier threads to get created. +SELECT @@global.wsrep_provider; +@@global.wsrep_provider +libgalera_smm.so +SELECT @@global.wsrep_cluster_address; +@@global.wsrep_cluster_address +gcomm:// +SHOW STATUS LIKE 'threads_connected'; +Variable_name Value +Threads_connected 1 +SHOW STATUS LIKE 'wsrep_thread_count'; +Variable_name Value +wsrep_thread_count 2 + +SET @wsrep_slave_threads_saved= @@global.wsrep_slave_threads; +SET GLOBAL wsrep_slave_threads= 10; +# Wait for applier threads to get created. +SHOW STATUS LIKE 'threads_connected'; +Variable_name Value +Threads_connected 1 +SHOW STATUS LIKE 'wsrep_thread_count'; +Variable_name Value +wsrep_thread_count 11 +SET GLOBAL wsrep_slave_threads= @wsrep_slave_threads_saved; +SET GLOBAL wsrep_provider= none; +SET GLOBAL wsrep_cluster_address= ''; +SET GLOBAL wsrep_provider_options= ''; +# +# MDEV#6411: Setting set @@global.wsrep_sst_auth=NULL causes crash +# +SET @wsrep_sst_auth_saved= @@global.wsrep_sst_auth; +SET @@global.wsrep_sst_auth= 'user:pass'; +SELECT @@global.wsrep_sst_auth; +@@global.wsrep_sst_auth +******** +SET @@global.wsrep_sst_auth= ''; +SELECT @@global.wsrep_sst_auth; +@@global.wsrep_sst_auth + +SET @@global.wsrep_sst_auth= NULL; +SELECT @@global.wsrep_sst_auth; +@@global.wsrep_sst_auth +NULL +SET @@global.wsrep_sst_auth= @wsrep_sst_auth_saved; +# End of test. diff --git a/mysql-test/suite/wsrep/t/binlog_format.opt b/mysql-test/suite/wsrep/t/binlog_format.opt new file mode 100644 index 00000000000..1b8937b91f3 --- /dev/null +++ b/mysql-test/suite/wsrep/t/binlog_format.opt @@ -0,0 +1 @@ +--binlog-format=row --innodb_autoinc_lock_mode=2 --innodb_locks_unsafe_for_binlog=1 --wsrep-provider=$WSREP_PROVIDER --wsrep-cluster-address=gcomm:// --wsrep_provider_options='base_port=$GALERA_BASE_PORT' --wsrep-on=1 --log-bin diff --git a/mysql-test/suite/wsrep/t/binlog_format.test b/mysql-test/suite/wsrep/t/binlog_format.test new file mode 100644 index 00000000000..99d34873512 --- /dev/null +++ b/mysql-test/suite/wsrep/t/binlog_format.test @@ -0,0 +1,27 @@ +--source include/have_wsrep_enabled.inc +--source include/have_binlog_format_row.inc +# +# MDEV-4227: Galera server should stop crashing on setting binlog_format STATEMENT +# +call mtr.add_suppression("WSREP: cannot get fake InnoDB transaction ID"); +call mtr.add_suppression("WSREP: Could not open saved state file for reading:.*"); + +SHOW VARIABLES LIKE 'binlog_format'; +-- error ER_WRONG_VALUE_FOR_VAR +SET binlog_format=STATEMENT; +SHOW WARNINGS; +SHOW VARIABLES LIKE 'binlog_format'; +CREATE TABLE IF NOT EXISTS test.t1 AS SELECT * FROM information_schema.routines WHERE 1 = 0; +-- error ER_WRONG_VALUE_FOR_VAR +SET binlog_format=MIXED; +SHOW WARNINGS; +SHOW VARIABLES LIKE 'binlog_format'; +CREATE TABLE IF NOT EXISTS test.t2 AS SELECT * FROM information_schema.routines WHERE 1 = 0; +SET binlog_format=ROW; +SHOW WARNINGS; +SHOW VARIABLES LIKE 'binlog_format'; +CREATE TABLE IF NOT EXISTS test.t3 AS SELECT * FROM information_schema.routines WHERE 1 = 0; +DROP TABLE IF EXISTS test.t1; +DROP TABLE IF EXISTS test.t2; +DROP TABLE IF EXISTS test.t3; + diff --git a/mysql-test/suite/wsrep/t/mysql_tzinfo_to_sql_symlink.test b/mysql-test/suite/wsrep/t/mysql_tzinfo_to_sql_symlink.test new file mode 100644 index 00000000000..100e09d3afb --- /dev/null +++ b/mysql-test/suite/wsrep/t/mysql_tzinfo_to_sql_symlink.test @@ -0,0 +1,40 @@ +--source include/have_wsrep.inc +--source include/have_symlink.inc +--source include/not_windows.inc + +--echo # +--echo # MDEV-5226 mysql_tzinfo_to_sql errors with tzdata 2013f and above +--echo # + +--exec mkdir $MYSQLTEST_VARDIR/zoneinfo +--exec ln -s $MYSQLTEST_VARDIR/zoneinfo $MYSQLTEST_VARDIR/zoneinfo/posix +--copy_file std_data/zoneinfo/GMT $MYSQLTEST_VARDIR/zoneinfo/GMT +--copy_file std_data/words.dat $MYSQLTEST_VARDIR/zoneinfo/garbage +--copy_file std_data/words.dat $MYSQLTEST_VARDIR/zoneinfo/ignored.tab + +--echo # Verbose run +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MYSQL_TZINFO_TO_SQL --verbose $MYSQLTEST_VARDIR/zoneinfo 2>&1 + +--echo # Silent run +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MYSQL_TZINFO_TO_SQL $MYSQLTEST_VARDIR/zoneinfo 2>&1 + +--echo # +--echo # Testing with explicit timezonefile +--echo # + +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MYSQL_TZINFO_TO_SQL $MYSQLTEST_VARDIR/zoneinfo/GMT XXX 2>&1 + +--echo # +--echo # Testing --leap +--echo # + +--exec $MYSQL_TZINFO_TO_SQL --leap $MYSQLTEST_VARDIR/zoneinfo/GMT 2>&1 + +# +# Cleanup +# + +--exec rm -rf $MYSQLTEST_VARDIR/zoneinfo diff --git a/mysql-test/suite/wsrep/t/pool_of_threads.opt b/mysql-test/suite/wsrep/t/pool_of_threads.opt new file mode 100644 index 00000000000..5ee38531a4a --- /dev/null +++ b/mysql-test/suite/wsrep/t/pool_of_threads.opt @@ -0,0 +1 @@ +--binlog-format=row --innodb_autoinc_lock_mode=2 --innodb_locks_unsafe_for_binlog=1 --wsrep-provider=$WSREP_PROVIDER --wsrep-cluster-address=gcomm:// --wsrep_provider_options='base_port=$GALERA_BASE_PORT' --thread_handling=pool-of-threads diff --git a/mysql-test/suite/wsrep/t/pool_of_threads.test b/mysql-test/suite/wsrep/t/pool_of_threads.test new file mode 100644 index 00000000000..f4fffaf4f9a --- /dev/null +++ b/mysql-test/suite/wsrep/t/pool_of_threads.test @@ -0,0 +1,11 @@ +--source include/have_wsrep.inc + +--echo +--echo # +--echo # MDEV#5687: Maria doesn't shutdown following upgrade to 5.5.35-galera +--echo # + +# Note: This test is to ensure that server shuts down properly. +SELECT @@GLOBAL.thread_handling; + +--echo # End of test. diff --git a/mysql-test/suite/wsrep/t/trans.test b/mysql-test/suite/wsrep/t/trans.test new file mode 100644 index 00000000000..d8c4a4722a0 --- /dev/null +++ b/mysql-test/suite/wsrep/t/trans.test @@ -0,0 +1,14 @@ +--source include/have_wsrep.inc +--source include/have_innodb.inc + +--echo # +--echo # MDEV-4222 : Assertion `( ((global_system_variables.wsrep_on) && +--echo # (thd && thd->variables.wsrep_on)) && srep_emulate_bin_log) +--echo # || mysql_bin_log .is_open()' fails on SAVEPOINT with +--echo # disabled wsrep_provider +--echo # + +START TRANSACTION WITH CONSISTENT SNAPSHOT; +SAVEPOINT A; + +--echo End of test. diff --git a/mysql-test/suite/wsrep/t/variables.test b/mysql-test/suite/wsrep/t/variables.test new file mode 100644 index 00000000000..6cc895a75d9 --- /dev/null +++ b/mysql-test/suite/wsrep/t/variables.test @@ -0,0 +1,146 @@ +--source include/have_wsrep.inc + +# Set galera's base_port so that test can run in parallel with other galera +# tests. +--disable_query_log +eval SET GLOBAL wsrep_provider_options='base_port=$GALERA_BASE_PORT'; +--enable_query_log + +--echo +--echo # MDEV#5534: mysql_tzinfo_to_sql generates wrong query +--echo # +--echo # Testing wsrep_replicate_myisam variable. + +--disable_query_log +eval SET GLOBAL wsrep_provider= '$WSREP_PROVIDER'; +--enable_query_log + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_replicate_myisam; +SELECT @@global.wsrep_replicate_myisam; + +--error ER_GLOBAL_VARIABLE +SET SESSION wsrep_replicate_myisam= ON; +SET GLOBAL wsrep_replicate_myisam= ON; + +# Reset it back. +SET GLOBAL wsrep_replicate_myisam= OFF; +SET GLOBAL wsrep_provider=none; + +--echo # +--echo # MDEV#5790: SHOW GLOBAL STATUS LIKE does not show the correct list of +--echo # variables when using "_" +--echo # + +CALL mtr.add_suppression("WSREP: Could not open saved state file for reading.*"); + +--disable_query_log +eval SET GLOBAL wsrep_provider= '$WSREP_PROVIDER'; +--enable_query_log + +--replace_column 2 # +SHOW GLOBAL STATUS LIKE 'wsrep%'; + +--echo +--replace_column 2 # +SHOW GLOBAL STATUS LIKE 'wsrep_%'; + +--replace_column 2 # +SHOW GLOBAL STATUS LIKE 'wsrep_local_state_comment'; + +--echo # Should show nothing. +SHOW STATUS LIKE 'x'; + +# Reset it back. +SET GLOBAL wsrep_provider=none; + +--echo # +--echo # MDEV#6079: xtrabackup SST failing with maria-10.0-galera +--echo # + +--disable_query_log +eval SET GLOBAL wsrep_provider= '$WSREP_PROVIDER'; +--enable_query_log + +# The following 2 variables are used in innobackupex during xtrabackup-based +# SST. +--echo +--replace_column 2 # +SHOW STATUS LIKE 'wsrep_local_state_uuid'; +--echo +--replace_column 2 # +SHOW STATUS LIKE 'wsrep_last_committed'; + +# Reset it back. +SET GLOBAL wsrep_provider=none; + +--echo +--echo # +--echo # MDEV#6206: wsrep_slave_threads subtracts from max_connections +--echo # +call mtr.add_suppression("safe_mutex: Found wrong usage of mutex 'LOCK_wsrep_slave_threads' and 'LOCK_global_system_variables'"); +call mtr.add_suppression("WSREP: Failed to get provider options"); + +--disable_query_log +eval SET GLOBAL wsrep_provider= '$WSREP_PROVIDER'; +--enable_query_log + +--replace_regex /.*libgalera_smm.*/libgalera_smm.so/ +SELECT @@global.wsrep_provider; +SELECT @@global.wsrep_slave_threads; +SELECT @@global.wsrep_cluster_address; +SHOW STATUS LIKE 'threads_connected'; +SHOW STATUS LIKE 'wsrep_thread_count'; +--echo + +--disable_query_log +eval SET GLOBAL wsrep_provider= '$WSREP_PROVIDER'; +--enable_query_log + +--replace_regex /.*libgalera_smm.*/libgalera_smm.so/ +SELECT @@global.wsrep_provider; +SELECT @@global.wsrep_cluster_address; +SHOW STATUS LIKE 'threads_connected'; +SHOW STATUS LIKE 'wsrep_thread_count'; +--echo + +--echo # Setting wsrep_cluster_address triggers the creation of +--echo # applier/rollbacker threads. +SET GLOBAL wsrep_cluster_address= 'gcomm://'; +--echo # Wait for applier threads to get created. +sleep 3; + +--replace_regex /.*libgalera_smm.*/libgalera_smm.so/ +SELECT @@global.wsrep_provider; +SELECT @@global.wsrep_cluster_address; +SHOW STATUS LIKE 'threads_connected'; +SHOW STATUS LIKE 'wsrep_thread_count'; +--echo + +SET @wsrep_slave_threads_saved= @@global.wsrep_slave_threads; +SET GLOBAL wsrep_slave_threads= 10; +--echo # Wait for applier threads to get created. +sleep 3; +SHOW STATUS LIKE 'threads_connected'; +SHOW STATUS LIKE 'wsrep_thread_count'; + +# reset (for mtr internal checks) +SET GLOBAL wsrep_slave_threads= @wsrep_slave_threads_saved; +SET GLOBAL wsrep_provider= none; +SET GLOBAL wsrep_cluster_address= ''; +SET GLOBAL wsrep_provider_options= ''; + +--echo # +--echo # MDEV#6411: Setting set @@global.wsrep_sst_auth=NULL causes crash +--echo # +SET @wsrep_sst_auth_saved= @@global.wsrep_sst_auth; +SET @@global.wsrep_sst_auth= 'user:pass'; +SELECT @@global.wsrep_sst_auth; +SET @@global.wsrep_sst_auth= ''; +SELECT @@global.wsrep_sst_auth; +SET @@global.wsrep_sst_auth= NULL; +SELECT @@global.wsrep_sst_auth; +SET @@global.wsrep_sst_auth= @wsrep_sst_auth_saved; + +--echo # End of test. + diff --git a/mysql-test/t/mysql_tzinfo_to_sql_symlink.test b/mysql-test/t/mysql_tzinfo_to_sql_symlink.test index 1ba4e91be3c..0c70315c93b 100644 --- a/mysql-test/t/mysql_tzinfo_to_sql_symlink.test +++ b/mysql-test/t/mysql_tzinfo_to_sql_symlink.test @@ -1,5 +1,16 @@ --source include/have_symlink.inc --source include/not_windows.inc +--source include/not_wsrep.inc + +# Note: The output of mysql_tzinfo_to_sql is different if server is compiled +# with wsrep. Hence a copy of this test has been placed under wsrep suite with +# the updated result. (lp:1161432) +--source include/not_wsrep.inc + +# Note: The output of mysql_tzinfo_to_sql is different if server is compiled +# with wsrep. Hence a copy of this test has been placed under wsrep suite with +# the updated result. (lp:1161432) +--source include/not_wsrep.inc --echo # --echo # MDEV-5226 mysql_tzinfo_to_sql errors with tzdata 2013f and above diff --git a/mysql-test/t/mysqld--help.test b/mysql-test/t/mysqld--help.test index c27fa58f935..a8cafed9efb 100644 --- a/mysql-test/t/mysqld--help.test +++ b/mysql-test/t/mysqld--help.test @@ -4,6 +4,7 @@ --source include/not_embedded.inc --source include/have_perfschema.inc --source include/platform.inc +--source include/not_wsrep.inc # # force lower-case-table-names=1 (linux/macosx have different defaults) @@ -22,7 +23,7 @@ perl; log-slow-queries pid-file slow-query-log-file log-basename datadir slave-load-tmpdir tmpdir socket thread-pool-size large-files-support lower-case-file-system system-time-zone - version.*/; + wsrep-node-name version.*/; # Plugins which may or may not be there: @plugins=qw/innodb ndb archive blackhole federated partition ndbcluster diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index f0d25dae6b9..e342427c737 100644 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -15,6 +15,10 @@ INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/mysys) +IF(WITH_WSREP) + BUILD_WITH_WSREP() +ENDIF() + SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c my_default.c errors.c hash.c list.c mf_cache.c mf_dirname.c mf_fn_ext.c diff --git a/mysys/my_default.c b/mysys/my_default.c index 1e4038d17fb..4721382acc2 100644 --- a/mysys/my_default.c +++ b/mysys/my_default.c @@ -88,6 +88,12 @@ static char my_defaults_extra_file_buffer[FN_REFLEN]; static my_bool defaults_already_read= FALSE; +#ifdef WITH_WSREP +/* The only purpose of this global array is to hold full name of my.cnf + * which seems to be otherwise unavailable */ +char wsrep_defaults_file[FN_REFLEN + 10]={0,}; +#endif /* WITH_WREP */ + /* Which directories are searched for options (and in which order) */ #define MAX_DEFAULT_DIRS 6 @@ -804,6 +810,12 @@ static int search_default_file_with_ext(Process_option_func opt_handler, if (!(fp= mysql_file_fopen(key_file_cnf, name, O_RDONLY, MYF(0)))) return 1; /* Ignore wrong files */ +#ifdef WITH_WSREP + /* make sure we do this only once - for top-level file */ + if ('\0' == wsrep_defaults_file[0]) + strncpy(wsrep_defaults_file, name, sizeof(wsrep_defaults_file) - 1); +#endif /* WITH_WSREP */ + while (mysql_file_fgets(buff, sizeof(buff) - 1, fp)) { line++; diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index 60e01974320..80a43974324 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -95,6 +95,24 @@ my_bool thr_lock_inited=0; ulong locks_immediate = 0L, locks_waited = 0L; enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE; +#ifdef WITH_WSREP +static wsrep_thd_is_brute_force_fun wsrep_thd_is_brute_force= NULL; +static wsrep_abort_thd_fun wsrep_abort_thd= NULL; +static my_bool wsrep_debug; +static my_bool wsrep_convert_LOCK_to_trx; +static wsrep_on_fun wsrep_on = NULL; + +void wsrep_thr_lock_init( + wsrep_thd_is_brute_force_fun bf_fun, wsrep_abort_thd_fun abort_fun, + my_bool debug, my_bool convert_LOCK_to_trx, wsrep_on_fun on_fun +) { + wsrep_thd_is_brute_force = bf_fun; + wsrep_abort_thd = abort_fun; + wsrep_debug = debug; + wsrep_convert_LOCK_to_trx= convert_LOCK_to_trx; + wsrep_on = on_fun; +} +#endif /* The following constants are only for debug output */ #define MAX_THREADS 1000 #define MAX_LOCKS 1000 @@ -646,6 +664,108 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, DBUG_RETURN(result); } +#ifdef WITH_WSREP +/* + * If brute force applier would need to wait for a thr lock, + * it needs to make sure that it will get the lock without (too much) + * delay. + * We identify here the owners of blocking locks and ask them to + * abort. We then put our lock request in the first place in the + * wait queue. When lock holders abort (one by one) the lock release + * algorithm should grant the lock to us. We rely on this and proceed + * to wait_for_locks(). + * wsrep_break_locks() should be called in all the cases, where lock + * wait would happen. + * + * TODO: current implementation might not cover all possible lock wait + * situations. This needs an review still. + * TODO: lock release, might favor some other lock (instead our bf). + * This needs an condition to check for bf locks first. + * TODO: we still have a debug fprintf, this should be removed + */ +static inline my_bool +wsrep_break_lock( + THR_LOCK_DATA *data, struct st_lock_list *lock_queue1, + struct st_lock_list *lock_queue2, struct st_lock_list *wait_queue) +{ + if (wsrep_on(data->owner->mysql_thd) && + wsrep_thd_is_brute_force && + wsrep_thd_is_brute_force(data->owner->mysql_thd, TRUE)) + { + THR_LOCK_DATA *holder; + + /* if locking session conversion to transaction has been enabled, + we know that this conflicting lock must be read lock and furthermore, + lock holder is read-only. It is safe to wait for him. + */ +#ifdef TODO + if (wsrep_convert_LOCK_to_trx && + (THD*)(data->owner->mysql_thd)->in_lock_tables) + { + if (wsrep_debug) + fprintf(stderr,"WSREP wsrep_break_lock read lock untouched\n"); + return FALSE; + } +#endif + if (wsrep_debug) + fprintf(stderr,"WSREP wsrep_break_lock aborting locks\n"); + + /* aborting lock holder(s) here */ + for (holder=(lock_queue1) ? lock_queue1->data : NULL; + holder; + holder=holder->next) + { + if (!wsrep_thd_is_brute_force(holder->owner->mysql_thd, TRUE)) + { + wsrep_abort_thd(data->owner->mysql_thd, + holder->owner->mysql_thd, FALSE); + } + else + { + if (wsrep_debug) + fprintf(stderr,"WSREP wsrep_break_lock skipping BF lock conflict\n"); + return FALSE; + } + } + for (holder=(lock_queue2) ? lock_queue2->data : NULL; + holder; + holder=holder->next) + { + if (!wsrep_thd_is_brute_force(holder->owner->mysql_thd, TRUE)) + { + wsrep_abort_thd(data->owner->mysql_thd, + holder->owner->mysql_thd, FALSE); + } + else + { + if (wsrep_debug) + fprintf(stderr,"WSREP wsrep_break_lock skipping BF lock conflict\n"); + return FALSE; + } + } + + /* Add our lock to the head of the wait queue */ + if (*(wait_queue->last)==wait_queue->data) + { + wait_queue->last=&data->next; + assert(wait_queue->data==0); + } + else + { + assert(wait_queue->data!=0); + wait_queue->data->prev=&data->next; + } + data->next=wait_queue->data; + data->prev=&wait_queue->data; + wait_queue->data=data; + data->cond=get_cond(); + + statistic_increment(locks_immediate,&THR_LOCK_lock); + return TRUE; + } + return FALSE; +} +#endif static enum enum_thr_lock_result thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) @@ -654,6 +774,9 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) enum enum_thr_lock_result result= THR_LOCK_SUCCESS; struct st_lock_list *wait_queue; enum thr_lock_type lock_type= data->type; +#ifdef WITH_WSREP + my_bool wsrep_lock_inserted= FALSE; +#endif MYSQL_TABLE_WAIT_VARIABLES(locker, state) /* no ';' */ DBUG_ENTER("thr_lock"); @@ -723,6 +846,14 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) } if (lock->write.data->type == TL_WRITE_ONLY) { +#ifdef WITH_WSREP + if (wsrep_break_lock(data, &lock->write, NULL, &lock->read_wait)) + { + wsrep_lock_inserted= TRUE; + goto wsrep_read_wait; + } +#endif + /* We are not allowed to get a READ lock in this case */ data->type=TL_UNLOCK; result= THR_LOCK_ABORTED; /* Can't wait for this one */ @@ -750,6 +881,14 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) lock but a high priority write waiting in the write_wait queue. In the latter case we should yield the lock to the writer. */ +#ifdef WITH_WSREP + if (wsrep_break_lock(data, &lock->write, NULL, &lock->read_wait)) + { + wsrep_lock_inserted= TRUE; + } + wsrep_read_wait: +#endif + wait_queue= &lock->read_wait; } else /* Request for WRITE lock */ @@ -758,12 +897,25 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) { if (lock->write.data && lock->write.data->type == TL_WRITE_ONLY) { +#ifdef WITH_WSREP + if (wsrep_break_lock(data, &lock->write, NULL, &lock->write_wait)) + { + wsrep_lock_inserted=TRUE; + goto wsrep_write_wait; + } +#endif data->type=TL_UNLOCK; result= THR_LOCK_ABORTED; /* Can't wait for this one */ goto end; } if (lock->write.data || lock->read.data) { +#ifdef WITH_WSREP + if (wsrep_break_lock(data, &lock->write, NULL, &lock->write_wait)) + { + goto end; + } +#endif /* Add delayed write lock to write_wait queue, and return at once */ (*lock->write_wait.last)=data; data->prev=lock->write_wait.last; @@ -788,6 +940,13 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) /* Allow lock owner to bypass TL_WRITE_ONLY. */ if (!thr_lock_owner_equal(data->owner, lock->write.data->owner)) { +#ifdef WITH_WSREP + if (wsrep_break_lock(data, &lock->write, NULL, &lock->write_wait)) + { + wsrep_lock_inserted=TRUE; + goto wsrep_write_wait; + } +#endif /* We are not allowed to get a lock in this case */ data->type=TL_UNLOCK; result= THR_LOCK_ABORTED; /* Can't wait for this one */ @@ -891,9 +1050,22 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) DBUG_PRINT("lock",("write locked 3 by thread: 0x%lx type: %d", lock->read.data->owner->thread_id, data->type)); } +#ifdef WITH_WSREP + if (wsrep_break_lock(data, &lock->write, NULL, &lock->write_wait)) + { + wsrep_lock_inserted= TRUE; + } + wsrep_write_wait: + +#endif + wait_queue= &lock->write_wait; } /* Can't get lock yet; Wait for it */ +#ifdef WITH_WSREP + if (wsrep_on(data->owner->mysql_thd) && wsrep_lock_inserted) + DBUG_RETURN(wait_for_lock(wait_queue, data, 1, lock_wait_timeout)); +#endif result= wait_for_lock(wait_queue, data, 0, lock_wait_timeout); MYSQL_END_TABLE_LOCK_WAIT(locker); DBUG_RETURN(result); diff --git a/plugin/feedback/CMakeLists.txt b/plugin/feedback/CMakeLists.txt index a243ba07751..9070de26ccb 100644 --- a/plugin/feedback/CMakeLists.txt +++ b/plugin/feedback/CMakeLists.txt @@ -18,6 +18,7 @@ IF(WIN32) ENDIF(WIN32) MYSQL_ADD_PLUGIN(FEEDBACK ${FEEDBACK_SOURCES} + RECOMPILE_FOR_EMBEDDED LINK_LIBRARIES ${SSL_LIBRARIES} ${MAYBE_STATIC_ONLY} DEFAULT) diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt index d3a7861269c..1f0f28061ed 100644 --- a/scripts/CMakeLists.txt +++ b/scripts/CMakeLists.txt @@ -327,6 +327,15 @@ IF(WIN32) INSTALL_SCRIPT(${CMAKE_CURRENT_BINARY_DIR}/${file}.pl COMPONENT Server_Scripts) ENDFOREACH() ELSE() + IF(WITH_WSREP) + SET(WSREP_BINARIES + wsrep_sst_common + wsrep_sst_mysqldump + wsrep_sst_rsync + wsrep_sst_xtrabackup + wsrep_sst_xtrabackup-v2 + ) + ENDIF() # Configure this one, for testing, but do not install it. CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/mysql_config.pl.in ${CMAKE_CURRENT_BINARY_DIR}/mysql_config.pl ESCAPE_QUOTES @ONLY) @@ -346,6 +355,7 @@ ELSE() mysqldumpslow mysqld_multi mysqld_safe + ${WSREP_BINARIES} ) FOREACH(file ${BIN_SCRIPTS}) IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${file}.sh) diff --git a/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh index cd1b6fc18b7..93ab717c8ae 100644 --- a/scripts/mysqld_multi.sh +++ b/scripts/mysqld_multi.sh @@ -38,7 +38,7 @@ use Getopt::Long; use POSIX qw(strftime getcwd); $|=1; -$VER="2.16"; +$VER="2.20"; my @defaults_options; # Leading --no-defaults, --defaults-file, etc. @@ -138,6 +138,7 @@ sub main print "will be disabled\nand some will be enabled.\n\n"; } + init_log() if (!defined($opt_log)); $groupids = $ARGV[1]; if ($opt_version) { @@ -163,7 +164,6 @@ sub main !($ARGV[0] =~ m/^stop$/i) && !($ARGV[0] =~ m/^report$/i))); - init_log() if (!defined($opt_log)); if (!$opt_no_log) { w2log("$my_progname log file version $VER; run: ", @@ -218,6 +218,10 @@ sub quote_shell_word return $option; } +#### +#### get options for a group +#### + sub defaults_for_group { my ($group) = @_; diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh index 9d0dd0e68ac..4e7b098c8d8 100644 --- a/scripts/mysqld_safe.sh +++ b/scripts/mysqld_safe.sh @@ -189,6 +189,89 @@ shell_quote_string() { echo "$1" | sed -e 's,\([^a-zA-Z0-9/_.=-]\),\\\1,g' } +wsrep_pick_url() { + [ $# -eq 0 ] && return 0 + + log_error "WSREP: 'wsrep_urls' is DEPRECATED! Use wsrep_cluster_address to specify multiple addresses instead." + + if ! which nc >/dev/null; then + log_error "ERROR: nc tool not found in PATH! Make sure you have it installed." + return 1 + fi + + local url + # Assuming URL in the form scheme://host:port + # If host and port are not NULL, the liveness of URL is assumed to be tested + # If port part is absent, the url is returned literally and unconditionally + # If every URL has port but none is reachable, nothing is returned + for url in `echo $@ | sed s/,/\ /g` 0; do + local host=`echo $url | cut -d \: -f 2 | sed s/^\\\/\\\///` + local port=`echo $url | cut -d \: -f 3` + [ -z "$port" ] && break + nc -z "$host" $port >/dev/null && break + done + + if [ "$url" == "0" ]; then + log_error "ERROR: none of the URLs in '$@' is reachable." + return 1 + fi + + echo $url +} + +# Run mysqld with --wsrep-recover and parse recovered position from log. +# Position will be stored in wsrep_start_position_opt global. +wsrep_start_position_opt="" +wsrep_recover_position() { + local mysqld_cmd="$@" + local euid=$(id -u) + local ret=0 + + local wr_logfile=$(mktemp $DATADIR/wsrep_recovery.XXXXXX) + + # safety checks + if [ -z $wr_logfile ]; then + log_error "WSREP: mktemp failed" + return 1 + fi + + if [ -f $wr_logfile ]; then + [ "$euid" = "0" ] && chown $user $wr_logfile + chmod 600 $wr_logfile + else + log_error "WSREP: mktemp failed" + return 1 + fi + + local wr_pidfile="$DATADIR/"`@HOSTNAME@`"-recover.pid" + + local wr_options="--log_error='$wr_logfile' --pid-file='$wr_pidfile'" + + log_notice "WSREP: Running position recovery with $wr_options" + + eval_log_error "$mysqld_cmd --wsrep_recover $wr_options" + + local rp="$(grep 'WSREP: Recovered position:' $wr_logfile)" + if [ -z "$rp" ]; then + local skipped="$(grep WSREP $wr_logfile | grep 'skipping position recovery')" + if [ -z "$skipped" ]; then + log_error "WSREP: Failed to recover position: '`cat $wr_logfile`'" + ret=1 + else + log_notice "WSREP: Position recovery skipped" + fi + else + local start_pos="$(echo $rp | sed 's/.*WSREP\:\ Recovered\ position://' \ + | sed 's/^[ \t]*//')" + log_notice "WSREP: Recovered position $start_pos" + wsrep_start_position_opt="--wsrep_start_position=$start_pos" + fi + + [ $ret -eq 0 ] && rm $wr_logfile + + return $ret +} + parse_arguments() { # We only need to pass arguments through to the server if we don't # handle them here. So, we collect unrecognized options (passed on @@ -245,6 +328,14 @@ parse_arguments() { --timezone=*) TZ="$val"; export TZ; ;; --flush[-_]caches) flush_caches=1 ;; --numa[-_]interleave) numa_interleave=1 ;; + --wsrep[-_]urls=*) wsrep_urls="$val"; ;; + --wsrep[-_]provider=*) + if test -n "$val" && test "$val" != "none" + then + wsrep_restart=1 + fi + append_arg_to_args "$arg" + ;; --help) usage ;; @@ -860,13 +951,28 @@ max_fast_restarts=5 # flag whether a usable sleep command exists have_sleep=1 +# maximum number of wsrep restarts +max_wsrep_restarts=0 + while true do rm -f "$pid_file" # Some extra safety start_time=`date +%M%S` - eval_log_error "$cmd" + # this sets wsrep_start_position_opt + wsrep_recover_position "$cmd" + + [ $? -ne 0 ] && exit 1 # + + [ -n "$wsrep_urls" ] && url=`wsrep_pick_url $wsrep_urls` # check connect address + + if [ -z "$url" ] + then + eval_log_error "$cmd $wsrep_start_position_opt $nohup_redir" + else + eval_log_error "$cmd $wsrep_start_position_opt --wsrep_cluster_address=$url $nohup_redir" + fi if [ $want_syslog -eq 0 -a ! -f "$err_log" ]; then touch "$err_log" # hypothetical: log was renamed but not @@ -936,6 +1042,20 @@ do I=`expr $I + 1` done fi + + if [ -n "$wsrep_restart" ] + then + if [ $wsrep_restart -le $max_wsrep_restarts ] + then + wsrep_restart=`expr $wsrep_restart + 1` + log_notice "WSREP: sleeping 15 seconds before restart" + sleep 15 + else + log_notice "WSREP: not restarting wsrep node automatically" + break + fi + fi + log_notice "mysqld restarted" if test -n "$CRASH_SCRIPT" then diff --git a/scripts/wsrep_sst_common b/scripts/wsrep_sst_common new file mode 100755 index 00000000000..333d9dfab9a --- /dev/null +++ b/scripts/wsrep_sst_common @@ -0,0 +1,157 @@ +# Copyright (C) 2012-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 +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1301 USA. + +# This is a common command line parser to be sourced by other SST scripts + +set -u + +WSREP_SST_OPT_BYPASS=0 +WSREP_SST_OPT_BINLOG="" +WSREP_SST_OPT_DATA="" +WSREP_SST_OPT_AUTH="" + +while [ $# -gt 0 ]; do +case "$1" in + '--address') + readonly WSREP_SST_OPT_ADDR="$2" + shift + ;; + '--auth') + WSREP_SST_OPT_AUTH="$2" + shift + ;; + '--bypass') + WSREP_SST_OPT_BYPASS=1 + ;; + '--datadir') + readonly WSREP_SST_OPT_DATA="$2" + shift + ;; + '--defaults-file') + readonly WSREP_SST_OPT_CONF="$2" + shift + ;; + '--host') + readonly WSREP_SST_OPT_HOST="$2" + shift + ;; + '--local-port') + readonly WSREP_SST_OPT_LPORT="$2" + shift + ;; + '--parent') + readonly WSREP_SST_OPT_PARENT="$2" + shift + ;; + '--password') + WSREP_SST_OPT_PSWD="$2" + shift + ;; + '--port') + readonly WSREP_SST_OPT_PORT="$2" + shift + ;; + '--role') + readonly WSREP_SST_OPT_ROLE="$2" + shift + ;; + '--socket') + readonly WSREP_SST_OPT_SOCKET="$2" + shift + ;; + '--user') + WSREP_SST_OPT_USER="$2" + shift + ;; + '--gtid') + readonly WSREP_SST_OPT_GTID="$2" + shift + ;; + '--binlog') + WSREP_SST_OPT_BINLOG="$2" + shift + ;; + *) # must be command + # usage + # exit 1 + ;; +esac +shift +done +readonly WSREP_SST_OPT_BYPASS +readonly WSREP_SST_OPT_BINLOG + +# For Bug:1200727 +if my_print_defaults -c $WSREP_SST_OPT_CONF sst | grep -q "wsrep_sst_auth";then + if [ -z "$WSREP_SST_OPT_AUTH" -o "$WSREP_SST_OPT_AUTH" = "(null)" ];then + WSREP_SST_OPT_AUTH=$(my_print_defaults -c $WSREP_SST_OPT_CONF sst | grep -- "--wsrep_sst_auth" | cut -d= -f2) + fi +fi + +if [ -n "${WSREP_SST_OPT_DATA:-}" ] +then + SST_PROGRESS_FILE="$WSREP_SST_OPT_DATA/sst_in_progress" +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_info() +{ + wsrep_log "[INFO] $*" +} + +wsrep_cleanup_progress_file() +{ + [ -n "$SST_PROGRESS_FILE" ] && rm -f "$SST_PROGRESS_FILE" 2>/dev/null +} + +wsrep_check_program() +{ + local prog=$1 + + if ! which $prog >/dev/null + then + echo "'$prog' not found in PATH" + return 2 # no such file or directory + fi +} + +wsrep_check_programs() +{ + local ret=0 + + while [ $# -gt 0 ] + do + wsrep_check_program $1 || ret=$? + shift + done + + return $ret +} diff --git a/scripts/wsrep_sst_common.sh b/scripts/wsrep_sst_common.sh new file mode 100644 index 00000000000..333d9dfab9a --- /dev/null +++ b/scripts/wsrep_sst_common.sh @@ -0,0 +1,157 @@ +# Copyright (C) 2012-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 +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1301 USA. + +# This is a common command line parser to be sourced by other SST scripts + +set -u + +WSREP_SST_OPT_BYPASS=0 +WSREP_SST_OPT_BINLOG="" +WSREP_SST_OPT_DATA="" +WSREP_SST_OPT_AUTH="" + +while [ $# -gt 0 ]; do +case "$1" in + '--address') + readonly WSREP_SST_OPT_ADDR="$2" + shift + ;; + '--auth') + WSREP_SST_OPT_AUTH="$2" + shift + ;; + '--bypass') + WSREP_SST_OPT_BYPASS=1 + ;; + '--datadir') + readonly WSREP_SST_OPT_DATA="$2" + shift + ;; + '--defaults-file') + readonly WSREP_SST_OPT_CONF="$2" + shift + ;; + '--host') + readonly WSREP_SST_OPT_HOST="$2" + shift + ;; + '--local-port') + readonly WSREP_SST_OPT_LPORT="$2" + shift + ;; + '--parent') + readonly WSREP_SST_OPT_PARENT="$2" + shift + ;; + '--password') + WSREP_SST_OPT_PSWD="$2" + shift + ;; + '--port') + readonly WSREP_SST_OPT_PORT="$2" + shift + ;; + '--role') + readonly WSREP_SST_OPT_ROLE="$2" + shift + ;; + '--socket') + readonly WSREP_SST_OPT_SOCKET="$2" + shift + ;; + '--user') + WSREP_SST_OPT_USER="$2" + shift + ;; + '--gtid') + readonly WSREP_SST_OPT_GTID="$2" + shift + ;; + '--binlog') + WSREP_SST_OPT_BINLOG="$2" + shift + ;; + *) # must be command + # usage + # exit 1 + ;; +esac +shift +done +readonly WSREP_SST_OPT_BYPASS +readonly WSREP_SST_OPT_BINLOG + +# For Bug:1200727 +if my_print_defaults -c $WSREP_SST_OPT_CONF sst | grep -q "wsrep_sst_auth";then + if [ -z "$WSREP_SST_OPT_AUTH" -o "$WSREP_SST_OPT_AUTH" = "(null)" ];then + WSREP_SST_OPT_AUTH=$(my_print_defaults -c $WSREP_SST_OPT_CONF sst | grep -- "--wsrep_sst_auth" | cut -d= -f2) + fi +fi + +if [ -n "${WSREP_SST_OPT_DATA:-}" ] +then + SST_PROGRESS_FILE="$WSREP_SST_OPT_DATA/sst_in_progress" +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_info() +{ + wsrep_log "[INFO] $*" +} + +wsrep_cleanup_progress_file() +{ + [ -n "$SST_PROGRESS_FILE" ] && rm -f "$SST_PROGRESS_FILE" 2>/dev/null +} + +wsrep_check_program() +{ + local prog=$1 + + if ! which $prog >/dev/null + then + echo "'$prog' not found in PATH" + return 2 # no such file or directory + fi +} + +wsrep_check_programs() +{ + local ret=0 + + while [ $# -gt 0 ] + do + wsrep_check_program $1 || ret=$? + shift + done + + return $ret +} diff --git a/scripts/wsrep_sst_mysqldump b/scripts/wsrep_sst_mysqldump new file mode 100755 index 00000000000..3fce316f379 --- /dev/null +++ b/scripts/wsrep_sst_mysqldump @@ -0,0 +1,132 @@ +#!/bin/bash -e +# Copyright (C) 2009 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 +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1301 USA. + +# This is a reference script for mysqldump-based state snapshot tansfer + +# This variable is not used in mysqldump sst, so better initialize it +# to avoid shell's "parameter not set" message. +WSREP_SST_OPT_CONF="" + +. $(dirname $0)/wsrep_sst_common + +EINVAL=22 + +local_ip() +{ + PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin + + [ "$1" = "127.0.0.1" ] && return 0 + [ "$1" = "localhost" ] && return 0 + [ "$1" = "$(hostname -s)" ] && return 0 + [ "$1" = "$(hostname -f)" ] && return 0 + [ "$1" = "$(hostname -d)" ] && return 0 + + # Now if ip program is not found in the path, we can't return 0 since + # it would block any address. Thankfully grep should fail in this case + ip route get "$1" | grep local >/dev/null && return 0 + + return 1 +} + +if test -z "$WSREP_SST_OPT_USER"; then wsrep_log_error "USER cannot be nil"; exit $EINVAL; fi +if test -z "$WSREP_SST_OPT_HOST"; then wsrep_log_error "HOST cannot be nil"; exit $EINVAL; fi +if test -z "$WSREP_SST_OPT_PORT"; then wsrep_log_error "PORT cannot be nil"; exit $EINVAL; fi +if test -z "$WSREP_SST_OPT_LPORT"; then wsrep_log_error "LPORT cannot be nil"; exit $EINVAL; fi +if test -z "$WSREP_SST_OPT_SOCKET";then wsrep_log_error "SOCKET cannot be nil";exit $EINVAL; fi +if test -z "$WSREP_SST_OPT_GTID"; then wsrep_log_error "GTID cannot be nil"; exit $EINVAL; fi + +if local_ip $WSREP_SST_OPT_HOST && \ + [ "$WSREP_SST_OPT_PORT" = "$WSREP_SST_OPT_LPORT" ] +then + wsrep_log_error \ + "destination address '$WSREP_SST_OPT_HOST:$WSREP_SST_OPT_PORT' matches source address." + exit $EINVAL +fi + +# Check client version +if ! mysql --version | grep 'Distrib 10.0' >/dev/null +then + mysql --version >&2 + wsrep_log_error "this operation requires MySQL client version 10.0.x" + exit $EINVAL +fi + +# For Bug:1293798 +if [ -z "$WSREP_SST_OPT_PSWD" -a -n "$WSREP_SST_OPT_AUTH" ]; then + WSREP_SST_OPT_USER=$(echo $WSREP_SST_OPT_AUTH | cut -d: -f1) + WSREP_SST_OPT_PSWD=$(echo $WSREP_SST_OPT_AUTH | cut -d: -f2) +fi +AUTH="-u$WSREP_SST_OPT_USER" +if test -n "$WSREP_SST_OPT_PSWD"; then AUTH="$AUTH -p$WSREP_SST_OPT_PSWD"; fi + +STOP_WSREP="SET wsrep_on=OFF;" + +# NOTE: we don't use --routines here because we're dumping mysql.proc table +MYSQLDUMP="mysqldump $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" + +# mysqldump cannot restore CSV tables, fix this issue +CSV_TABLES_FIX=" +set sql_mode=''; + +USE mysql; + +SET @cond = (SELECT (SUPPORT = 'YES' or SUPPORT = 'DEFAULT') FROM INFORMATION_SCHEMA.ENGINES WHERE ENGINE = 'csv'); + +SET @stmt = IF (@cond = '1', 'CREATE TABLE IF NOT EXISTS general_log ( event_time timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), user_host mediumtext NOT NULL, thread_id bigint(21) unsigned NOT NULL, server_id int(10) unsigned NOT NULL, command_type varchar(64) NOT NULL, argument mediumtext NOT NULL) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT=\"General log\"', 'SET @dummy = 0'); + +PREPARE stmt FROM @stmt; +EXECUTE stmt; +DROP PREPARE stmt; + +SET @stmt = IF (@cond = '1', 'CREATE TABLE IF NOT EXISTS slow_log ( start_time timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), user_host mediumtext NOT NULL, query_time time(6) NOT NULL, lock_time time(6) NOT NULL, rows_sent int(11) NOT NULL, rows_examined int(11) NOT NULL, db varchar(512) NOT NULL, last_insert_id int(11) NOT NULL, insert_id int(11) NOT NULL, server_id int(10) unsigned NOT NULL, sql_text mediumtext NOT NULL, thread_id bigint(21) unsigned NOT NULL) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT=\"Slow log\"', 'SET @dummy = 0'); + +PREPARE stmt FROM @stmt; +EXECUTE stmt; +DROP PREPARE stmt;" + +SET_START_POSITION="SET GLOBAL wsrep_start_position='$WSREP_SST_OPT_GTID';" + +MYSQL="mysql $AUTH -h$WSREP_SST_OPT_HOST -P$WSREP_SST_OPT_PORT "\ +"--disable-reconnect --connect_timeout=10" + +# need to disable logging when loading the dump +# reason is that dump contains ALTER TABLE for log tables, and +# this causes an error if logging is enabled +GENERAL_LOG_OPT=`$MYSQL --skip-column-names -e"$STOP_WSREP SELECT @@GENERAL_LOG"` +SLOW_LOG_OPT=`$MYSQL --skip-column-names -e"$STOP_WSREP SELECT @@SLOW_QUERY_LOG"` +$MYSQL -e"$STOP_WSREP SET GLOBAL GENERAL_LOG=OFF" +$MYSQL -e"$STOP_WSREP SET GLOBAL SLOW_QUERY_LOG=OFF" + +# commands to restore log settings +RESTORE_GENERAL_LOG="SET GLOBAL GENERAL_LOG=$GENERAL_LOG_OPT;" +RESTORE_SLOW_QUERY_LOG="SET GLOBAL SLOW_QUERY_LOG=$SLOW_LOG_OPT;" + +if [ $WSREP_SST_OPT_BYPASS -eq 0 ] +then + (echo $STOP_WSREP && $MYSQLDUMP && echo $CSV_TABLES_FIX \ + && echo $RESTORE_GENERAL_LOG && echo $RESTORE_SLOW_QUERY_LOG \ + && echo $SET_START_POSITION \ + || echo "SST failed to complete;") | $MYSQL +else + wsrep_log_info "Bypassing state dump." + echo $SET_START_POSITION | $MYSQL +fi + +# diff --git a/scripts/wsrep_sst_mysqldump.sh b/scripts/wsrep_sst_mysqldump.sh new file mode 100644 index 00000000000..3fce316f379 --- /dev/null +++ b/scripts/wsrep_sst_mysqldump.sh @@ -0,0 +1,132 @@ +#!/bin/bash -e +# Copyright (C) 2009 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 +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1301 USA. + +# This is a reference script for mysqldump-based state snapshot tansfer + +# This variable is not used in mysqldump sst, so better initialize it +# to avoid shell's "parameter not set" message. +WSREP_SST_OPT_CONF="" + +. $(dirname $0)/wsrep_sst_common + +EINVAL=22 + +local_ip() +{ + PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin + + [ "$1" = "127.0.0.1" ] && return 0 + [ "$1" = "localhost" ] && return 0 + [ "$1" = "$(hostname -s)" ] && return 0 + [ "$1" = "$(hostname -f)" ] && return 0 + [ "$1" = "$(hostname -d)" ] && return 0 + + # Now if ip program is not found in the path, we can't return 0 since + # it would block any address. Thankfully grep should fail in this case + ip route get "$1" | grep local >/dev/null && return 0 + + return 1 +} + +if test -z "$WSREP_SST_OPT_USER"; then wsrep_log_error "USER cannot be nil"; exit $EINVAL; fi +if test -z "$WSREP_SST_OPT_HOST"; then wsrep_log_error "HOST cannot be nil"; exit $EINVAL; fi +if test -z "$WSREP_SST_OPT_PORT"; then wsrep_log_error "PORT cannot be nil"; exit $EINVAL; fi +if test -z "$WSREP_SST_OPT_LPORT"; then wsrep_log_error "LPORT cannot be nil"; exit $EINVAL; fi +if test -z "$WSREP_SST_OPT_SOCKET";then wsrep_log_error "SOCKET cannot be nil";exit $EINVAL; fi +if test -z "$WSREP_SST_OPT_GTID"; then wsrep_log_error "GTID cannot be nil"; exit $EINVAL; fi + +if local_ip $WSREP_SST_OPT_HOST && \ + [ "$WSREP_SST_OPT_PORT" = "$WSREP_SST_OPT_LPORT" ] +then + wsrep_log_error \ + "destination address '$WSREP_SST_OPT_HOST:$WSREP_SST_OPT_PORT' matches source address." + exit $EINVAL +fi + +# Check client version +if ! mysql --version | grep 'Distrib 10.0' >/dev/null +then + mysql --version >&2 + wsrep_log_error "this operation requires MySQL client version 10.0.x" + exit $EINVAL +fi + +# For Bug:1293798 +if [ -z "$WSREP_SST_OPT_PSWD" -a -n "$WSREP_SST_OPT_AUTH" ]; then + WSREP_SST_OPT_USER=$(echo $WSREP_SST_OPT_AUTH | cut -d: -f1) + WSREP_SST_OPT_PSWD=$(echo $WSREP_SST_OPT_AUTH | cut -d: -f2) +fi +AUTH="-u$WSREP_SST_OPT_USER" +if test -n "$WSREP_SST_OPT_PSWD"; then AUTH="$AUTH -p$WSREP_SST_OPT_PSWD"; fi + +STOP_WSREP="SET wsrep_on=OFF;" + +# NOTE: we don't use --routines here because we're dumping mysql.proc table +MYSQLDUMP="mysqldump $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" + +# mysqldump cannot restore CSV tables, fix this issue +CSV_TABLES_FIX=" +set sql_mode=''; + +USE mysql; + +SET @cond = (SELECT (SUPPORT = 'YES' or SUPPORT = 'DEFAULT') FROM INFORMATION_SCHEMA.ENGINES WHERE ENGINE = 'csv'); + +SET @stmt = IF (@cond = '1', 'CREATE TABLE IF NOT EXISTS general_log ( event_time timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), user_host mediumtext NOT NULL, thread_id bigint(21) unsigned NOT NULL, server_id int(10) unsigned NOT NULL, command_type varchar(64) NOT NULL, argument mediumtext NOT NULL) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT=\"General log\"', 'SET @dummy = 0'); + +PREPARE stmt FROM @stmt; +EXECUTE stmt; +DROP PREPARE stmt; + +SET @stmt = IF (@cond = '1', 'CREATE TABLE IF NOT EXISTS slow_log ( start_time timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), user_host mediumtext NOT NULL, query_time time(6) NOT NULL, lock_time time(6) NOT NULL, rows_sent int(11) NOT NULL, rows_examined int(11) NOT NULL, db varchar(512) NOT NULL, last_insert_id int(11) NOT NULL, insert_id int(11) NOT NULL, server_id int(10) unsigned NOT NULL, sql_text mediumtext NOT NULL, thread_id bigint(21) unsigned NOT NULL) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT=\"Slow log\"', 'SET @dummy = 0'); + +PREPARE stmt FROM @stmt; +EXECUTE stmt; +DROP PREPARE stmt;" + +SET_START_POSITION="SET GLOBAL wsrep_start_position='$WSREP_SST_OPT_GTID';" + +MYSQL="mysql $AUTH -h$WSREP_SST_OPT_HOST -P$WSREP_SST_OPT_PORT "\ +"--disable-reconnect --connect_timeout=10" + +# need to disable logging when loading the dump +# reason is that dump contains ALTER TABLE for log tables, and +# this causes an error if logging is enabled +GENERAL_LOG_OPT=`$MYSQL --skip-column-names -e"$STOP_WSREP SELECT @@GENERAL_LOG"` +SLOW_LOG_OPT=`$MYSQL --skip-column-names -e"$STOP_WSREP SELECT @@SLOW_QUERY_LOG"` +$MYSQL -e"$STOP_WSREP SET GLOBAL GENERAL_LOG=OFF" +$MYSQL -e"$STOP_WSREP SET GLOBAL SLOW_QUERY_LOG=OFF" + +# commands to restore log settings +RESTORE_GENERAL_LOG="SET GLOBAL GENERAL_LOG=$GENERAL_LOG_OPT;" +RESTORE_SLOW_QUERY_LOG="SET GLOBAL SLOW_QUERY_LOG=$SLOW_LOG_OPT;" + +if [ $WSREP_SST_OPT_BYPASS -eq 0 ] +then + (echo $STOP_WSREP && $MYSQLDUMP && echo $CSV_TABLES_FIX \ + && echo $RESTORE_GENERAL_LOG && echo $RESTORE_SLOW_QUERY_LOG \ + && echo $SET_START_POSITION \ + || echo "SST failed to complete;") | $MYSQL +else + wsrep_log_info "Bypassing state dump." + echo $SET_START_POSITION | $MYSQL +fi + +# diff --git a/scripts/wsrep_sst_rsync b/scripts/wsrep_sst_rsync new file mode 100755 index 00000000000..86bf557662d --- /dev/null +++ b/scripts/wsrep_sst_rsync @@ -0,0 +1,335 @@ +#!/bin/bash -ue + +# 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 +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1301 USA. + +# This is a reference script for rsync-based state snapshot tansfer + +RSYNC_PID= +RSYNC_CONF= +OS=$(uname) +[ "$OS" == "Darwin" ] && export -n LD_LIBRARY_PATH + +# Setting the path for lsof on CentOS +export PATH="/usr/sbin:/sbin:$PATH" + +. $(dirname $0)/wsrep_sst_common + +wsrep_check_programs rsync + +cleanup_joiner() +{ + wsrep_log_info "Joiner cleanup." + local PID=$(cat "$RSYNC_PID" 2>/dev/null || echo 0) + [ "0" != "$PID" ] && kill $PID && sleep 0.5 && kill -9 $PID >/dev/null 2>&1 \ + || : + rm -rf "$RSYNC_CONF" + rm -rf "$MAGIC_FILE" + rm -rf "$RSYNC_PID" + wsrep_log_info "Joiner cleanup done." + if [ "${WSREP_SST_OPT_ROLE}" = "joiner" ];then + wsrep_cleanup_progress_file + fi +} + +check_pid() +{ + local pid_file=$1 + [ -r "$pid_file" ] && ps -p $(cat $pid_file) >/dev/null 2>&1 +} + +check_pid_and_port() +{ + local pid_file=$1 + local rsync_pid=$2 + local rsync_port=$3 + + if ! which lsof > /dev/null; then + wsrep_log_error "lsof tool not found in PATH! Make sure you have it installed." + exit 2 # ENOENT + fi + + local port_info=$(lsof -i :$rsync_port -Pn 2>/dev/null | \ + grep "(LISTEN)") + local is_rsync=$(echo $port_info | \ + grep -w '^rsync[[:space:]]\+'"$rsync_pid" 2>/dev/null) + + if [ -n "$port_info" -a -z "$is_rsync" ]; then + wsrep_log_error "rsync daemon port '$rsync_port' has been taken" + exit 16 # EBUSY + fi + check_pid $pid_file && \ + [ -n "$port_info" ] && [ -n "$is_rsync" ] && \ + [ $(cat $pid_file) -eq $rsync_pid ] +} + +MAGIC_FILE="$WSREP_SST_OPT_DATA/rsync_sst_complete" +rm -rf "$MAGIC_FILE" + +BINLOG_TAR_FILE="$WSREP_SST_OPT_DATA/wsrep_sst_binlog.tar" +BINLOG_N_FILES=1 +rm -f "$BINLOG_TAR_FILE" || : + +if ! [ -z $WSREP_SST_OPT_BINLOG ] +then + BINLOG_DIRNAME=$(dirname $WSREP_SST_OPT_BINLOG) + BINLOG_FILENAME=$(basename $WSREP_SST_OPT_BINLOG) +fi + +WSREP_LOG_DIR=${WSREP_LOG_DIR:-""} +# if WSREP_LOG_DIR env. variable is not set, try to get it from my.cnf +if [ -z "$WSREP_LOG_DIR" ]; then + SCRIPT_DIR="$(cd $(dirname "$0"); pwd -P)" + WSREP_LOG_DIR=$($SCRIPT_DIR/my_print_defaults --defaults-file \ + "$WSREP_SST_OPT_CONF" mysqld server mysqld-10.0 mariadb mariadb-10.0 \ + | grep -- '--innodb[-_]log[-_]group[-_]home[-_]dir=' \ + | cut -b 29- ) +fi + +if [ -n "$WSREP_LOG_DIR" ]; then + # handle both relative and absolute paths + WSREP_LOG_DIR=$(cd $WSREP_SST_OPT_DATA; mkdir -p "$WSREP_LOG_DIR"; cd $WSREP_LOG_DIR; pwd -P) +else + # default to datadir + WSREP_LOG_DIR=$(cd $WSREP_SST_OPT_DATA; pwd -P) +fi + +# Old filter - include everything except selected +# FILTER=(--exclude '*.err' --exclude '*.pid' --exclude '*.sock' \ +# --exclude '*.conf' --exclude core --exclude 'galera.*' \ +# --exclude grastate.txt --exclude '*.pem' \ +# --exclude '*.[0-9][0-9][0-9][0-9][0-9][0-9]' --exclude '*.index') + +# New filter - exclude everything except dirs (schemas) and innodb files +FILTER=(-f '- /lost+found' -f '- /.fseventsd' -f '- /.Trashes' + -f '+ /wsrep_sst_binlog.tar' -f '+ /ib_lru_dump' -f '+ /ibdata*' -f '+ /*/' -f '- /*') + +if [ "$WSREP_SST_OPT_ROLE" = "donor" ] +then + + if [ $WSREP_SST_OPT_BYPASS -eq 0 ] + then + + FLUSHED="$WSREP_SST_OPT_DATA/tables_flushed" + rm -rf "$FLUSHED" + + # Use deltaxfer only for WAN + inv=$(basename $0) + [ "$inv" = "wsrep_sst_rsync_wan" ] && WHOLE_FILE_OPT="" \ + || WHOLE_FILE_OPT="--whole-file" + + echo "flush tables" + + # wait for tables flushed and state ID written to the file + while [ ! -r "$FLUSHED" ] && ! grep -q ':' "$FLUSHED" >/dev/null 2>&1 + do + sleep 0.2 + done + + STATE="$(cat $FLUSHED)" + rm -rf "$FLUSHED" + + sync + + if ! [ -z $WSREP_SST_OPT_BINLOG ] + then + # Prepare binlog files + pushd $BINLOG_DIRNAME &> /dev/null + binlog_files_full=$(tail -n $BINLOG_N_FILES ${BINLOG_FILENAME}.index) + binlog_files="" + for ii in $binlog_files_full + do + binlog_files="$binlog_files $(basename $ii)" + done + if ! [ -z "$binlog_files" ] + then + wsrep_log_info "Preparing binlog files for transfer:" + tar -cvf $BINLOG_TAR_FILE $binlog_files >&2 + fi + popd &> /dev/null + fi + + # first, the normal directories, so that we can detect incompatible protocol + RC=0 + rsync --owner --group --perms --links --specials \ + --ignore-times --inplace --dirs --delete --quiet \ + $WHOLE_FILE_OPT "${FILTER[@]}" "$WSREP_SST_OPT_DATA/" \ + rsync://$WSREP_SST_OPT_ADDR >&2 || RC=$? + + if [ "$RC" -ne 0 ]; then + wsrep_log_error "rsync returned code $RC:" + + case $RC in + 12) RC=71 # EPROTO + wsrep_log_error \ + "rsync server on the other end has incompatible protocol. " \ + "Make sure you have the same version of rsync on all nodes." + ;; + 22) RC=12 # ENOMEM + ;; + *) RC=255 # unknown error + ;; + esac + exit $RC + fi + + # second, we transfer InnoDB log files + rsync --owner --group --perms --links --specials \ + --ignore-times --inplace --dirs --delete --quiet \ + $WHOLE_FILE_OPT -f '+ /ib_logfile[0-9]*' -f '- **' "$WSREP_LOG_DIR/" \ + rsync://$WSREP_SST_OPT_ADDR-log_dir >&2 || RC=$? + + if [ $RC -ne 0 ]; then + wsrep_log_error "rsync innodb_log_group_home_dir returned code $RC:" + exit 255 # unknown error + fi + + # then, we parallelize the transfer of database directories, use . so that pathconcatenation works + pushd "$WSREP_SST_OPT_DATA" >/dev/null + + count=1 + [ "$OS" == "Linux" ] && count=$(grep -c processor /proc/cpuinfo) + [ "$OS" == "Darwin" -o "$OS" == "FreeBSD" ] && count=$(sysctl -n hw.ncpu) + + find . -maxdepth 1 -mindepth 1 -type d -print0 | xargs -I{} -0 -P $count \ + rsync --owner --group --perms --links --specials \ + --ignore-times --inplace --recursive --delete --quiet \ + $WHOLE_FILE_OPT --exclude '*/ib_logfile*' "$WSREP_SST_OPT_DATA"/{}/ \ + rsync://$WSREP_SST_OPT_ADDR/{} >&2 || RC=$? + + popd >/dev/null + + if [ $RC -ne 0 ]; then + wsrep_log_error "find/rsync returned code $RC:" + exit 255 # unknown error + fi + + else # BYPASS + wsrep_log_info "Bypassing state dump." + STATE="$WSREP_SST_OPT_GTID" + fi + + echo "continue" # now server can resume updating data + + echo "$STATE" > "$MAGIC_FILE" + rsync --archive --quiet --checksum "$MAGIC_FILE" rsync://$WSREP_SST_OPT_ADDR + + echo "done $STATE" + +elif [ "$WSREP_SST_OPT_ROLE" = "joiner" ] +then + wsrep_check_programs lsof + + touch $SST_PROGRESS_FILE + MYSQLD_PID=$WSREP_SST_OPT_PARENT + + MODULE="rsync_sst" + + RSYNC_PID="$WSREP_SST_OPT_DATA/$MODULE.pid" + + if check_pid $RSYNC_PID + then + wsrep_log_error "rsync daemon already running." + exit 114 # EALREADY + fi + rm -rf "$RSYNC_PID" + + ADDR=$WSREP_SST_OPT_ADDR + RSYNC_PORT=$(echo $ADDR | awk -F ':' '{ print $2 }') + if [ -z "$RSYNC_PORT" ] + then + RSYNC_PORT=4444 + ADDR="$(echo $ADDR | awk -F ':' '{ print $1 }'):$RSYNC_PORT" + fi + + trap "exit 32" HUP PIPE + trap "exit 3" INT TERM ABRT + trap cleanup_joiner EXIT + + RSYNC_CONF="$WSREP_SST_OPT_DATA/$MODULE.conf" + +cat << EOF > "$RSYNC_CONF" +pid file = $RSYNC_PID +use chroot = no +read only = no +timeout = 300 +[$MODULE] + path = $WSREP_SST_OPT_DATA +[$MODULE-log_dir] + path = $WSREP_LOG_DIR +EOF + +# rm -rf "$DATA"/ib_logfile* # we don't want old logs around + + # listen at all interfaces (for firewalled setups) + rsync --daemon --no-detach --port $RSYNC_PORT --config "$RSYNC_CONF" & + RSYNC_REAL_PID=$! + + until check_pid_and_port $RSYNC_PID $RSYNC_REAL_PID $RSYNC_PORT + do + sleep 0.2 + done + + echo "ready $ADDR/$MODULE" + + # wait for SST to complete by monitoring magic file + while [ ! -r "$MAGIC_FILE" ] && check_pid "$RSYNC_PID" && \ + ps -p $MYSQLD_PID >/dev/null + do + sleep 1 + done + + if ! ps -p $MYSQLD_PID >/dev/null + then + wsrep_log_error \ + "Parent mysqld process (PID:$MYSQLD_PID) terminated unexpectedly." + exit 32 + fi + + if ! [ -z $WSREP_SST_OPT_BINLOG ] + then + + pushd $BINLOG_DIRNAME &> /dev/null + if [ -f $BINLOG_TAR_FILE ] + then + # Clean up old binlog files first + rm -f ${BINLOG_FILENAME}.* + wsrep_log_info "Extracting binlog files:" + tar -xvf $BINLOG_TAR_FILE >&2 + for ii in $(ls -1 ${BINLOG_FILENAME}.*) + do + echo ${BINLOG_DIRNAME}/${ii} >> ${BINLOG_FILENAME}.index + done + fi + popd &> /dev/null + fi + if [ -r "$MAGIC_FILE" ] + then + cat "$MAGIC_FILE" # output UUID:seqno + else + # this message should cause joiner to abort + echo "rsync process ended without creating '$MAGIC_FILE'" + fi + wsrep_cleanup_progress_file +# cleanup_joiner +else + wsrep_log_error "Unrecognized role: '$WSREP_SST_OPT_ROLE'" + exit 22 # EINVAL +fi + +rm -f $BINLOG_TAR_FILE || : + +exit 0 diff --git a/scripts/wsrep_sst_rsync.sh b/scripts/wsrep_sst_rsync.sh new file mode 100644 index 00000000000..86bf557662d --- /dev/null +++ b/scripts/wsrep_sst_rsync.sh @@ -0,0 +1,335 @@ +#!/bin/bash -ue + +# 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 +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1301 USA. + +# This is a reference script for rsync-based state snapshot tansfer + +RSYNC_PID= +RSYNC_CONF= +OS=$(uname) +[ "$OS" == "Darwin" ] && export -n LD_LIBRARY_PATH + +# Setting the path for lsof on CentOS +export PATH="/usr/sbin:/sbin:$PATH" + +. $(dirname $0)/wsrep_sst_common + +wsrep_check_programs rsync + +cleanup_joiner() +{ + wsrep_log_info "Joiner cleanup." + local PID=$(cat "$RSYNC_PID" 2>/dev/null || echo 0) + [ "0" != "$PID" ] && kill $PID && sleep 0.5 && kill -9 $PID >/dev/null 2>&1 \ + || : + rm -rf "$RSYNC_CONF" + rm -rf "$MAGIC_FILE" + rm -rf "$RSYNC_PID" + wsrep_log_info "Joiner cleanup done." + if [ "${WSREP_SST_OPT_ROLE}" = "joiner" ];then + wsrep_cleanup_progress_file + fi +} + +check_pid() +{ + local pid_file=$1 + [ -r "$pid_file" ] && ps -p $(cat $pid_file) >/dev/null 2>&1 +} + +check_pid_and_port() +{ + local pid_file=$1 + local rsync_pid=$2 + local rsync_port=$3 + + if ! which lsof > /dev/null; then + wsrep_log_error "lsof tool not found in PATH! Make sure you have it installed." + exit 2 # ENOENT + fi + + local port_info=$(lsof -i :$rsync_port -Pn 2>/dev/null | \ + grep "(LISTEN)") + local is_rsync=$(echo $port_info | \ + grep -w '^rsync[[:space:]]\+'"$rsync_pid" 2>/dev/null) + + if [ -n "$port_info" -a -z "$is_rsync" ]; then + wsrep_log_error "rsync daemon port '$rsync_port' has been taken" + exit 16 # EBUSY + fi + check_pid $pid_file && \ + [ -n "$port_info" ] && [ -n "$is_rsync" ] && \ + [ $(cat $pid_file) -eq $rsync_pid ] +} + +MAGIC_FILE="$WSREP_SST_OPT_DATA/rsync_sst_complete" +rm -rf "$MAGIC_FILE" + +BINLOG_TAR_FILE="$WSREP_SST_OPT_DATA/wsrep_sst_binlog.tar" +BINLOG_N_FILES=1 +rm -f "$BINLOG_TAR_FILE" || : + +if ! [ -z $WSREP_SST_OPT_BINLOG ] +then + BINLOG_DIRNAME=$(dirname $WSREP_SST_OPT_BINLOG) + BINLOG_FILENAME=$(basename $WSREP_SST_OPT_BINLOG) +fi + +WSREP_LOG_DIR=${WSREP_LOG_DIR:-""} +# if WSREP_LOG_DIR env. variable is not set, try to get it from my.cnf +if [ -z "$WSREP_LOG_DIR" ]; then + SCRIPT_DIR="$(cd $(dirname "$0"); pwd -P)" + WSREP_LOG_DIR=$($SCRIPT_DIR/my_print_defaults --defaults-file \ + "$WSREP_SST_OPT_CONF" mysqld server mysqld-10.0 mariadb mariadb-10.0 \ + | grep -- '--innodb[-_]log[-_]group[-_]home[-_]dir=' \ + | cut -b 29- ) +fi + +if [ -n "$WSREP_LOG_DIR" ]; then + # handle both relative and absolute paths + WSREP_LOG_DIR=$(cd $WSREP_SST_OPT_DATA; mkdir -p "$WSREP_LOG_DIR"; cd $WSREP_LOG_DIR; pwd -P) +else + # default to datadir + WSREP_LOG_DIR=$(cd $WSREP_SST_OPT_DATA; pwd -P) +fi + +# Old filter - include everything except selected +# FILTER=(--exclude '*.err' --exclude '*.pid' --exclude '*.sock' \ +# --exclude '*.conf' --exclude core --exclude 'galera.*' \ +# --exclude grastate.txt --exclude '*.pem' \ +# --exclude '*.[0-9][0-9][0-9][0-9][0-9][0-9]' --exclude '*.index') + +# New filter - exclude everything except dirs (schemas) and innodb files +FILTER=(-f '- /lost+found' -f '- /.fseventsd' -f '- /.Trashes' + -f '+ /wsrep_sst_binlog.tar' -f '+ /ib_lru_dump' -f '+ /ibdata*' -f '+ /*/' -f '- /*') + +if [ "$WSREP_SST_OPT_ROLE" = "donor" ] +then + + if [ $WSREP_SST_OPT_BYPASS -eq 0 ] + then + + FLUSHED="$WSREP_SST_OPT_DATA/tables_flushed" + rm -rf "$FLUSHED" + + # Use deltaxfer only for WAN + inv=$(basename $0) + [ "$inv" = "wsrep_sst_rsync_wan" ] && WHOLE_FILE_OPT="" \ + || WHOLE_FILE_OPT="--whole-file" + + echo "flush tables" + + # wait for tables flushed and state ID written to the file + while [ ! -r "$FLUSHED" ] && ! grep -q ':' "$FLUSHED" >/dev/null 2>&1 + do + sleep 0.2 + done + + STATE="$(cat $FLUSHED)" + rm -rf "$FLUSHED" + + sync + + if ! [ -z $WSREP_SST_OPT_BINLOG ] + then + # Prepare binlog files + pushd $BINLOG_DIRNAME &> /dev/null + binlog_files_full=$(tail -n $BINLOG_N_FILES ${BINLOG_FILENAME}.index) + binlog_files="" + for ii in $binlog_files_full + do + binlog_files="$binlog_files $(basename $ii)" + done + if ! [ -z "$binlog_files" ] + then + wsrep_log_info "Preparing binlog files for transfer:" + tar -cvf $BINLOG_TAR_FILE $binlog_files >&2 + fi + popd &> /dev/null + fi + + # first, the normal directories, so that we can detect incompatible protocol + RC=0 + rsync --owner --group --perms --links --specials \ + --ignore-times --inplace --dirs --delete --quiet \ + $WHOLE_FILE_OPT "${FILTER[@]}" "$WSREP_SST_OPT_DATA/" \ + rsync://$WSREP_SST_OPT_ADDR >&2 || RC=$? + + if [ "$RC" -ne 0 ]; then + wsrep_log_error "rsync returned code $RC:" + + case $RC in + 12) RC=71 # EPROTO + wsrep_log_error \ + "rsync server on the other end has incompatible protocol. " \ + "Make sure you have the same version of rsync on all nodes." + ;; + 22) RC=12 # ENOMEM + ;; + *) RC=255 # unknown error + ;; + esac + exit $RC + fi + + # second, we transfer InnoDB log files + rsync --owner --group --perms --links --specials \ + --ignore-times --inplace --dirs --delete --quiet \ + $WHOLE_FILE_OPT -f '+ /ib_logfile[0-9]*' -f '- **' "$WSREP_LOG_DIR/" \ + rsync://$WSREP_SST_OPT_ADDR-log_dir >&2 || RC=$? + + if [ $RC -ne 0 ]; then + wsrep_log_error "rsync innodb_log_group_home_dir returned code $RC:" + exit 255 # unknown error + fi + + # then, we parallelize the transfer of database directories, use . so that pathconcatenation works + pushd "$WSREP_SST_OPT_DATA" >/dev/null + + count=1 + [ "$OS" == "Linux" ] && count=$(grep -c processor /proc/cpuinfo) + [ "$OS" == "Darwin" -o "$OS" == "FreeBSD" ] && count=$(sysctl -n hw.ncpu) + + find . -maxdepth 1 -mindepth 1 -type d -print0 | xargs -I{} -0 -P $count \ + rsync --owner --group --perms --links --specials \ + --ignore-times --inplace --recursive --delete --quiet \ + $WHOLE_FILE_OPT --exclude '*/ib_logfile*' "$WSREP_SST_OPT_DATA"/{}/ \ + rsync://$WSREP_SST_OPT_ADDR/{} >&2 || RC=$? + + popd >/dev/null + + if [ $RC -ne 0 ]; then + wsrep_log_error "find/rsync returned code $RC:" + exit 255 # unknown error + fi + + else # BYPASS + wsrep_log_info "Bypassing state dump." + STATE="$WSREP_SST_OPT_GTID" + fi + + echo "continue" # now server can resume updating data + + echo "$STATE" > "$MAGIC_FILE" + rsync --archive --quiet --checksum "$MAGIC_FILE" rsync://$WSREP_SST_OPT_ADDR + + echo "done $STATE" + +elif [ "$WSREP_SST_OPT_ROLE" = "joiner" ] +then + wsrep_check_programs lsof + + touch $SST_PROGRESS_FILE + MYSQLD_PID=$WSREP_SST_OPT_PARENT + + MODULE="rsync_sst" + + RSYNC_PID="$WSREP_SST_OPT_DATA/$MODULE.pid" + + if check_pid $RSYNC_PID + then + wsrep_log_error "rsync daemon already running." + exit 114 # EALREADY + fi + rm -rf "$RSYNC_PID" + + ADDR=$WSREP_SST_OPT_ADDR + RSYNC_PORT=$(echo $ADDR | awk -F ':' '{ print $2 }') + if [ -z "$RSYNC_PORT" ] + then + RSYNC_PORT=4444 + ADDR="$(echo $ADDR | awk -F ':' '{ print $1 }'):$RSYNC_PORT" + fi + + trap "exit 32" HUP PIPE + trap "exit 3" INT TERM ABRT + trap cleanup_joiner EXIT + + RSYNC_CONF="$WSREP_SST_OPT_DATA/$MODULE.conf" + +cat << EOF > "$RSYNC_CONF" +pid file = $RSYNC_PID +use chroot = no +read only = no +timeout = 300 +[$MODULE] + path = $WSREP_SST_OPT_DATA +[$MODULE-log_dir] + path = $WSREP_LOG_DIR +EOF + +# rm -rf "$DATA"/ib_logfile* # we don't want old logs around + + # listen at all interfaces (for firewalled setups) + rsync --daemon --no-detach --port $RSYNC_PORT --config "$RSYNC_CONF" & + RSYNC_REAL_PID=$! + + until check_pid_and_port $RSYNC_PID $RSYNC_REAL_PID $RSYNC_PORT + do + sleep 0.2 + done + + echo "ready $ADDR/$MODULE" + + # wait for SST to complete by monitoring magic file + while [ ! -r "$MAGIC_FILE" ] && check_pid "$RSYNC_PID" && \ + ps -p $MYSQLD_PID >/dev/null + do + sleep 1 + done + + if ! ps -p $MYSQLD_PID >/dev/null + then + wsrep_log_error \ + "Parent mysqld process (PID:$MYSQLD_PID) terminated unexpectedly." + exit 32 + fi + + if ! [ -z $WSREP_SST_OPT_BINLOG ] + then + + pushd $BINLOG_DIRNAME &> /dev/null + if [ -f $BINLOG_TAR_FILE ] + then + # Clean up old binlog files first + rm -f ${BINLOG_FILENAME}.* + wsrep_log_info "Extracting binlog files:" + tar -xvf $BINLOG_TAR_FILE >&2 + for ii in $(ls -1 ${BINLOG_FILENAME}.*) + do + echo ${BINLOG_DIRNAME}/${ii} >> ${BINLOG_FILENAME}.index + done + fi + popd &> /dev/null + fi + if [ -r "$MAGIC_FILE" ] + then + cat "$MAGIC_FILE" # output UUID:seqno + else + # this message should cause joiner to abort + echo "rsync process ended without creating '$MAGIC_FILE'" + fi + wsrep_cleanup_progress_file +# cleanup_joiner +else + wsrep_log_error "Unrecognized role: '$WSREP_SST_OPT_ROLE'" + exit 22 # EINVAL +fi + +rm -f $BINLOG_TAR_FILE || : + +exit 0 diff --git a/scripts/wsrep_sst_xtrabackup b/scripts/wsrep_sst_xtrabackup new file mode 100755 index 00000000000..6b33eabee23 --- /dev/null +++ b/scripts/wsrep_sst_xtrabackup @@ -0,0 +1,715 @@ +#!/bin/bash -ue +# Copyright (C) 2013 Percona Inc +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1301 USA. + +# Optional dependencies and options documented here: http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html +# Make sure to read that before proceeding! + + + + +. $(dirname $0)/wsrep_sst_common + +ealgo="" +ekey="" +ekeyfile="" +encrypt=0 +nproc=1 +ecode=0 +XTRABACKUP_PID="" +SST_PORT="" +REMOTEIP="" +tcert="" +tpem="" +sockopt="" +progress="" +ttime=0 +totime=0 +lsn="" +incremental=0 +ecmd="" +rlimit="" + +sfmt="tar" +strmcmd="" +tfmt="" +tcmd="" +rebuild=0 +rebuildcmd="" +payload=0 +pvformat="-F '%N => Rate:%r Avg:%a Elapsed:%t %e Bytes: %b %p' " +pvopts="-f -i 10 -N $WSREP_SST_OPT_ROLE " +uextra=0 + +if which pv &>/dev/null && pv --help | grep -q FORMAT;then + pvopts+=$pvformat +fi +pcmd="pv $pvopts" +declare -a RC + +INNOBACKUPEX_BIN=innobackupex +readonly AUTH=(${WSREP_SST_OPT_AUTH//:/ }) +DATA="${WSREP_SST_OPT_DATA}" +INFO_FILE="xtrabackup_galera_info" +IST_FILE="xtrabackup_ist" +MAGIC_FILE="${DATA}/${INFO_FILE}" + +# Setting the path for ss and ip +export PATH="/usr/sbin:/sbin:$PATH" + +timeit(){ + local stage=$1 + shift + local cmd="$@" + local x1 x2 took extcode + + if [[ $ttime -eq 1 ]];then + x1=$(date +%s) + wsrep_log_info "Evaluating $cmd" + eval "$cmd" + extcode=$? + x2=$(date +%s) + took=$(( x2-x1 )) + wsrep_log_info "NOTE: $stage took $took seconds" + totime=$(( totime+took )) + else + wsrep_log_info "Evaluating $cmd" + eval "$cmd" + extcode=$? + fi + return $extcode +} + +get_keys() +{ + if [[ $encrypt -eq 2 ]];then + return + fi + + if [[ $encrypt -eq 0 ]];then + if my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -q encrypt;then + wsrep_log_error "Unexpected option combination. SST may fail. Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html " + fi + return + fi + + if [[ $sfmt == 'tar' ]];then + wsrep_log_info "NOTE: Xtrabackup-based encryption - encrypt=1 - cannot be enabled with tar format" + encrypt=0 + return + fi + + wsrep_log_info "Xtrabackup based encryption enabled in my.cnf - Supported only from Xtrabackup 2.1.4" + + if [[ -z $ealgo ]];then + wsrep_log_error "FATAL: Encryption algorithm empty from my.cnf, bailing out" + exit 3 + fi + + if [[ -z $ekey && ! -r $ekeyfile ]];then + wsrep_log_error "FATAL: Either key or keyfile must be readable" + exit 3 + fi + + if [[ -z $ekey ]];then + ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key-file=$ekeyfile" + else + ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key=$ekey" + fi + + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + ecmd+=" -d" + fi +} + +get_transfer() +{ + if [[ -z $SST_PORT ]];then + TSST_PORT=4444 + else + TSST_PORT=$SST_PORT + fi + + if [[ $tfmt == 'nc' ]];then + if [[ ! -x `which nc` ]];then + wsrep_log_error "nc(netcat) not found in path: $PATH" + exit 2 + fi + wsrep_log_info "Using netcat as streamer" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + tcmd="nc -dl ${TSST_PORT}" + else + tcmd="nc ${REMOTEIP} ${TSST_PORT}" + fi + else + tfmt='socat' + wsrep_log_info "Using socat as streamer" + if [[ ! -x `which socat` ]];then + wsrep_log_error "socat not found in path: $PATH" + exit 2 + fi + + if [[ $encrypt -eq 2 ]] && ! socat -V | grep -q OPENSSL;then + wsrep_log_info "NOTE: socat is not openssl enabled, falling back to plain transfer" + encrypt=0 + fi + + if [[ $encrypt -eq 2 ]];then + wsrep_log_info "Using openssl based encryption with socat" + if [[ -z $tpem || -z $tcert ]];then + wsrep_log_error "Both PEM and CRT files required" + exit 22 + fi + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + wsrep_log_info "Decrypting with PEM $tpem, CA: $tcert" + tcmd="socat -u openssl-listen:${TSST_PORT},reuseaddr,cert=$tpem,cafile=${tcert}${sockopt} stdio" + else + wsrep_log_info "Encrypting with PEM $tpem, CA: $tcert" + tcmd="socat -u stdio openssl-connect:${REMOTEIP}:${TSST_PORT},cert=$tpem,cafile=${tcert}${sockopt}" + 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 + fi + fi + +} + +parse_cnf() +{ + local group=$1 + local var=$2 + reval=$(my_print_defaults -c $WSREP_SST_OPT_CONF $group | awk -F= '{if ($1 ~ /_/) { gsub(/_/,"-",$1); print $1"="$2 } else { print $0 }}' | grep -- "--$var=" | cut -d= -f2-) + if [[ -z $reval ]];then + [[ -n $3 ]] && reval=$3 + fi + echo $reval +} + +get_footprint() +{ + pushd $WSREP_SST_OPT_DATA 1>/dev/null + payload=$(find . -regex '.*\.ibd$\|.*\.MYI$\|.*\.MYD$\|.*ibdata1$' -type f -print0 | xargs -0 du --block-size=1 -c | awk 'END { print $1 }') + if my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -q -- "--compress";then + # QuickLZ has around 50% compression ratio + # When compression/compaction used, the progress is only an approximate. + payload=$(( payload*1/2 )) + fi + popd 1>/dev/null + pcmd+=" -s $payload" + adjust_progress +} + +adjust_progress() +{ + if [[ -n $progress && $progress != '1' ]];then + if [[ -e $progress ]];then + pcmd+=" 2>>$progress" + else + pcmd+=" 2>$progress" + fi + elif [[ -z $progress && -n $rlimit ]];then + # When rlimit is non-zero + pcmd="pv -q" + fi + + if [[ -n $rlimit && "$WSREP_SST_OPT_ROLE" == "donor" ]];then + wsrep_log_info "Rate-limiting SST to $rlimit" + pcmd+=" -L \$rlimit" + fi +} + +read_cnf() +{ + sfmt=$(parse_cnf sst streamfmt "tar") + tfmt=$(parse_cnf sst transferfmt "socat") + tcert=$(parse_cnf sst tca "") + tpem=$(parse_cnf sst tcert "") + encrypt=$(parse_cnf sst encrypt 0) + sockopt=$(parse_cnf sst sockopt "") + progress=$(parse_cnf sst progress "") + rebuild=$(parse_cnf sst rebuild 0) + ttime=$(parse_cnf sst time 0) + incremental=$(parse_cnf sst incremental 0) + ealgo=$(parse_cnf xtrabackup encrypt "") + ekey=$(parse_cnf xtrabackup encrypt-key "") + ekeyfile=$(parse_cnf xtrabackup encrypt-key-file "") + + # Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html + if [[ -z $ealgo ]];then + ealgo=$(parse_cnf sst encrypt-algo "") + ekey=$(parse_cnf sst encrypt-key "") + ekeyfile=$(parse_cnf sst encrypt-key-file "") + fi + rlimit=$(parse_cnf sst rlimit "") + uextra=$(parse_cnf sst use_extra 0) +} + +get_stream() +{ + if [[ $sfmt == 'xbstream' ]];then + wsrep_log_info "Streaming with xbstream" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + strmcmd="xbstream -x" + else + strmcmd="xbstream -c \${INFO_FILE} \${IST_FILE}" + fi + else + sfmt="tar" + wsrep_log_info "Streaming with tar" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + strmcmd="tar xfi - --recursive-unlink -h" + else + strmcmd="tar cf - \${INFO_FILE} \${IST_FILE}" + fi + + fi +} + +get_proc() +{ + set +e + nproc=$(grep -c processor /proc/cpuinfo) + [[ -z $nproc || $nproc -eq 0 ]] && nproc=1 + set -e +} + +sig_joiner_cleanup() +{ + wsrep_log_error "Removing $MAGIC_FILE file due to signal" + 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" + fi + if [ "${WSREP_SST_OPT_ROLE}" = "joiner" ];then + wsrep_log_info "Removing the sst_in_progress file" + wsrep_cleanup_progress_file + fi + if [[ -n $progress && -p $progress ]];then + wsrep_log_info "Cleaning up fifo file $progress" + rm $progress + fi +} + +check_pid() +{ + local pid_file="$1" + [ -r "$pid_file" ] && ps -p $(cat "$pid_file") >/dev/null 2>&1 +} + +cleanup_donor() +{ + # Since this is invoked just after exit NNN + local estatus=$? + if [[ $estatus -ne 0 ]];then + wsrep_log_error "Cleanup after exit with status:$estatus" + fi + + if [[ -n $XTRABACKUP_PID ]];then + if check_pid $XTRABACKUP_PID + then + wsrep_log_error "xtrabackup process is still running. Killing... " + kill_xtrabackup + fi + + rm -f $XTRABACKUP_PID + fi + rm -f ${DATA}/${IST_FILE} + + if [[ -n $progress && -p $progress ]];then + wsrep_log_info "Cleaning up fifo file $progress" + rm $progress + fi +} + +kill_xtrabackup() +{ + local PID=$(cat $XTRABACKUP_PID) + [ -n "$PID" -a "0" != "$PID" ] && kill $PID && (kill $PID && kill -9 $PID) || : + rm -f "$XTRABACKUP_PID" +} + +setup_ports() +{ + if [[ "$WSREP_SST_OPT_ROLE" == "donor" ]];then + SST_PORT=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $2 }') + REMOTEIP=$(echo $WSREP_SST_OPT_ADDR | awk -F ':' '{ print $1 }') + lsn=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $4 }') + else + SST_PORT=$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $2 }') + fi +} + +# waits ~10 seconds for 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 + ss -p state listening "( sport = :$PORT )" | grep -qE 'socat|nc' && break + sleep 0.2 + done + if [[ $incremental -eq 1 ]];then + echo "ready ${ADDR}/${MODULE}/$lsn" + else + echo "ready ${ADDR}/${MODULE}" + fi +} + +check_extra() +{ + local use_socket=1 + if [[ $uextra -eq 1 ]];then + if my_print_defaults -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--thread-handling=" | grep -q 'pool-of-threads';then + local eport=$(my_print_defaults -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--extra-port=" | cut -d= -f2) + if [[ -n $eport ]];then + # Xtrabackup works only locally. + # Hence, setting host to 127.0.0.1 unconditionally. + wsrep_log_info "SST through extra_port $eport" + INNOEXTRA+=" --host=127.0.0.1 --port=$eport " + use_socket=0 + else + wsrep_log_error "Extra port $eport null, failing" + exit 1 + fi + else + wsrep_log_info "Thread pool not set, ignore the option use_extra" + fi + fi + if [[ $use_socket -eq 1 ]] && [[ -n "${WSREP_SST_OPT_SOCKET}" ]];then + INNOEXTRA+=" --socket=${WSREP_SST_OPT_SOCKET}" + fi +} + +if [[ ! -x `which innobackupex` ]];then + wsrep_log_error "innobackupex not in path: $PATH" + exit 2 +fi + +rm -f "${MAGIC_FILE}" + +if [[ ! ${WSREP_SST_OPT_ROLE} == 'joiner' && ! ${WSREP_SST_OPT_ROLE} == 'donor' ]];then + wsrep_log_error "Invalid role ${WSREP_SST_OPT_ROLE}" + exit 22 +fi + +read_cnf +setup_ports +get_stream +get_transfer + +INNOEXTRA="" +INNOAPPLY="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} --apply-log \$rebuildcmd \${DATA} &>\${DATA}/innobackup.prepare.log" +INNOBACKUP="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} \$INNOEXTRA --galera-info --stream=\$sfmt \${TMPDIR} 2>\${DATA}/innobackup.backup.log" + +if [ "$WSREP_SST_OPT_ROLE" = "donor" ] +then + trap cleanup_donor EXIT + + if [ $WSREP_SST_OPT_BYPASS -eq 0 ] + then + TMPDIR="${TMPDIR:-/tmp}" + + if [ "${AUTH[0]}" != "(null)" ]; then + INNOEXTRA+=" --user=${AUTH[0]}" + fi + + if [ ${#AUTH[*]} -eq 2 ]; then + INNOEXTRA+=" --password=${AUTH[1]}" + elif [ "${AUTH[0]}" != "(null)" ]; then + # Empty password, used for testing, debugging etc. + INNOEXTRA+=" --password=" + fi + + get_keys + if [[ $encrypt -eq 1 ]];then + if [[ -n $ekey ]];then + INNOEXTRA+=" --encrypt=$ealgo --encrypt-key=$ekey " + else + INNOEXTRA+=" --encrypt=$ealgo --encrypt-key-file=$ekeyfile " + fi + fi + + if [[ -n $lsn ]];then + INNOEXTRA+=" --incremental --incremental-lsn=$lsn " + fi + + check_extra + + wsrep_log_info "Streaming the backup to joiner at ${REMOTEIP} ${SST_PORT}" + + if [[ -n $progress ]];then + get_footprint + tcmd="$pcmd | $tcmd" + elif [[ -n $rlimit ]];then + adjust_progress + tcmd="$pcmd | $tcmd" + fi + + set +e + timeit "Donor-Transfer" "$INNOBACKUP | $tcmd; RC=( "\${PIPESTATUS[@]}" )" + set -e + + if [ ${RC[0]} -ne 0 ]; then + wsrep_log_error "${INNOBACKUPEX_BIN} finished with error: ${RC[0]}. " \ + "Check ${DATA}/innobackup.backup.log" + exit 22 + elif [[ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]];then + wsrep_log_error "$tcmd finished with error: ${RC[1]}" + exit 22 + fi + + # innobackupex implicitly writes PID to fixed location in ${TMPDIR} + XTRABACKUP_PID="${TMPDIR}/xtrabackup_pid" + + + else # BYPASS FOR IST + + wsrep_log_info "Bypassing the SST for IST" + STATE="${WSREP_SST_OPT_GTID}" + echo "continue" # now server can resume updating data + echo "${STATE}" > "${MAGIC_FILE}" + echo "1" > "${DATA}/${IST_FILE}" + get_keys + pushd ${DATA} 1>/dev/null + set +e + if [[ $encrypt -eq 1 ]];then + tcmd=" $ecmd | $tcmd" + fi + timeit "Donor-IST-Unencrypted-transfer" "$strmcmd | $tcmd; RC=( "\${PIPESTATUS[@]}" )" + set -e + popd 1>/dev/null + + for ecode in "${RC[@]}";do + if [[ $ecode -ne 0 ]];then + wsrep_log_error "Error while streaming data to joiner node: " \ + "exit codes: ${RC[@]}" + exit 1 + fi + done + fi + + echo "done ${WSREP_SST_OPT_GTID}" + wsrep_log_info "Total time on donor: $totime seconds" + +elif [ "${WSREP_SST_OPT_ROLE}" = "joiner" ] +then + [[ -e $SST_PROGRESS_FILE ]] && wsrep_log_info "Stale sst_in_progress file: $SST_PROGRESS_FILE" + touch $SST_PROGRESS_FILE + + if [[ ! -e ${DATA}/ibdata1 ]];then + incremental=0 + fi + + if [[ $incremental -eq 1 ]];then + wsrep_log_info "Incremental SST enabled" + #lsn=$(/pxc/bin/mysqld --defaults-file=$WSREP_SST_OPT_CONF --basedir=/pxc --wsrep-recover 2>&1 | grep -o 'log sequence number .*' | cut -d " " -f 4 | head -1) + lsn=$(grep to_lsn xtrabackup_checkpoints | cut -d= -f2 | tr -d ' ') + wsrep_log_info "Recovered LSN: $lsn" + fi + + sencrypted=1 + nthreads=1 + + MODULE="xtrabackup_sst" + + # May need xtrabackup_checkpoints later on + rm -f ${DATA}/xtrabackup_binary ${DATA}/xtrabackup_galera_info ${DATA}/xtrabackup_logfile + + ADDR=${WSREP_SST_OPT_ADDR} + if [ -z "${SST_PORT}" ] + then + SST_PORT=4444 + ADDR="$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $1 }'):${SST_PORT}" + fi + + wait_for_listen ${SST_PORT} ${ADDR} ${MODULE} & + + trap sig_joiner_cleanup HUP PIPE INT TERM + trap cleanup_joiner EXIT + + if [[ -n $progress ]];then + adjust_progress + tcmd+=" | $pcmd" + fi + + if [[ $incremental -eq 1 ]];then + BDATA=$DATA + DATA=$(mktemp -d) + MAGIC_FILE="${DATA}/${INFO_FILE}" + fi + + get_keys + set +e + if [[ $encrypt -eq 1 && $sencrypted -eq 1 ]];then + strmcmd=" $ecmd | $strmcmd" + fi + + pushd ${DATA} 1>/dev/null + timeit "Joiner-Recv-Unencrypted" "$tcmd | $strmcmd; RC=( "\${PIPESTATUS[@]}" )" + popd 1>/dev/null + + set -e + + if [[ $sfmt == 'xbstream' ]];then + # Special handling till lp:1193240 is fixed" + if [[ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]];then + wsrep_log_error "Xbstream failed" + wsrep_log_error "Data directory ${DATA} may not be empty: lp:1193240" \ + "Manual intervention required in that case" + exit 32 + fi + fi + + wait %% # join for wait_for_listen thread + + for ecode in "${RC[@]}";do + if [[ $ecode -ne 0 ]];then + wsrep_log_error "Error while getting data from donor node: " \ + "exit codes: ${RC[@]}" + exit 32 + fi + done + + if [ ! -r "${MAGIC_FILE}" ] + then + # this message should cause joiner to abort + wsrep_log_error "xtrabackup process ended without creating '${MAGIC_FILE}'" + wsrep_log_info "Contents of datadir" + wsrep_log_info "$(ls -l ${DATA}/**/*)" + exit 32 + fi + + if ! ps -p ${WSREP_SST_OPT_PARENT} &>/dev/null + then + wsrep_log_error "Parent mysqld process (PID:${WSREP_SST_OPT_PARENT}) terminated unexpectedly." + exit 32 + fi + + if [ ! -r "${DATA}/${IST_FILE}" ] + then + wsrep_log_info "Proceeding with SST" + wsrep_log_info "Removing existing ib_logfile files" + if [[ $incremental -ne 1 ]];then + rm -f ${DATA}/ib_logfile* + else + rm -f ${BDATA}/ib_logfile* + fi + + get_proc + + # Rebuild indexes for compact backups + if grep -q 'compact = 1' ${DATA}/xtrabackup_checkpoints;then + wsrep_log_info "Index compaction detected" + rebuild=1 + fi + + if [[ $rebuild -eq 1 ]];then + nthreads=$(parse_cnf xtrabackup rebuild-threads $nproc) + wsrep_log_info "Rebuilding during prepare with $nthreads threads" + rebuildcmd="--rebuild-indexes --rebuild-threads=$nthreads" + fi + + if test -n "$(find ${DATA} -maxdepth 1 -type f -name '*.qp' -print -quit)";then + + wsrep_log_info "Compressed qpress files found" + + if [[ ! -x `which qpress` ]];then + wsrep_log_error "qpress not found in path: $PATH" + exit 22 + fi + + if [[ -n $progress ]] && pv --help | grep -q 'line-mode';then + count=$(find ${DATA} -type f -name '*.qp' | wc -l) + count=$(( count*2 )) + if pv --help | grep -q FORMAT;then + pvopts="-f -s $count -l -N Decompression -F '%N => Rate:%r Elapsed:%t %e Progress: [%b/$count]'" + else + pvopts="-f -s $count -l -N Decompression" + fi + pcmd="pv $pvopts" + adjust_progress + dcmd="$pcmd | xargs -n 2 qpress -T${nproc}d" + else + dcmd="xargs -n 2 qpress -T${nproc}d" + fi + + wsrep_log_info "Removing existing ibdata1 file" + rm -f ${DATA}/ibdata1 + + # Decompress the qpress files + wsrep_log_info "Decompression with $nproc threads" + timeit "Decompression" "find ${DATA} -type f -name '*.qp' -printf '%p\n%h\n' | $dcmd" + extcode=$? + + if [[ $extcode -eq 0 ]];then + wsrep_log_info "Removing qpress files after decompression" + find ${DATA} -type f -name '*.qp' -delete + if [[ $? -ne 0 ]];then + wsrep_log_error "Something went wrong with deletion of qpress files. Investigate" + fi + else + wsrep_log_error "Decompression failed. Exit code: $extcode" + exit 22 + fi + fi + + if [[ $incremental -eq 1 ]];then + # Added --ibbackup=xtrabackup_55 because it fails otherwise citing connection issues. + INNOAPPLY="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} \ + --ibbackup=xtrabackup_55 --apply-log $rebuildcmd --redo-only $BDATA --incremental-dir=${DATA} &>>${BDATA}/innobackup.prepare.log" + fi + + wsrep_log_info "Preparing the backup at ${DATA}" + timeit "Xtrabackup prepare stage" "$INNOAPPLY" + + if [[ $incremental -eq 1 ]];then + wsrep_log_info "Cleaning up ${DATA} after incremental SST" + [[ -d ${DATA} ]] && rm -rf ${DATA} + DATA=$BDATA + fi + + if [ $? -ne 0 ]; + then + wsrep_log_error "${INNOBACKUPEX_BIN} finished with errors. Check ${DATA}/innobackup.prepare.log" + exit 22 + fi + else + 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" + exit 2 + fi + + cat "${MAGIC_FILE}" # output UUID:seqno + wsrep_log_info "Total time on joiner: $totime seconds" +fi + +exit 0 diff --git a/scripts/wsrep_sst_xtrabackup-v2 b/scripts/wsrep_sst_xtrabackup-v2 new file mode 100755 index 00000000000..f4d133d4f8e --- /dev/null +++ b/scripts/wsrep_sst_xtrabackup-v2 @@ -0,0 +1,930 @@ +#!/bin/bash -ue +# Copyright (C) 2013 Percona Inc +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1301 USA. + +# Documentation: http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html +# Make sure to read that before proceeding! + + + + +. $(dirname $0)/wsrep_sst_common + +ealgo="" +ekey="" +ekeyfile="" +encrypt=0 +nproc=1 +ecode=0 +XTRABACKUP_PID="" +SST_PORT="" +REMOTEIP="" +tcert="" +tpem="" +tkey="" +sockopt="" +progress="" +ttime=0 +totime=0 +lsn="" +incremental=0 +ecmd="" +rlimit="" +# Initially +stagemsg="${WSREP_SST_OPT_ROLE}" +cpat="" +speciald=0 +ib_home_dir="" +ib_log_dir="" + +sfmt="tar" +strmcmd="" +tfmt="" +tcmd="" +rebuild=0 +rebuildcmd="" +payload=0 +pvformat="-F '%N => Rate:%r Avg:%a Elapsed:%t %e Bytes: %b %p' " +pvopts="-f -i 10 -N $WSREP_SST_OPT_ROLE " +STATDIR="" +uextra=0 +disver="" + +tmpopts="" +itmpdir="" +xtmpdir="" + +scomp="" +sdecomp="" + +if which pv &>/dev/null && pv --help | grep -q FORMAT;then + pvopts+=$pvformat +fi +pcmd="pv $pvopts" +declare -a RC + +INNOBACKUPEX_BIN=innobackupex +readonly AUTH=(${WSREP_SST_OPT_AUTH//:/ }) +DATA="${WSREP_SST_OPT_DATA}" +INFO_FILE="xtrabackup_galera_info" +IST_FILE="xtrabackup_ist" +MAGIC_FILE="${DATA}/${INFO_FILE}" + +# Setting the path for ss and ip +export PATH="/usr/sbin:/sbin:$PATH" + +timeit(){ + local stage=$1 + shift + local cmd="$@" + local x1 x2 took extcode + + if [[ $ttime -eq 1 ]];then + x1=$(date +%s) + wsrep_log_info "Evaluating $cmd" + eval "$cmd" + extcode=$? + x2=$(date +%s) + took=$(( x2-x1 )) + wsrep_log_info "NOTE: $stage took $took seconds" + totime=$(( totime+took )) + else + wsrep_log_info "Evaluating $cmd" + eval "$cmd" + extcode=$? + fi + return $extcode +} + +get_keys() +{ + # $encrypt -eq 1 is for internal purposes only + if [[ $encrypt -ge 2 || $encrypt -eq -1 ]];then + return + fi + + if [[ $encrypt -eq 0 ]];then + if my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -q encrypt;then + wsrep_log_error "Unexpected option combination. SST may fail. Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html " + fi + return + fi + + if [[ $sfmt == 'tar' ]];then + wsrep_log_info "NOTE: Xtrabackup-based encryption - encrypt=1 - cannot be enabled with tar format" + encrypt=-1 + return + fi + + wsrep_log_info "Xtrabackup based encryption enabled in my.cnf - Supported only from Xtrabackup 2.1.4" + + if [[ -z $ealgo ]];then + wsrep_log_error "FATAL: Encryption algorithm empty from my.cnf, bailing out" + exit 3 + fi + + if [[ -z $ekey && ! -r $ekeyfile ]];then + wsrep_log_error "FATAL: Either key or keyfile must be readable" + exit 3 + fi + + if [[ -z $ekey ]];then + ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key-file=$ekeyfile" + else + ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key=$ekey" + fi + + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + ecmd+=" -d" + fi + + stagemsg+="-XB-Encrypted" +} + +get_transfer() +{ + if [[ -z $SST_PORT ]];then + TSST_PORT=4444 + else + TSST_PORT=$SST_PORT + fi + + if [[ $tfmt == 'nc' ]];then + if [[ ! -x `which nc` ]];then + wsrep_log_error "nc(netcat) not found in path: $PATH" + exit 2 + fi + wsrep_log_info "Using netcat as streamer" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + tcmd="nc -dl ${TSST_PORT}" + else + tcmd="nc ${REMOTEIP} ${TSST_PORT}" + fi + else + tfmt='socat' + wsrep_log_info "Using socat as streamer" + if [[ ! -x `which socat` ]];then + wsrep_log_error "socat not found in path: $PATH" + exit 2 + fi + + if [[ $encrypt -eq 2 || $encrypt -eq 3 ]] && ! socat -V | grep -q WITH_OPENSSL;then + wsrep_log_info "NOTE: socat is not openssl enabled, falling back to plain transfer" + encrypt=-1 + fi + + if [[ $encrypt -eq 2 ]];then + wsrep_log_info "Using openssl based encryption with socat: with crt and pem" + if [[ -z $tpem || -z $tcert ]];then + wsrep_log_error "Both PEM and CRT files required" + exit 22 + fi + stagemsg+="-OpenSSL-Encrypted-2" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + wsrep_log_info "Decrypting with PEM $tpem, CA: $tcert" + tcmd="socat -u openssl-listen:${TSST_PORT},reuseaddr,cert=$tpem,cafile=${tcert}${sockopt} stdio" + else + wsrep_log_info "Encrypting with PEM $tpem, CA: $tcert" + tcmd="socat -u stdio openssl-connect:${REMOTEIP}:${TSST_PORT},cert=$tpem,cafile=${tcert}${sockopt}" + fi + elif [[ $encrypt -eq 3 ]];then + wsrep_log_info "Using openssl based encryption with socat: with key and crt" + if [[ -z $tpem || -z $tkey ]];then + wsrep_log_error "Both certificate and key files required" + exit 22 + fi + stagemsg+="-OpenSSL-Encrypted-3" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + wsrep_log_info "Decrypting with certificate $tpem, key $tkey" + tcmd="socat -u openssl-listen:${TSST_PORT},reuseaddr,cert=$tpem,key=${tkey},verify=0${sockopt} stdio" + else + wsrep_log_info "Encrypting with certificate $tpem, key $tkey" + tcmd="socat -u stdio openssl-connect:${REMOTEIP}:${TSST_PORT},cert=$tpem,key=${tkey},verify=0${sockopt}" + 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 + fi + fi + +} + +parse_cnf() +{ + local group=$1 + local var=$2 + reval=$(my_print_defaults -c $WSREP_SST_OPT_CONF $group | awk -F= '{if ($1 ~ /_/) { gsub(/_/,"-",$1); print $1"="$2 } else { print $0 }}' | grep -- "--$var=" | cut -d= -f2-) + if [[ -z $reval ]];then + [[ -n $3 ]] && reval=$3 + fi + echo $reval +} + +get_footprint() +{ + pushd $WSREP_SST_OPT_DATA 1>/dev/null + payload=$(find . -regex '.*\.ibd$\|.*\.MYI$\|.*\.MYD$\|.*ibdata1$' -type f -print0 | xargs -0 du --block-size=1 -c | awk 'END { print $1 }') + if my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -q -- "--compress";then + # QuickLZ has around 50% compression ratio + # When compression/compaction used, the progress is only an approximate. + payload=$(( payload*1/2 )) + fi + popd 1>/dev/null + pcmd+=" -s $payload" + adjust_progress +} + +adjust_progress() +{ + if [[ -n $progress && $progress != '1' ]];then + if [[ -e $progress ]];then + pcmd+=" 2>>$progress" + else + pcmd+=" 2>$progress" + fi + elif [[ -z $progress && -n $rlimit ]];then + # When rlimit is non-zero + pcmd="pv -q" + fi + + if [[ -n $rlimit && "$WSREP_SST_OPT_ROLE" == "donor" ]];then + wsrep_log_info "Rate-limiting SST to $rlimit" + pcmd+=" -L \$rlimit" + fi +} + +read_cnf() +{ + sfmt=$(parse_cnf sst streamfmt "xbstream") + tfmt=$(parse_cnf sst transferfmt "socat") + tcert=$(parse_cnf sst tca "") + tpem=$(parse_cnf sst tcert "") + tkey=$(parse_cnf sst tkey "") + encrypt=$(parse_cnf sst encrypt 0) + sockopt=$(parse_cnf sst sockopt "") + progress=$(parse_cnf sst progress "") + rebuild=$(parse_cnf sst rebuild 0) + ttime=$(parse_cnf sst time 0) + cpat=$(parse_cnf sst cpat '.*galera\.cache$\|.*sst_in_progress$\|.*grastate\.dat$\|.*\.err$\|.*\.log$\|.*RPM_UPGRADE_MARKER$\|.*RPM_UPGRADE_HISTORY$') + incremental=$(parse_cnf sst incremental 0) + ealgo=$(parse_cnf xtrabackup encrypt "") + ekey=$(parse_cnf xtrabackup encrypt-key "") + ekeyfile=$(parse_cnf xtrabackup encrypt-key-file "") + scomp=$(parse_cnf sst compressor "") + sdecomp=$(parse_cnf sst decompressor "") + + + # Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html + if [[ -z $ealgo ]];then + ealgo=$(parse_cnf sst encrypt-algo "") + ekey=$(parse_cnf sst encrypt-key "") + ekeyfile=$(parse_cnf sst encrypt-key-file "") + fi + rlimit=$(parse_cnf sst rlimit "") + uextra=$(parse_cnf sst use-extra 0) + speciald=$(parse_cnf sst sst-special-dirs 1) + iopts=$(parse_cnf sst inno-backup-opts "") + iapts=$(parse_cnf sst inno-apply-opts "") + impts=$(parse_cnf sst inno-move-opts "") + stimeout=$(parse_cnf sst sst-initial-timeout 100) +} + +get_stream() +{ + if [[ $sfmt == 'xbstream' ]];then + wsrep_log_info "Streaming with xbstream" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + strmcmd="xbstream -x" + else + strmcmd="xbstream -c \${INFO_FILE}" + fi + else + sfmt="tar" + wsrep_log_info "Streaming with 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 || $nproc -eq 0 ]] && nproc=1 + set -e +} + +sig_joiner_cleanup() +{ + wsrep_log_error "Removing $MAGIC_FILE file due to signal" + 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" + fi + if [ "${WSREP_SST_OPT_ROLE}" = "joiner" ];then + wsrep_log_info "Removing the sst_in_progress file" + wsrep_cleanup_progress_file + fi + if [[ -n $progress && -p $progress ]];then + wsrep_log_info "Cleaning up fifo file $progress" + rm $progress + fi + if [[ -n ${STATDIR:-} ]];then + [[ -d $STATDIR ]] && rm -rf $STATDIR + fi +} + +check_pid() +{ + local pid_file="$1" + [ -r "$pid_file" ] && ps -p $(cat "$pid_file") >/dev/null 2>&1 +} + +cleanup_donor() +{ + # Since this is invoked just after exit NNN + local estatus=$? + if [[ $estatus -ne 0 ]];then + wsrep_log_error "Cleanup after exit with status:$estatus" + fi + + if [[ -n ${XTRABACKUP_PID:-} ]];then + if check_pid $XTRABACKUP_PID + then + wsrep_log_error "xtrabackup process is still running. Killing... " + kill_xtrabackup + fi + + fi + rm -f ${DATA}/${IST_FILE} || true + + if [[ -n $progress && -p $progress ]];then + wsrep_log_info "Cleaning up fifo file $progress" + rm -f $progress || true + fi + + wsrep_log_info "Cleaning up temporary directories" + + if [[ -n $xtmpdir ]];then + [[ -d $xtmpdir ]] && rm -rf $xtmpdir || true + fi + + if [[ -n $itmpdir ]];then + [[ -d $itmpdir ]] && rm -rf $itmpdir || true + fi +} + +kill_xtrabackup() +{ + local PID=$(cat $XTRABACKUP_PID) + [ -n "$PID" -a "0" != "$PID" ] && kill $PID && (kill $PID && kill -9 $PID) || : + wsrep_log_info "Removing xtrabackup pid file $XTRABACKUP_PID" + rm -f "$XTRABACKUP_PID" || true +} + +setup_ports() +{ + if [[ "$WSREP_SST_OPT_ROLE" == "donor" ]];then + SST_PORT=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $2 }') + REMOTEIP=$(echo $WSREP_SST_OPT_ADDR | awk -F ':' '{ print $1 }') + lsn=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $4 }') + else + SST_PORT=$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $2 }') + fi +} + +# waits ~10 seconds for 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 + ss -p state listening "( sport = :$PORT )" | grep -qE 'socat|nc' && break + sleep 0.2 + done + if [[ $incremental -eq 1 ]];then + echo "ready ${ADDR}/${MODULE}/$lsn" + else + echo "ready ${ADDR}/${MODULE}" + fi +} + +check_extra() +{ + local use_socket=1 + if [[ $uextra -eq 1 ]];then + if my_print_defaults -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--thread-handling=" | grep -q 'pool-of-threads';then + local eport=$(my_print_defaults -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--extra-port=" | cut -d= -f2) + if [[ -n $eport ]];then + # Xtrabackup works only locally. + # Hence, setting host to 127.0.0.1 unconditionally. + wsrep_log_info "SST through extra_port $eport" + INNOEXTRA+=" --host=127.0.0.1 --port=$eport " + use_socket=0 + else + wsrep_log_error "Extra port $eport null, failing" + exit 1 + fi + else + wsrep_log_info "Thread pool not set, ignore the option use_extra" + fi + fi + if [[ $use_socket -eq 1 ]] && [[ -n "${WSREP_SST_OPT_SOCKET}" ]];then + INNOEXTRA+=" --socket=${WSREP_SST_OPT_SOCKET}" + fi +} + +recv_joiner() +{ + local dir=$1 + local msg=$2 + local tmt=$3 + local ltcmd + + pushd ${dir} 1>/dev/null + set +e + + if [[ $tmt -gt 0 && -x `which timeout` ]];then + if timeout --help | grep -q -- '-k';then + ltcmd="timeout -k $(( tmt+10 )) $tmt $tcmd" + else + ltcmd="timeout $tmt $tcmd" + fi + timeit "$msg" "$ltcmd | $strmcmd; RC=( "\${PIPESTATUS[@]}" )" + else + timeit "$msg" "$tcmd | $strmcmd; RC=( "\${PIPESTATUS[@]}" )" + fi + + set -e + popd 1>/dev/null + + if [[ ${RC[0]} -eq 124 ]];then + wsrep_log_error "Possible timeout in receving first data from donor in gtid stage" + exit 32 + fi + + for ecode in "${RC[@]}";do + if [[ $ecode -ne 0 ]];then + wsrep_log_error "Error while getting data from donor node: " \ + "exit codes: ${RC[@]}" + exit 32 + fi + done + + if [ ! -r "${MAGIC_FILE}" ];then + # this message should cause joiner to abort + wsrep_log_error "xtrabackup process ended without creating '${MAGIC_FILE}'" + wsrep_log_info "Contents of datadir" + wsrep_log_info "$(ls -l ${dir}/*)" + exit 32 + fi +} + + +send_donor() +{ + local dir=$1 + local msg=$2 + + pushd ${dir} 1>/dev/null + set +e + timeit "$msg" "$strmcmd | $tcmd; RC=( "\${PIPESTATUS[@]}" )" + set -e + popd 1>/dev/null + + + for ecode in "${RC[@]}";do + if [[ $ecode -ne 0 ]];then + wsrep_log_error "Error while getting data from donor node: " \ + "exit codes: ${RC[@]}" + exit 32 + fi + done + +} + +if [[ ! -x `which $INNOBACKUPEX_BIN` ]];then + wsrep_log_error "innobackupex not in path: $PATH" + exit 2 +fi + +rm -f "${MAGIC_FILE}" + +if [[ ! ${WSREP_SST_OPT_ROLE} == 'joiner' && ! ${WSREP_SST_OPT_ROLE} == 'donor' ]];then + wsrep_log_error "Invalid role ${WSREP_SST_OPT_ROLE}" + exit 22 +fi + +read_cnf +setup_ports +get_stream +get_transfer + +if ${INNOBACKUPEX_BIN} /tmp --help | grep -q -- '--version-check'; then + disver="--no-version-check" +fi + + +INNOEXTRA="" +INNOAPPLY="${INNOBACKUPEX_BIN} $disver $iapts --apply-log \$rebuildcmd \${DATA} &>\${DATA}/innobackup.prepare.log" +INNOMOVE="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} $disver $impts --move-back --force-non-empty-directories \${DATA} &>\${DATA}/innobackup.move.log" +INNOBACKUP="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} $disver $iopts \$tmpopts \$INNOEXTRA --galera-info --stream=\$sfmt \$itmpdir 2>\${DATA}/innobackup.backup.log" + +if [ "$WSREP_SST_OPT_ROLE" = "donor" ] +then + trap cleanup_donor EXIT + + if [ $WSREP_SST_OPT_BYPASS -eq 0 ] + then + + if [[ -z $(parse_cnf mysqld tmpdir "") && -z $(parse_cnf xtrabackup tmpdir "") ]];then + xtmpdir=$(mktemp -d) + tmpopts=" --tmpdir=$xtmpdir " + wsrep_log_info "Using $xtmpdir as xtrabackup temporary directory" + fi + + itmpdir=$(mktemp -d) + wsrep_log_info "Using $itmpdir as innobackupex temporary directory" + + if [ "${AUTH[0]}" != "(null)" ]; then + INNOEXTRA+=" --user=${AUTH[0]}" + fi + + if [ ${#AUTH[*]} -eq 2 ]; then + INNOEXTRA+=" --password=${AUTH[1]}" + elif [ "${AUTH[0]}" != "(null)" ]; then + # Empty password, used for testing, debugging etc. + INNOEXTRA+=" --password=" + fi + + get_keys + if [[ $encrypt -eq 1 ]];then + if [[ -n $ekey ]];then + INNOEXTRA+=" --encrypt=$ealgo --encrypt-key=$ekey " + else + INNOEXTRA+=" --encrypt=$ealgo --encrypt-key-file=$ekeyfile " + fi + fi + + if [[ -n $lsn ]];then + INNOEXTRA+=" --incremental --incremental-lsn=$lsn " + fi + + check_extra + + wsrep_log_info "Streaming GTID file before SST" + + echo "${WSREP_SST_OPT_GTID}" > "${MAGIC_FILE}" + + ttcmd="$tcmd" + + if [[ $encrypt -eq 1 ]];then + if [[ -n $scomp ]];then + tcmd=" $ecmd | $scomp | $tcmd " + else + tcmd=" $ecmd | $tcmd " + fi + elif [[ -n $scomp ]];then + tcmd=" $scomp | $tcmd " + fi + + + send_donor $DATA "${stagemsg}-gtid" + + tcmd="$ttcmd" + if [[ -n $progress ]];then + get_footprint + tcmd="$pcmd | $tcmd" + elif [[ -n $rlimit ]];then + adjust_progress + tcmd="$pcmd | $tcmd" + fi + + wsrep_log_info "Sleeping before data transfer for SST" + sleep 10 + + wsrep_log_info "Streaming the backup to joiner at ${REMOTEIP} ${SST_PORT:-4444}" + + if [[ -n $scomp ]];then + tcmd="$scomp | $tcmd" + fi + + set +e + timeit "${stagemsg}-SST" "$INNOBACKUP | $tcmd; RC=( "\${PIPESTATUS[@]}" )" + set -e + + if [ ${RC[0]} -ne 0 ]; then + wsrep_log_error "${INNOBACKUPEX_BIN} finished with error: ${RC[0]}. " \ + "Check ${DATA}/innobackup.backup.log" + exit 22 + elif [[ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]];then + wsrep_log_error "$tcmd finished with error: ${RC[1]}" + exit 22 + fi + + # innobackupex implicitly writes PID to fixed location in $xtmpdir + XTRABACKUP_PID="$xtmpdir/xtrabackup_pid" + + + else # BYPASS FOR IST + + wsrep_log_info "Bypassing the SST for IST" + echo "continue" # now server can resume updating data + echo "${WSREP_SST_OPT_GTID}" > "${MAGIC_FILE}" + echo "1" > "${DATA}/${IST_FILE}" + get_keys + if [[ $encrypt -eq 1 ]];then + if [[ -n $scomp ]];then + tcmd=" $ecmd | $scomp | $tcmd " + else + tcmd=" $ecmd | $tcmd " + fi + elif [[ -n $scomp ]];then + tcmd=" $scomp | $tcmd " + fi + strmcmd+=" \${IST_FILE}" + + send_donor $DATA "${stagemsg}-IST" + + fi + + echo "done ${WSREP_SST_OPT_GTID}" + wsrep_log_info "Total time on donor: $totime seconds" + +elif [ "${WSREP_SST_OPT_ROLE}" = "joiner" ] +then + [[ -e $SST_PROGRESS_FILE ]] && wsrep_log_info "Stale sst_in_progress file: $SST_PROGRESS_FILE" + [[ -n $SST_PROGRESS_FILE ]] && touch $SST_PROGRESS_FILE + + if [[ $speciald -eq 1 ]];then + ib_home_dir=$(parse_cnf mysqld innodb-data-home-dir "") + ib_log_dir=$(parse_cnf mysqld innodb-log-group-home-dir "") + if [[ -z $ib_home_dir && -z $ib_log_dir ]];then + speciald=0 + fi + fi + + stagemsg="Joiner-Recv" + + if [[ ! -e ${DATA}/ibdata1 ]];then + incremental=0 + fi + + if [[ $incremental -eq 1 ]];then + wsrep_log_info "Incremental SST enabled: NOT SUPPORTED yet" + lsn=$(grep to_lsn xtrabackup_checkpoints | cut -d= -f2 | tr -d ' ') + wsrep_log_info "Recovered LSN: $lsn" + fi + + sencrypted=1 + nthreads=1 + + MODULE="xtrabackup_sst" + + rm -f "${DATA}/${IST_FILE}" + + # May need xtrabackup_checkpoints later on + rm -f ${DATA}/xtrabackup_binary ${DATA}/xtrabackup_galera_info ${DATA}/xtrabackup_logfile + + ADDR=${WSREP_SST_OPT_ADDR} + if [ -z "${SST_PORT}" ] + then + SST_PORT=4444 + ADDR="$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $1 }'):${SST_PORT}" + fi + + wait_for_listen ${SST_PORT} ${ADDR} ${MODULE} & + + trap sig_joiner_cleanup HUP PIPE INT TERM + trap cleanup_joiner EXIT + + if [[ -n $progress ]];then + adjust_progress + tcmd+=" | $pcmd" + fi + + if [[ $incremental -eq 1 ]];then + BDATA=$DATA + DATA=$(mktemp -d) + MAGIC_FILE="${DATA}/${INFO_FILE}" + fi + + get_keys + if [[ $encrypt -eq 1 && $sencrypted -eq 1 ]];then + if [[ -n $sdecomp ]];then + strmcmd=" $sdecomp | $ecmd | $strmcmd" + else + strmcmd=" $ecmd | $strmcmd" + fi + elif [[ -n $sdecomp ]];then + strmcmd=" $sdecomp | $strmcmd" + fi + + STATDIR=$(mktemp -d) + MAGIC_FILE="${STATDIR}/${INFO_FILE}" + recv_joiner $STATDIR "${stagemsg}-gtid" $stimeout + + if ! ps -p ${WSREP_SST_OPT_PARENT} &>/dev/null + then + wsrep_log_error "Parent mysqld process (PID:${WSREP_SST_OPT_PARENT}) terminated unexpectedly." + exit 32 + fi + + if [ ! -r "${STATDIR}/${IST_FILE}" ] + then + wsrep_log_info "Proceeding with SST" + + if [[ $speciald -eq 1 && -d ${DATA}/.sst ]];then + wsrep_log_info "WARNING: Stale temporary SST directory: ${DATA}/.sst from previous SST" + fi + + if [[ $incremental -ne 1 ]];then + if [[ $speciald -eq 1 ]];then + wsrep_log_info "Cleaning the existing datadir and innodb-data/log directories" + find $ib_home_dir $ib_log_dir $DATA -mindepth 1 -regex $cpat -prune -o -exec rm -rfv {} 1>&2 \+ + else + wsrep_log_info "Cleaning the existing datadir" + find $DATA -mindepth 1 -regex $cpat -prune -o -exec rm -rfv {} 1>&2 \+ + fi + tempdir=$(parse_cnf mysqld log-bin "") + if [[ -n ${tempdir:-} ]];then + binlog_dir=$(dirname $tempdir) + binlog_file=$(basename $tempdir) + if [[ -n ${binlog_dir:-} && $binlog_dir != '.' && $binlog_dir != $DATA ]];then + pattern="$binlog_dir/$binlog_file\.[0-9]+$" + wsrep_log_info "Cleaning the binlog directory $binlog_dir as well" + find $binlog_dir -maxdepth 1 -type f -regex $pattern -exec rm -fv {} 1>&2 \+ + rm $binlog_dir/*.index || true + fi + fi + + else + wsrep_log_info "Removing existing ib_logfile files" + rm -f ${BDATA}/ib_logfile* + fi + + + if [[ $speciald -eq 1 ]];then + mkdir -p ${DATA}/.sst + TDATA=${DATA} + DATA="${DATA}/.sst" + fi + + + MAGIC_FILE="${DATA}/${INFO_FILE}" + recv_joiner $DATA "${stagemsg}-SST" 0 + + get_proc + + # Rebuild indexes for compact backups + if grep -q 'compact = 1' ${DATA}/xtrabackup_checkpoints;then + wsrep_log_info "Index compaction detected" + rebuild=1 + fi + + if [[ $rebuild -eq 1 ]];then + nthreads=$(parse_cnf xtrabackup rebuild-threads $nproc) + wsrep_log_info "Rebuilding during prepare with $nthreads threads" + rebuildcmd="--rebuild-indexes --rebuild-threads=$nthreads" + fi + + if test -n "$(find ${DATA} -maxdepth 1 -type f -name '*.qp' -print -quit)";then + + wsrep_log_info "Compressed qpress files found" + + if [[ ! -x `which qpress` ]];then + wsrep_log_error "qpress not found in path: $PATH" + exit 22 + fi + + if [[ -n $progress ]] && pv --help | grep -q 'line-mode';then + count=$(find ${DATA} -type f -name '*.qp' | wc -l) + count=$(( count*2 )) + if pv --help | grep -q FORMAT;then + pvopts="-f -s $count -l -N Decompression -F '%N => Rate:%r Elapsed:%t %e Progress: [%b/$count]'" + else + pvopts="-f -s $count -l -N Decompression" + fi + pcmd="pv $pvopts" + adjust_progress + dcmd="$pcmd | xargs -n 2 qpress -T${nproc}d" + else + dcmd="xargs -n 2 qpress -T${nproc}d" + fi + + + # Decompress the qpress files + wsrep_log_info "Decompression with $nproc threads" + timeit "Joiner-Decompression" "find ${DATA} -type f -name '*.qp' -printf '%p\n%h\n' | $dcmd" + extcode=$? + + if [[ $extcode -eq 0 ]];then + wsrep_log_info "Removing qpress files after decompression" + find ${DATA} -type f -name '*.qp' -delete + if [[ $? -ne 0 ]];then + wsrep_log_error "Something went wrong with deletion of qpress files. Investigate" + fi + else + wsrep_log_error "Decompression failed. Exit code: $extcode" + exit 22 + fi + fi + + + if [[ ! -z $WSREP_SST_OPT_BINLOG ]];then + + BINLOG_DIRNAME=$(dirname $WSREP_SST_OPT_BINLOG) + BINLOG_FILENAME=$(basename $WSREP_SST_OPT_BINLOG) + + # To avoid comparing data directory and BINLOG_DIRNAME + mv $DATA/${BINLOG_FILENAME}.* $BINLOG_DIRNAME/ 2>/dev/null || true + + pushd $BINLOG_DIRNAME &>/dev/null + for bfiles in $(ls -1 ${BINLOG_FILENAME}.*);do + echo ${BINLOG_DIRNAME}/${bfiles} >> ${BINLOG_FILENAME}.index + done + popd &> /dev/null + + fi + + if [[ $incremental -eq 1 ]];then + # Added --ibbackup=xtrabackup_55 because it fails otherwise citing connection issues. + INNOAPPLY="${INNOBACKUPEX_BIN} $disver --defaults-file=${WSREP_SST_OPT_CONF} \ + --ibbackup=xtrabackup_56 --apply-log $rebuildcmd --redo-only $BDATA --incremental-dir=${DATA} &>>${BDATA}/innobackup.prepare.log" + fi + + wsrep_log_info "Preparing the backup at ${DATA}" + timeit "Xtrabackup prepare stage" "$INNOAPPLY" + + if [ $? -ne 0 ]; + then + wsrep_log_error "${INNOBACKUPEX_BIN} apply finished with errors. Check ${DATA}/innobackup.prepare.log" + exit 22 + fi + + if [[ $speciald -eq 1 ]];then + MAGIC_FILE="${TDATA}/${INFO_FILE}" + set +e + rm $TDATA/innobackup.prepare.log $TDATA/innobackup.move.log + set -e + wsrep_log_info "Moving the backup to ${TDATA}" + timeit "Xtrabackup move stage" "$INNOMOVE" + if [[ $? -eq 0 ]];then + 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 ${DATA}/innobackup.move.log for details" + fi + fi + + if [[ $incremental -eq 1 ]];then + wsrep_log_info "Cleaning up ${DATA} after incremental SST" + [[ -d ${DATA} ]] && rm -rf ${DATA} + DATA=$BDATA + fi + + else + 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" + exit 2 + fi + cat "${MAGIC_FILE}" # output UUID:seqno + wsrep_log_info "Total time on joiner: $totime seconds" +fi + +exit 0 diff --git a/scripts/wsrep_sst_xtrabackup-v2.sh b/scripts/wsrep_sst_xtrabackup-v2.sh new file mode 100644 index 00000000000..f4d133d4f8e --- /dev/null +++ b/scripts/wsrep_sst_xtrabackup-v2.sh @@ -0,0 +1,930 @@ +#!/bin/bash -ue +# Copyright (C) 2013 Percona Inc +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1301 USA. + +# Documentation: http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html +# Make sure to read that before proceeding! + + + + +. $(dirname $0)/wsrep_sst_common + +ealgo="" +ekey="" +ekeyfile="" +encrypt=0 +nproc=1 +ecode=0 +XTRABACKUP_PID="" +SST_PORT="" +REMOTEIP="" +tcert="" +tpem="" +tkey="" +sockopt="" +progress="" +ttime=0 +totime=0 +lsn="" +incremental=0 +ecmd="" +rlimit="" +# Initially +stagemsg="${WSREP_SST_OPT_ROLE}" +cpat="" +speciald=0 +ib_home_dir="" +ib_log_dir="" + +sfmt="tar" +strmcmd="" +tfmt="" +tcmd="" +rebuild=0 +rebuildcmd="" +payload=0 +pvformat="-F '%N => Rate:%r Avg:%a Elapsed:%t %e Bytes: %b %p' " +pvopts="-f -i 10 -N $WSREP_SST_OPT_ROLE " +STATDIR="" +uextra=0 +disver="" + +tmpopts="" +itmpdir="" +xtmpdir="" + +scomp="" +sdecomp="" + +if which pv &>/dev/null && pv --help | grep -q FORMAT;then + pvopts+=$pvformat +fi +pcmd="pv $pvopts" +declare -a RC + +INNOBACKUPEX_BIN=innobackupex +readonly AUTH=(${WSREP_SST_OPT_AUTH//:/ }) +DATA="${WSREP_SST_OPT_DATA}" +INFO_FILE="xtrabackup_galera_info" +IST_FILE="xtrabackup_ist" +MAGIC_FILE="${DATA}/${INFO_FILE}" + +# Setting the path for ss and ip +export PATH="/usr/sbin:/sbin:$PATH" + +timeit(){ + local stage=$1 + shift + local cmd="$@" + local x1 x2 took extcode + + if [[ $ttime -eq 1 ]];then + x1=$(date +%s) + wsrep_log_info "Evaluating $cmd" + eval "$cmd" + extcode=$? + x2=$(date +%s) + took=$(( x2-x1 )) + wsrep_log_info "NOTE: $stage took $took seconds" + totime=$(( totime+took )) + else + wsrep_log_info "Evaluating $cmd" + eval "$cmd" + extcode=$? + fi + return $extcode +} + +get_keys() +{ + # $encrypt -eq 1 is for internal purposes only + if [[ $encrypt -ge 2 || $encrypt -eq -1 ]];then + return + fi + + if [[ $encrypt -eq 0 ]];then + if my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -q encrypt;then + wsrep_log_error "Unexpected option combination. SST may fail. Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html " + fi + return + fi + + if [[ $sfmt == 'tar' ]];then + wsrep_log_info "NOTE: Xtrabackup-based encryption - encrypt=1 - cannot be enabled with tar format" + encrypt=-1 + return + fi + + wsrep_log_info "Xtrabackup based encryption enabled in my.cnf - Supported only from Xtrabackup 2.1.4" + + if [[ -z $ealgo ]];then + wsrep_log_error "FATAL: Encryption algorithm empty from my.cnf, bailing out" + exit 3 + fi + + if [[ -z $ekey && ! -r $ekeyfile ]];then + wsrep_log_error "FATAL: Either key or keyfile must be readable" + exit 3 + fi + + if [[ -z $ekey ]];then + ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key-file=$ekeyfile" + else + ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key=$ekey" + fi + + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + ecmd+=" -d" + fi + + stagemsg+="-XB-Encrypted" +} + +get_transfer() +{ + if [[ -z $SST_PORT ]];then + TSST_PORT=4444 + else + TSST_PORT=$SST_PORT + fi + + if [[ $tfmt == 'nc' ]];then + if [[ ! -x `which nc` ]];then + wsrep_log_error "nc(netcat) not found in path: $PATH" + exit 2 + fi + wsrep_log_info "Using netcat as streamer" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + tcmd="nc -dl ${TSST_PORT}" + else + tcmd="nc ${REMOTEIP} ${TSST_PORT}" + fi + else + tfmt='socat' + wsrep_log_info "Using socat as streamer" + if [[ ! -x `which socat` ]];then + wsrep_log_error "socat not found in path: $PATH" + exit 2 + fi + + if [[ $encrypt -eq 2 || $encrypt -eq 3 ]] && ! socat -V | grep -q WITH_OPENSSL;then + wsrep_log_info "NOTE: socat is not openssl enabled, falling back to plain transfer" + encrypt=-1 + fi + + if [[ $encrypt -eq 2 ]];then + wsrep_log_info "Using openssl based encryption with socat: with crt and pem" + if [[ -z $tpem || -z $tcert ]];then + wsrep_log_error "Both PEM and CRT files required" + exit 22 + fi + stagemsg+="-OpenSSL-Encrypted-2" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + wsrep_log_info "Decrypting with PEM $tpem, CA: $tcert" + tcmd="socat -u openssl-listen:${TSST_PORT},reuseaddr,cert=$tpem,cafile=${tcert}${sockopt} stdio" + else + wsrep_log_info "Encrypting with PEM $tpem, CA: $tcert" + tcmd="socat -u stdio openssl-connect:${REMOTEIP}:${TSST_PORT},cert=$tpem,cafile=${tcert}${sockopt}" + fi + elif [[ $encrypt -eq 3 ]];then + wsrep_log_info "Using openssl based encryption with socat: with key and crt" + if [[ -z $tpem || -z $tkey ]];then + wsrep_log_error "Both certificate and key files required" + exit 22 + fi + stagemsg+="-OpenSSL-Encrypted-3" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + wsrep_log_info "Decrypting with certificate $tpem, key $tkey" + tcmd="socat -u openssl-listen:${TSST_PORT},reuseaddr,cert=$tpem,key=${tkey},verify=0${sockopt} stdio" + else + wsrep_log_info "Encrypting with certificate $tpem, key $tkey" + tcmd="socat -u stdio openssl-connect:${REMOTEIP}:${TSST_PORT},cert=$tpem,key=${tkey},verify=0${sockopt}" + 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 + fi + fi + +} + +parse_cnf() +{ + local group=$1 + local var=$2 + reval=$(my_print_defaults -c $WSREP_SST_OPT_CONF $group | awk -F= '{if ($1 ~ /_/) { gsub(/_/,"-",$1); print $1"="$2 } else { print $0 }}' | grep -- "--$var=" | cut -d= -f2-) + if [[ -z $reval ]];then + [[ -n $3 ]] && reval=$3 + fi + echo $reval +} + +get_footprint() +{ + pushd $WSREP_SST_OPT_DATA 1>/dev/null + payload=$(find . -regex '.*\.ibd$\|.*\.MYI$\|.*\.MYD$\|.*ibdata1$' -type f -print0 | xargs -0 du --block-size=1 -c | awk 'END { print $1 }') + if my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -q -- "--compress";then + # QuickLZ has around 50% compression ratio + # When compression/compaction used, the progress is only an approximate. + payload=$(( payload*1/2 )) + fi + popd 1>/dev/null + pcmd+=" -s $payload" + adjust_progress +} + +adjust_progress() +{ + if [[ -n $progress && $progress != '1' ]];then + if [[ -e $progress ]];then + pcmd+=" 2>>$progress" + else + pcmd+=" 2>$progress" + fi + elif [[ -z $progress && -n $rlimit ]];then + # When rlimit is non-zero + pcmd="pv -q" + fi + + if [[ -n $rlimit && "$WSREP_SST_OPT_ROLE" == "donor" ]];then + wsrep_log_info "Rate-limiting SST to $rlimit" + pcmd+=" -L \$rlimit" + fi +} + +read_cnf() +{ + sfmt=$(parse_cnf sst streamfmt "xbstream") + tfmt=$(parse_cnf sst transferfmt "socat") + tcert=$(parse_cnf sst tca "") + tpem=$(parse_cnf sst tcert "") + tkey=$(parse_cnf sst tkey "") + encrypt=$(parse_cnf sst encrypt 0) + sockopt=$(parse_cnf sst sockopt "") + progress=$(parse_cnf sst progress "") + rebuild=$(parse_cnf sst rebuild 0) + ttime=$(parse_cnf sst time 0) + cpat=$(parse_cnf sst cpat '.*galera\.cache$\|.*sst_in_progress$\|.*grastate\.dat$\|.*\.err$\|.*\.log$\|.*RPM_UPGRADE_MARKER$\|.*RPM_UPGRADE_HISTORY$') + incremental=$(parse_cnf sst incremental 0) + ealgo=$(parse_cnf xtrabackup encrypt "") + ekey=$(parse_cnf xtrabackup encrypt-key "") + ekeyfile=$(parse_cnf xtrabackup encrypt-key-file "") + scomp=$(parse_cnf sst compressor "") + sdecomp=$(parse_cnf sst decompressor "") + + + # Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html + if [[ -z $ealgo ]];then + ealgo=$(parse_cnf sst encrypt-algo "") + ekey=$(parse_cnf sst encrypt-key "") + ekeyfile=$(parse_cnf sst encrypt-key-file "") + fi + rlimit=$(parse_cnf sst rlimit "") + uextra=$(parse_cnf sst use-extra 0) + speciald=$(parse_cnf sst sst-special-dirs 1) + iopts=$(parse_cnf sst inno-backup-opts "") + iapts=$(parse_cnf sst inno-apply-opts "") + impts=$(parse_cnf sst inno-move-opts "") + stimeout=$(parse_cnf sst sst-initial-timeout 100) +} + +get_stream() +{ + if [[ $sfmt == 'xbstream' ]];then + wsrep_log_info "Streaming with xbstream" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + strmcmd="xbstream -x" + else + strmcmd="xbstream -c \${INFO_FILE}" + fi + else + sfmt="tar" + wsrep_log_info "Streaming with 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 || $nproc -eq 0 ]] && nproc=1 + set -e +} + +sig_joiner_cleanup() +{ + wsrep_log_error "Removing $MAGIC_FILE file due to signal" + 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" + fi + if [ "${WSREP_SST_OPT_ROLE}" = "joiner" ];then + wsrep_log_info "Removing the sst_in_progress file" + wsrep_cleanup_progress_file + fi + if [[ -n $progress && -p $progress ]];then + wsrep_log_info "Cleaning up fifo file $progress" + rm $progress + fi + if [[ -n ${STATDIR:-} ]];then + [[ -d $STATDIR ]] && rm -rf $STATDIR + fi +} + +check_pid() +{ + local pid_file="$1" + [ -r "$pid_file" ] && ps -p $(cat "$pid_file") >/dev/null 2>&1 +} + +cleanup_donor() +{ + # Since this is invoked just after exit NNN + local estatus=$? + if [[ $estatus -ne 0 ]];then + wsrep_log_error "Cleanup after exit with status:$estatus" + fi + + if [[ -n ${XTRABACKUP_PID:-} ]];then + if check_pid $XTRABACKUP_PID + then + wsrep_log_error "xtrabackup process is still running. Killing... " + kill_xtrabackup + fi + + fi + rm -f ${DATA}/${IST_FILE} || true + + if [[ -n $progress && -p $progress ]];then + wsrep_log_info "Cleaning up fifo file $progress" + rm -f $progress || true + fi + + wsrep_log_info "Cleaning up temporary directories" + + if [[ -n $xtmpdir ]];then + [[ -d $xtmpdir ]] && rm -rf $xtmpdir || true + fi + + if [[ -n $itmpdir ]];then + [[ -d $itmpdir ]] && rm -rf $itmpdir || true + fi +} + +kill_xtrabackup() +{ + local PID=$(cat $XTRABACKUP_PID) + [ -n "$PID" -a "0" != "$PID" ] && kill $PID && (kill $PID && kill -9 $PID) || : + wsrep_log_info "Removing xtrabackup pid file $XTRABACKUP_PID" + rm -f "$XTRABACKUP_PID" || true +} + +setup_ports() +{ + if [[ "$WSREP_SST_OPT_ROLE" == "donor" ]];then + SST_PORT=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $2 }') + REMOTEIP=$(echo $WSREP_SST_OPT_ADDR | awk -F ':' '{ print $1 }') + lsn=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $4 }') + else + SST_PORT=$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $2 }') + fi +} + +# waits ~10 seconds for 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 + ss -p state listening "( sport = :$PORT )" | grep -qE 'socat|nc' && break + sleep 0.2 + done + if [[ $incremental -eq 1 ]];then + echo "ready ${ADDR}/${MODULE}/$lsn" + else + echo "ready ${ADDR}/${MODULE}" + fi +} + +check_extra() +{ + local use_socket=1 + if [[ $uextra -eq 1 ]];then + if my_print_defaults -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--thread-handling=" | grep -q 'pool-of-threads';then + local eport=$(my_print_defaults -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--extra-port=" | cut -d= -f2) + if [[ -n $eport ]];then + # Xtrabackup works only locally. + # Hence, setting host to 127.0.0.1 unconditionally. + wsrep_log_info "SST through extra_port $eport" + INNOEXTRA+=" --host=127.0.0.1 --port=$eport " + use_socket=0 + else + wsrep_log_error "Extra port $eport null, failing" + exit 1 + fi + else + wsrep_log_info "Thread pool not set, ignore the option use_extra" + fi + fi + if [[ $use_socket -eq 1 ]] && [[ -n "${WSREP_SST_OPT_SOCKET}" ]];then + INNOEXTRA+=" --socket=${WSREP_SST_OPT_SOCKET}" + fi +} + +recv_joiner() +{ + local dir=$1 + local msg=$2 + local tmt=$3 + local ltcmd + + pushd ${dir} 1>/dev/null + set +e + + if [[ $tmt -gt 0 && -x `which timeout` ]];then + if timeout --help | grep -q -- '-k';then + ltcmd="timeout -k $(( tmt+10 )) $tmt $tcmd" + else + ltcmd="timeout $tmt $tcmd" + fi + timeit "$msg" "$ltcmd | $strmcmd; RC=( "\${PIPESTATUS[@]}" )" + else + timeit "$msg" "$tcmd | $strmcmd; RC=( "\${PIPESTATUS[@]}" )" + fi + + set -e + popd 1>/dev/null + + if [[ ${RC[0]} -eq 124 ]];then + wsrep_log_error "Possible timeout in receving first data from donor in gtid stage" + exit 32 + fi + + for ecode in "${RC[@]}";do + if [[ $ecode -ne 0 ]];then + wsrep_log_error "Error while getting data from donor node: " \ + "exit codes: ${RC[@]}" + exit 32 + fi + done + + if [ ! -r "${MAGIC_FILE}" ];then + # this message should cause joiner to abort + wsrep_log_error "xtrabackup process ended without creating '${MAGIC_FILE}'" + wsrep_log_info "Contents of datadir" + wsrep_log_info "$(ls -l ${dir}/*)" + exit 32 + fi +} + + +send_donor() +{ + local dir=$1 + local msg=$2 + + pushd ${dir} 1>/dev/null + set +e + timeit "$msg" "$strmcmd | $tcmd; RC=( "\${PIPESTATUS[@]}" )" + set -e + popd 1>/dev/null + + + for ecode in "${RC[@]}";do + if [[ $ecode -ne 0 ]];then + wsrep_log_error "Error while getting data from donor node: " \ + "exit codes: ${RC[@]}" + exit 32 + fi + done + +} + +if [[ ! -x `which $INNOBACKUPEX_BIN` ]];then + wsrep_log_error "innobackupex not in path: $PATH" + exit 2 +fi + +rm -f "${MAGIC_FILE}" + +if [[ ! ${WSREP_SST_OPT_ROLE} == 'joiner' && ! ${WSREP_SST_OPT_ROLE} == 'donor' ]];then + wsrep_log_error "Invalid role ${WSREP_SST_OPT_ROLE}" + exit 22 +fi + +read_cnf +setup_ports +get_stream +get_transfer + +if ${INNOBACKUPEX_BIN} /tmp --help | grep -q -- '--version-check'; then + disver="--no-version-check" +fi + + +INNOEXTRA="" +INNOAPPLY="${INNOBACKUPEX_BIN} $disver $iapts --apply-log \$rebuildcmd \${DATA} &>\${DATA}/innobackup.prepare.log" +INNOMOVE="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} $disver $impts --move-back --force-non-empty-directories \${DATA} &>\${DATA}/innobackup.move.log" +INNOBACKUP="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} $disver $iopts \$tmpopts \$INNOEXTRA --galera-info --stream=\$sfmt \$itmpdir 2>\${DATA}/innobackup.backup.log" + +if [ "$WSREP_SST_OPT_ROLE" = "donor" ] +then + trap cleanup_donor EXIT + + if [ $WSREP_SST_OPT_BYPASS -eq 0 ] + then + + if [[ -z $(parse_cnf mysqld tmpdir "") && -z $(parse_cnf xtrabackup tmpdir "") ]];then + xtmpdir=$(mktemp -d) + tmpopts=" --tmpdir=$xtmpdir " + wsrep_log_info "Using $xtmpdir as xtrabackup temporary directory" + fi + + itmpdir=$(mktemp -d) + wsrep_log_info "Using $itmpdir as innobackupex temporary directory" + + if [ "${AUTH[0]}" != "(null)" ]; then + INNOEXTRA+=" --user=${AUTH[0]}" + fi + + if [ ${#AUTH[*]} -eq 2 ]; then + INNOEXTRA+=" --password=${AUTH[1]}" + elif [ "${AUTH[0]}" != "(null)" ]; then + # Empty password, used for testing, debugging etc. + INNOEXTRA+=" --password=" + fi + + get_keys + if [[ $encrypt -eq 1 ]];then + if [[ -n $ekey ]];then + INNOEXTRA+=" --encrypt=$ealgo --encrypt-key=$ekey " + else + INNOEXTRA+=" --encrypt=$ealgo --encrypt-key-file=$ekeyfile " + fi + fi + + if [[ -n $lsn ]];then + INNOEXTRA+=" --incremental --incremental-lsn=$lsn " + fi + + check_extra + + wsrep_log_info "Streaming GTID file before SST" + + echo "${WSREP_SST_OPT_GTID}" > "${MAGIC_FILE}" + + ttcmd="$tcmd" + + if [[ $encrypt -eq 1 ]];then + if [[ -n $scomp ]];then + tcmd=" $ecmd | $scomp | $tcmd " + else + tcmd=" $ecmd | $tcmd " + fi + elif [[ -n $scomp ]];then + tcmd=" $scomp | $tcmd " + fi + + + send_donor $DATA "${stagemsg}-gtid" + + tcmd="$ttcmd" + if [[ -n $progress ]];then + get_footprint + tcmd="$pcmd | $tcmd" + elif [[ -n $rlimit ]];then + adjust_progress + tcmd="$pcmd | $tcmd" + fi + + wsrep_log_info "Sleeping before data transfer for SST" + sleep 10 + + wsrep_log_info "Streaming the backup to joiner at ${REMOTEIP} ${SST_PORT:-4444}" + + if [[ -n $scomp ]];then + tcmd="$scomp | $tcmd" + fi + + set +e + timeit "${stagemsg}-SST" "$INNOBACKUP | $tcmd; RC=( "\${PIPESTATUS[@]}" )" + set -e + + if [ ${RC[0]} -ne 0 ]; then + wsrep_log_error "${INNOBACKUPEX_BIN} finished with error: ${RC[0]}. " \ + "Check ${DATA}/innobackup.backup.log" + exit 22 + elif [[ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]];then + wsrep_log_error "$tcmd finished with error: ${RC[1]}" + exit 22 + fi + + # innobackupex implicitly writes PID to fixed location in $xtmpdir + XTRABACKUP_PID="$xtmpdir/xtrabackup_pid" + + + else # BYPASS FOR IST + + wsrep_log_info "Bypassing the SST for IST" + echo "continue" # now server can resume updating data + echo "${WSREP_SST_OPT_GTID}" > "${MAGIC_FILE}" + echo "1" > "${DATA}/${IST_FILE}" + get_keys + if [[ $encrypt -eq 1 ]];then + if [[ -n $scomp ]];then + tcmd=" $ecmd | $scomp | $tcmd " + else + tcmd=" $ecmd | $tcmd " + fi + elif [[ -n $scomp ]];then + tcmd=" $scomp | $tcmd " + fi + strmcmd+=" \${IST_FILE}" + + send_donor $DATA "${stagemsg}-IST" + + fi + + echo "done ${WSREP_SST_OPT_GTID}" + wsrep_log_info "Total time on donor: $totime seconds" + +elif [ "${WSREP_SST_OPT_ROLE}" = "joiner" ] +then + [[ -e $SST_PROGRESS_FILE ]] && wsrep_log_info "Stale sst_in_progress file: $SST_PROGRESS_FILE" + [[ -n $SST_PROGRESS_FILE ]] && touch $SST_PROGRESS_FILE + + if [[ $speciald -eq 1 ]];then + ib_home_dir=$(parse_cnf mysqld innodb-data-home-dir "") + ib_log_dir=$(parse_cnf mysqld innodb-log-group-home-dir "") + if [[ -z $ib_home_dir && -z $ib_log_dir ]];then + speciald=0 + fi + fi + + stagemsg="Joiner-Recv" + + if [[ ! -e ${DATA}/ibdata1 ]];then + incremental=0 + fi + + if [[ $incremental -eq 1 ]];then + wsrep_log_info "Incremental SST enabled: NOT SUPPORTED yet" + lsn=$(grep to_lsn xtrabackup_checkpoints | cut -d= -f2 | tr -d ' ') + wsrep_log_info "Recovered LSN: $lsn" + fi + + sencrypted=1 + nthreads=1 + + MODULE="xtrabackup_sst" + + rm -f "${DATA}/${IST_FILE}" + + # May need xtrabackup_checkpoints later on + rm -f ${DATA}/xtrabackup_binary ${DATA}/xtrabackup_galera_info ${DATA}/xtrabackup_logfile + + ADDR=${WSREP_SST_OPT_ADDR} + if [ -z "${SST_PORT}" ] + then + SST_PORT=4444 + ADDR="$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $1 }'):${SST_PORT}" + fi + + wait_for_listen ${SST_PORT} ${ADDR} ${MODULE} & + + trap sig_joiner_cleanup HUP PIPE INT TERM + trap cleanup_joiner EXIT + + if [[ -n $progress ]];then + adjust_progress + tcmd+=" | $pcmd" + fi + + if [[ $incremental -eq 1 ]];then + BDATA=$DATA + DATA=$(mktemp -d) + MAGIC_FILE="${DATA}/${INFO_FILE}" + fi + + get_keys + if [[ $encrypt -eq 1 && $sencrypted -eq 1 ]];then + if [[ -n $sdecomp ]];then + strmcmd=" $sdecomp | $ecmd | $strmcmd" + else + strmcmd=" $ecmd | $strmcmd" + fi + elif [[ -n $sdecomp ]];then + strmcmd=" $sdecomp | $strmcmd" + fi + + STATDIR=$(mktemp -d) + MAGIC_FILE="${STATDIR}/${INFO_FILE}" + recv_joiner $STATDIR "${stagemsg}-gtid" $stimeout + + if ! ps -p ${WSREP_SST_OPT_PARENT} &>/dev/null + then + wsrep_log_error "Parent mysqld process (PID:${WSREP_SST_OPT_PARENT}) terminated unexpectedly." + exit 32 + fi + + if [ ! -r "${STATDIR}/${IST_FILE}" ] + then + wsrep_log_info "Proceeding with SST" + + if [[ $speciald -eq 1 && -d ${DATA}/.sst ]];then + wsrep_log_info "WARNING: Stale temporary SST directory: ${DATA}/.sst from previous SST" + fi + + if [[ $incremental -ne 1 ]];then + if [[ $speciald -eq 1 ]];then + wsrep_log_info "Cleaning the existing datadir and innodb-data/log directories" + find $ib_home_dir $ib_log_dir $DATA -mindepth 1 -regex $cpat -prune -o -exec rm -rfv {} 1>&2 \+ + else + wsrep_log_info "Cleaning the existing datadir" + find $DATA -mindepth 1 -regex $cpat -prune -o -exec rm -rfv {} 1>&2 \+ + fi + tempdir=$(parse_cnf mysqld log-bin "") + if [[ -n ${tempdir:-} ]];then + binlog_dir=$(dirname $tempdir) + binlog_file=$(basename $tempdir) + if [[ -n ${binlog_dir:-} && $binlog_dir != '.' && $binlog_dir != $DATA ]];then + pattern="$binlog_dir/$binlog_file\.[0-9]+$" + wsrep_log_info "Cleaning the binlog directory $binlog_dir as well" + find $binlog_dir -maxdepth 1 -type f -regex $pattern -exec rm -fv {} 1>&2 \+ + rm $binlog_dir/*.index || true + fi + fi + + else + wsrep_log_info "Removing existing ib_logfile files" + rm -f ${BDATA}/ib_logfile* + fi + + + if [[ $speciald -eq 1 ]];then + mkdir -p ${DATA}/.sst + TDATA=${DATA} + DATA="${DATA}/.sst" + fi + + + MAGIC_FILE="${DATA}/${INFO_FILE}" + recv_joiner $DATA "${stagemsg}-SST" 0 + + get_proc + + # Rebuild indexes for compact backups + if grep -q 'compact = 1' ${DATA}/xtrabackup_checkpoints;then + wsrep_log_info "Index compaction detected" + rebuild=1 + fi + + if [[ $rebuild -eq 1 ]];then + nthreads=$(parse_cnf xtrabackup rebuild-threads $nproc) + wsrep_log_info "Rebuilding during prepare with $nthreads threads" + rebuildcmd="--rebuild-indexes --rebuild-threads=$nthreads" + fi + + if test -n "$(find ${DATA} -maxdepth 1 -type f -name '*.qp' -print -quit)";then + + wsrep_log_info "Compressed qpress files found" + + if [[ ! -x `which qpress` ]];then + wsrep_log_error "qpress not found in path: $PATH" + exit 22 + fi + + if [[ -n $progress ]] && pv --help | grep -q 'line-mode';then + count=$(find ${DATA} -type f -name '*.qp' | wc -l) + count=$(( count*2 )) + if pv --help | grep -q FORMAT;then + pvopts="-f -s $count -l -N Decompression -F '%N => Rate:%r Elapsed:%t %e Progress: [%b/$count]'" + else + pvopts="-f -s $count -l -N Decompression" + fi + pcmd="pv $pvopts" + adjust_progress + dcmd="$pcmd | xargs -n 2 qpress -T${nproc}d" + else + dcmd="xargs -n 2 qpress -T${nproc}d" + fi + + + # Decompress the qpress files + wsrep_log_info "Decompression with $nproc threads" + timeit "Joiner-Decompression" "find ${DATA} -type f -name '*.qp' -printf '%p\n%h\n' | $dcmd" + extcode=$? + + if [[ $extcode -eq 0 ]];then + wsrep_log_info "Removing qpress files after decompression" + find ${DATA} -type f -name '*.qp' -delete + if [[ $? -ne 0 ]];then + wsrep_log_error "Something went wrong with deletion of qpress files. Investigate" + fi + else + wsrep_log_error "Decompression failed. Exit code: $extcode" + exit 22 + fi + fi + + + if [[ ! -z $WSREP_SST_OPT_BINLOG ]];then + + BINLOG_DIRNAME=$(dirname $WSREP_SST_OPT_BINLOG) + BINLOG_FILENAME=$(basename $WSREP_SST_OPT_BINLOG) + + # To avoid comparing data directory and BINLOG_DIRNAME + mv $DATA/${BINLOG_FILENAME}.* $BINLOG_DIRNAME/ 2>/dev/null || true + + pushd $BINLOG_DIRNAME &>/dev/null + for bfiles in $(ls -1 ${BINLOG_FILENAME}.*);do + echo ${BINLOG_DIRNAME}/${bfiles} >> ${BINLOG_FILENAME}.index + done + popd &> /dev/null + + fi + + if [[ $incremental -eq 1 ]];then + # Added --ibbackup=xtrabackup_55 because it fails otherwise citing connection issues. + INNOAPPLY="${INNOBACKUPEX_BIN} $disver --defaults-file=${WSREP_SST_OPT_CONF} \ + --ibbackup=xtrabackup_56 --apply-log $rebuildcmd --redo-only $BDATA --incremental-dir=${DATA} &>>${BDATA}/innobackup.prepare.log" + fi + + wsrep_log_info "Preparing the backup at ${DATA}" + timeit "Xtrabackup prepare stage" "$INNOAPPLY" + + if [ $? -ne 0 ]; + then + wsrep_log_error "${INNOBACKUPEX_BIN} apply finished with errors. Check ${DATA}/innobackup.prepare.log" + exit 22 + fi + + if [[ $speciald -eq 1 ]];then + MAGIC_FILE="${TDATA}/${INFO_FILE}" + set +e + rm $TDATA/innobackup.prepare.log $TDATA/innobackup.move.log + set -e + wsrep_log_info "Moving the backup to ${TDATA}" + timeit "Xtrabackup move stage" "$INNOMOVE" + if [[ $? -eq 0 ]];then + 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 ${DATA}/innobackup.move.log for details" + fi + fi + + if [[ $incremental -eq 1 ]];then + wsrep_log_info "Cleaning up ${DATA} after incremental SST" + [[ -d ${DATA} ]] && rm -rf ${DATA} + DATA=$BDATA + fi + + else + 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" + exit 2 + fi + cat "${MAGIC_FILE}" # output UUID:seqno + wsrep_log_info "Total time on joiner: $totime seconds" +fi + +exit 0 diff --git a/scripts/wsrep_sst_xtrabackup.sh b/scripts/wsrep_sst_xtrabackup.sh new file mode 100644 index 00000000000..6b33eabee23 --- /dev/null +++ b/scripts/wsrep_sst_xtrabackup.sh @@ -0,0 +1,715 @@ +#!/bin/bash -ue +# Copyright (C) 2013 Percona Inc +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1301 USA. + +# Optional dependencies and options documented here: http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html +# Make sure to read that before proceeding! + + + + +. $(dirname $0)/wsrep_sst_common + +ealgo="" +ekey="" +ekeyfile="" +encrypt=0 +nproc=1 +ecode=0 +XTRABACKUP_PID="" +SST_PORT="" +REMOTEIP="" +tcert="" +tpem="" +sockopt="" +progress="" +ttime=0 +totime=0 +lsn="" +incremental=0 +ecmd="" +rlimit="" + +sfmt="tar" +strmcmd="" +tfmt="" +tcmd="" +rebuild=0 +rebuildcmd="" +payload=0 +pvformat="-F '%N => Rate:%r Avg:%a Elapsed:%t %e Bytes: %b %p' " +pvopts="-f -i 10 -N $WSREP_SST_OPT_ROLE " +uextra=0 + +if which pv &>/dev/null && pv --help | grep -q FORMAT;then + pvopts+=$pvformat +fi +pcmd="pv $pvopts" +declare -a RC + +INNOBACKUPEX_BIN=innobackupex +readonly AUTH=(${WSREP_SST_OPT_AUTH//:/ }) +DATA="${WSREP_SST_OPT_DATA}" +INFO_FILE="xtrabackup_galera_info" +IST_FILE="xtrabackup_ist" +MAGIC_FILE="${DATA}/${INFO_FILE}" + +# Setting the path for ss and ip +export PATH="/usr/sbin:/sbin:$PATH" + +timeit(){ + local stage=$1 + shift + local cmd="$@" + local x1 x2 took extcode + + if [[ $ttime -eq 1 ]];then + x1=$(date +%s) + wsrep_log_info "Evaluating $cmd" + eval "$cmd" + extcode=$? + x2=$(date +%s) + took=$(( x2-x1 )) + wsrep_log_info "NOTE: $stage took $took seconds" + totime=$(( totime+took )) + else + wsrep_log_info "Evaluating $cmd" + eval "$cmd" + extcode=$? + fi + return $extcode +} + +get_keys() +{ + if [[ $encrypt -eq 2 ]];then + return + fi + + if [[ $encrypt -eq 0 ]];then + if my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -q encrypt;then + wsrep_log_error "Unexpected option combination. SST may fail. Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html " + fi + return + fi + + if [[ $sfmt == 'tar' ]];then + wsrep_log_info "NOTE: Xtrabackup-based encryption - encrypt=1 - cannot be enabled with tar format" + encrypt=0 + return + fi + + wsrep_log_info "Xtrabackup based encryption enabled in my.cnf - Supported only from Xtrabackup 2.1.4" + + if [[ -z $ealgo ]];then + wsrep_log_error "FATAL: Encryption algorithm empty from my.cnf, bailing out" + exit 3 + fi + + if [[ -z $ekey && ! -r $ekeyfile ]];then + wsrep_log_error "FATAL: Either key or keyfile must be readable" + exit 3 + fi + + if [[ -z $ekey ]];then + ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key-file=$ekeyfile" + else + ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key=$ekey" + fi + + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + ecmd+=" -d" + fi +} + +get_transfer() +{ + if [[ -z $SST_PORT ]];then + TSST_PORT=4444 + else + TSST_PORT=$SST_PORT + fi + + if [[ $tfmt == 'nc' ]];then + if [[ ! -x `which nc` ]];then + wsrep_log_error "nc(netcat) not found in path: $PATH" + exit 2 + fi + wsrep_log_info "Using netcat as streamer" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + tcmd="nc -dl ${TSST_PORT}" + else + tcmd="nc ${REMOTEIP} ${TSST_PORT}" + fi + else + tfmt='socat' + wsrep_log_info "Using socat as streamer" + if [[ ! -x `which socat` ]];then + wsrep_log_error "socat not found in path: $PATH" + exit 2 + fi + + if [[ $encrypt -eq 2 ]] && ! socat -V | grep -q OPENSSL;then + wsrep_log_info "NOTE: socat is not openssl enabled, falling back to plain transfer" + encrypt=0 + fi + + if [[ $encrypt -eq 2 ]];then + wsrep_log_info "Using openssl based encryption with socat" + if [[ -z $tpem || -z $tcert ]];then + wsrep_log_error "Both PEM and CRT files required" + exit 22 + fi + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + wsrep_log_info "Decrypting with PEM $tpem, CA: $tcert" + tcmd="socat -u openssl-listen:${TSST_PORT},reuseaddr,cert=$tpem,cafile=${tcert}${sockopt} stdio" + else + wsrep_log_info "Encrypting with PEM $tpem, CA: $tcert" + tcmd="socat -u stdio openssl-connect:${REMOTEIP}:${TSST_PORT},cert=$tpem,cafile=${tcert}${sockopt}" + 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 + fi + fi + +} + +parse_cnf() +{ + local group=$1 + local var=$2 + reval=$(my_print_defaults -c $WSREP_SST_OPT_CONF $group | awk -F= '{if ($1 ~ /_/) { gsub(/_/,"-",$1); print $1"="$2 } else { print $0 }}' | grep -- "--$var=" | cut -d= -f2-) + if [[ -z $reval ]];then + [[ -n $3 ]] && reval=$3 + fi + echo $reval +} + +get_footprint() +{ + pushd $WSREP_SST_OPT_DATA 1>/dev/null + payload=$(find . -regex '.*\.ibd$\|.*\.MYI$\|.*\.MYD$\|.*ibdata1$' -type f -print0 | xargs -0 du --block-size=1 -c | awk 'END { print $1 }') + if my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -q -- "--compress";then + # QuickLZ has around 50% compression ratio + # When compression/compaction used, the progress is only an approximate. + payload=$(( payload*1/2 )) + fi + popd 1>/dev/null + pcmd+=" -s $payload" + adjust_progress +} + +adjust_progress() +{ + if [[ -n $progress && $progress != '1' ]];then + if [[ -e $progress ]];then + pcmd+=" 2>>$progress" + else + pcmd+=" 2>$progress" + fi + elif [[ -z $progress && -n $rlimit ]];then + # When rlimit is non-zero + pcmd="pv -q" + fi + + if [[ -n $rlimit && "$WSREP_SST_OPT_ROLE" == "donor" ]];then + wsrep_log_info "Rate-limiting SST to $rlimit" + pcmd+=" -L \$rlimit" + fi +} + +read_cnf() +{ + sfmt=$(parse_cnf sst streamfmt "tar") + tfmt=$(parse_cnf sst transferfmt "socat") + tcert=$(parse_cnf sst tca "") + tpem=$(parse_cnf sst tcert "") + encrypt=$(parse_cnf sst encrypt 0) + sockopt=$(parse_cnf sst sockopt "") + progress=$(parse_cnf sst progress "") + rebuild=$(parse_cnf sst rebuild 0) + ttime=$(parse_cnf sst time 0) + incremental=$(parse_cnf sst incremental 0) + ealgo=$(parse_cnf xtrabackup encrypt "") + ekey=$(parse_cnf xtrabackup encrypt-key "") + ekeyfile=$(parse_cnf xtrabackup encrypt-key-file "") + + # Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html + if [[ -z $ealgo ]];then + ealgo=$(parse_cnf sst encrypt-algo "") + ekey=$(parse_cnf sst encrypt-key "") + ekeyfile=$(parse_cnf sst encrypt-key-file "") + fi + rlimit=$(parse_cnf sst rlimit "") + uextra=$(parse_cnf sst use_extra 0) +} + +get_stream() +{ + if [[ $sfmt == 'xbstream' ]];then + wsrep_log_info "Streaming with xbstream" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + strmcmd="xbstream -x" + else + strmcmd="xbstream -c \${INFO_FILE} \${IST_FILE}" + fi + else + sfmt="tar" + wsrep_log_info "Streaming with tar" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + strmcmd="tar xfi - --recursive-unlink -h" + else + strmcmd="tar cf - \${INFO_FILE} \${IST_FILE}" + fi + + fi +} + +get_proc() +{ + set +e + nproc=$(grep -c processor /proc/cpuinfo) + [[ -z $nproc || $nproc -eq 0 ]] && nproc=1 + set -e +} + +sig_joiner_cleanup() +{ + wsrep_log_error "Removing $MAGIC_FILE file due to signal" + 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" + fi + if [ "${WSREP_SST_OPT_ROLE}" = "joiner" ];then + wsrep_log_info "Removing the sst_in_progress file" + wsrep_cleanup_progress_file + fi + if [[ -n $progress && -p $progress ]];then + wsrep_log_info "Cleaning up fifo file $progress" + rm $progress + fi +} + +check_pid() +{ + local pid_file="$1" + [ -r "$pid_file" ] && ps -p $(cat "$pid_file") >/dev/null 2>&1 +} + +cleanup_donor() +{ + # Since this is invoked just after exit NNN + local estatus=$? + if [[ $estatus -ne 0 ]];then + wsrep_log_error "Cleanup after exit with status:$estatus" + fi + + if [[ -n $XTRABACKUP_PID ]];then + if check_pid $XTRABACKUP_PID + then + wsrep_log_error "xtrabackup process is still running. Killing... " + kill_xtrabackup + fi + + rm -f $XTRABACKUP_PID + fi + rm -f ${DATA}/${IST_FILE} + + if [[ -n $progress && -p $progress ]];then + wsrep_log_info "Cleaning up fifo file $progress" + rm $progress + fi +} + +kill_xtrabackup() +{ + local PID=$(cat $XTRABACKUP_PID) + [ -n "$PID" -a "0" != "$PID" ] && kill $PID && (kill $PID && kill -9 $PID) || : + rm -f "$XTRABACKUP_PID" +} + +setup_ports() +{ + if [[ "$WSREP_SST_OPT_ROLE" == "donor" ]];then + SST_PORT=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $2 }') + REMOTEIP=$(echo $WSREP_SST_OPT_ADDR | awk -F ':' '{ print $1 }') + lsn=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $4 }') + else + SST_PORT=$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $2 }') + fi +} + +# waits ~10 seconds for 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 + ss -p state listening "( sport = :$PORT )" | grep -qE 'socat|nc' && break + sleep 0.2 + done + if [[ $incremental -eq 1 ]];then + echo "ready ${ADDR}/${MODULE}/$lsn" + else + echo "ready ${ADDR}/${MODULE}" + fi +} + +check_extra() +{ + local use_socket=1 + if [[ $uextra -eq 1 ]];then + if my_print_defaults -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--thread-handling=" | grep -q 'pool-of-threads';then + local eport=$(my_print_defaults -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--extra-port=" | cut -d= -f2) + if [[ -n $eport ]];then + # Xtrabackup works only locally. + # Hence, setting host to 127.0.0.1 unconditionally. + wsrep_log_info "SST through extra_port $eport" + INNOEXTRA+=" --host=127.0.0.1 --port=$eport " + use_socket=0 + else + wsrep_log_error "Extra port $eport null, failing" + exit 1 + fi + else + wsrep_log_info "Thread pool not set, ignore the option use_extra" + fi + fi + if [[ $use_socket -eq 1 ]] && [[ -n "${WSREP_SST_OPT_SOCKET}" ]];then + INNOEXTRA+=" --socket=${WSREP_SST_OPT_SOCKET}" + fi +} + +if [[ ! -x `which innobackupex` ]];then + wsrep_log_error "innobackupex not in path: $PATH" + exit 2 +fi + +rm -f "${MAGIC_FILE}" + +if [[ ! ${WSREP_SST_OPT_ROLE} == 'joiner' && ! ${WSREP_SST_OPT_ROLE} == 'donor' ]];then + wsrep_log_error "Invalid role ${WSREP_SST_OPT_ROLE}" + exit 22 +fi + +read_cnf +setup_ports +get_stream +get_transfer + +INNOEXTRA="" +INNOAPPLY="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} --apply-log \$rebuildcmd \${DATA} &>\${DATA}/innobackup.prepare.log" +INNOBACKUP="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} \$INNOEXTRA --galera-info --stream=\$sfmt \${TMPDIR} 2>\${DATA}/innobackup.backup.log" + +if [ "$WSREP_SST_OPT_ROLE" = "donor" ] +then + trap cleanup_donor EXIT + + if [ $WSREP_SST_OPT_BYPASS -eq 0 ] + then + TMPDIR="${TMPDIR:-/tmp}" + + if [ "${AUTH[0]}" != "(null)" ]; then + INNOEXTRA+=" --user=${AUTH[0]}" + fi + + if [ ${#AUTH[*]} -eq 2 ]; then + INNOEXTRA+=" --password=${AUTH[1]}" + elif [ "${AUTH[0]}" != "(null)" ]; then + # Empty password, used for testing, debugging etc. + INNOEXTRA+=" --password=" + fi + + get_keys + if [[ $encrypt -eq 1 ]];then + if [[ -n $ekey ]];then + INNOEXTRA+=" --encrypt=$ealgo --encrypt-key=$ekey " + else + INNOEXTRA+=" --encrypt=$ealgo --encrypt-key-file=$ekeyfile " + fi + fi + + if [[ -n $lsn ]];then + INNOEXTRA+=" --incremental --incremental-lsn=$lsn " + fi + + check_extra + + wsrep_log_info "Streaming the backup to joiner at ${REMOTEIP} ${SST_PORT}" + + if [[ -n $progress ]];then + get_footprint + tcmd="$pcmd | $tcmd" + elif [[ -n $rlimit ]];then + adjust_progress + tcmd="$pcmd | $tcmd" + fi + + set +e + timeit "Donor-Transfer" "$INNOBACKUP | $tcmd; RC=( "\${PIPESTATUS[@]}" )" + set -e + + if [ ${RC[0]} -ne 0 ]; then + wsrep_log_error "${INNOBACKUPEX_BIN} finished with error: ${RC[0]}. " \ + "Check ${DATA}/innobackup.backup.log" + exit 22 + elif [[ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]];then + wsrep_log_error "$tcmd finished with error: ${RC[1]}" + exit 22 + fi + + # innobackupex implicitly writes PID to fixed location in ${TMPDIR} + XTRABACKUP_PID="${TMPDIR}/xtrabackup_pid" + + + else # BYPASS FOR IST + + wsrep_log_info "Bypassing the SST for IST" + STATE="${WSREP_SST_OPT_GTID}" + echo "continue" # now server can resume updating data + echo "${STATE}" > "${MAGIC_FILE}" + echo "1" > "${DATA}/${IST_FILE}" + get_keys + pushd ${DATA} 1>/dev/null + set +e + if [[ $encrypt -eq 1 ]];then + tcmd=" $ecmd | $tcmd" + fi + timeit "Donor-IST-Unencrypted-transfer" "$strmcmd | $tcmd; RC=( "\${PIPESTATUS[@]}" )" + set -e + popd 1>/dev/null + + for ecode in "${RC[@]}";do + if [[ $ecode -ne 0 ]];then + wsrep_log_error "Error while streaming data to joiner node: " \ + "exit codes: ${RC[@]}" + exit 1 + fi + done + fi + + echo "done ${WSREP_SST_OPT_GTID}" + wsrep_log_info "Total time on donor: $totime seconds" + +elif [ "${WSREP_SST_OPT_ROLE}" = "joiner" ] +then + [[ -e $SST_PROGRESS_FILE ]] && wsrep_log_info "Stale sst_in_progress file: $SST_PROGRESS_FILE" + touch $SST_PROGRESS_FILE + + if [[ ! -e ${DATA}/ibdata1 ]];then + incremental=0 + fi + + if [[ $incremental -eq 1 ]];then + wsrep_log_info "Incremental SST enabled" + #lsn=$(/pxc/bin/mysqld --defaults-file=$WSREP_SST_OPT_CONF --basedir=/pxc --wsrep-recover 2>&1 | grep -o 'log sequence number .*' | cut -d " " -f 4 | head -1) + lsn=$(grep to_lsn xtrabackup_checkpoints | cut -d= -f2 | tr -d ' ') + wsrep_log_info "Recovered LSN: $lsn" + fi + + sencrypted=1 + nthreads=1 + + MODULE="xtrabackup_sst" + + # May need xtrabackup_checkpoints later on + rm -f ${DATA}/xtrabackup_binary ${DATA}/xtrabackup_galera_info ${DATA}/xtrabackup_logfile + + ADDR=${WSREP_SST_OPT_ADDR} + if [ -z "${SST_PORT}" ] + then + SST_PORT=4444 + ADDR="$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $1 }'):${SST_PORT}" + fi + + wait_for_listen ${SST_PORT} ${ADDR} ${MODULE} & + + trap sig_joiner_cleanup HUP PIPE INT TERM + trap cleanup_joiner EXIT + + if [[ -n $progress ]];then + adjust_progress + tcmd+=" | $pcmd" + fi + + if [[ $incremental -eq 1 ]];then + BDATA=$DATA + DATA=$(mktemp -d) + MAGIC_FILE="${DATA}/${INFO_FILE}" + fi + + get_keys + set +e + if [[ $encrypt -eq 1 && $sencrypted -eq 1 ]];then + strmcmd=" $ecmd | $strmcmd" + fi + + pushd ${DATA} 1>/dev/null + timeit "Joiner-Recv-Unencrypted" "$tcmd | $strmcmd; RC=( "\${PIPESTATUS[@]}" )" + popd 1>/dev/null + + set -e + + if [[ $sfmt == 'xbstream' ]];then + # Special handling till lp:1193240 is fixed" + if [[ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]];then + wsrep_log_error "Xbstream failed" + wsrep_log_error "Data directory ${DATA} may not be empty: lp:1193240" \ + "Manual intervention required in that case" + exit 32 + fi + fi + + wait %% # join for wait_for_listen thread + + for ecode in "${RC[@]}";do + if [[ $ecode -ne 0 ]];then + wsrep_log_error "Error while getting data from donor node: " \ + "exit codes: ${RC[@]}" + exit 32 + fi + done + + if [ ! -r "${MAGIC_FILE}" ] + then + # this message should cause joiner to abort + wsrep_log_error "xtrabackup process ended without creating '${MAGIC_FILE}'" + wsrep_log_info "Contents of datadir" + wsrep_log_info "$(ls -l ${DATA}/**/*)" + exit 32 + fi + + if ! ps -p ${WSREP_SST_OPT_PARENT} &>/dev/null + then + wsrep_log_error "Parent mysqld process (PID:${WSREP_SST_OPT_PARENT}) terminated unexpectedly." + exit 32 + fi + + if [ ! -r "${DATA}/${IST_FILE}" ] + then + wsrep_log_info "Proceeding with SST" + wsrep_log_info "Removing existing ib_logfile files" + if [[ $incremental -ne 1 ]];then + rm -f ${DATA}/ib_logfile* + else + rm -f ${BDATA}/ib_logfile* + fi + + get_proc + + # Rebuild indexes for compact backups + if grep -q 'compact = 1' ${DATA}/xtrabackup_checkpoints;then + wsrep_log_info "Index compaction detected" + rebuild=1 + fi + + if [[ $rebuild -eq 1 ]];then + nthreads=$(parse_cnf xtrabackup rebuild-threads $nproc) + wsrep_log_info "Rebuilding during prepare with $nthreads threads" + rebuildcmd="--rebuild-indexes --rebuild-threads=$nthreads" + fi + + if test -n "$(find ${DATA} -maxdepth 1 -type f -name '*.qp' -print -quit)";then + + wsrep_log_info "Compressed qpress files found" + + if [[ ! -x `which qpress` ]];then + wsrep_log_error "qpress not found in path: $PATH" + exit 22 + fi + + if [[ -n $progress ]] && pv --help | grep -q 'line-mode';then + count=$(find ${DATA} -type f -name '*.qp' | wc -l) + count=$(( count*2 )) + if pv --help | grep -q FORMAT;then + pvopts="-f -s $count -l -N Decompression -F '%N => Rate:%r Elapsed:%t %e Progress: [%b/$count]'" + else + pvopts="-f -s $count -l -N Decompression" + fi + pcmd="pv $pvopts" + adjust_progress + dcmd="$pcmd | xargs -n 2 qpress -T${nproc}d" + else + dcmd="xargs -n 2 qpress -T${nproc}d" + fi + + wsrep_log_info "Removing existing ibdata1 file" + rm -f ${DATA}/ibdata1 + + # Decompress the qpress files + wsrep_log_info "Decompression with $nproc threads" + timeit "Decompression" "find ${DATA} -type f -name '*.qp' -printf '%p\n%h\n' | $dcmd" + extcode=$? + + if [[ $extcode -eq 0 ]];then + wsrep_log_info "Removing qpress files after decompression" + find ${DATA} -type f -name '*.qp' -delete + if [[ $? -ne 0 ]];then + wsrep_log_error "Something went wrong with deletion of qpress files. Investigate" + fi + else + wsrep_log_error "Decompression failed. Exit code: $extcode" + exit 22 + fi + fi + + if [[ $incremental -eq 1 ]];then + # Added --ibbackup=xtrabackup_55 because it fails otherwise citing connection issues. + INNOAPPLY="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} \ + --ibbackup=xtrabackup_55 --apply-log $rebuildcmd --redo-only $BDATA --incremental-dir=${DATA} &>>${BDATA}/innobackup.prepare.log" + fi + + wsrep_log_info "Preparing the backup at ${DATA}" + timeit "Xtrabackup prepare stage" "$INNOAPPLY" + + if [[ $incremental -eq 1 ]];then + wsrep_log_info "Cleaning up ${DATA} after incremental SST" + [[ -d ${DATA} ]] && rm -rf ${DATA} + DATA=$BDATA + fi + + if [ $? -ne 0 ]; + then + wsrep_log_error "${INNOBACKUPEX_BIN} finished with errors. Check ${DATA}/innobackup.prepare.log" + exit 22 + fi + else + 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" + exit 2 + fi + + cat "${MAGIC_FILE}" # output UUID:seqno + wsrep_log_info "Total time on joiner: $totime seconds" +fi + +exit 0 diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 1eb8dc7cdd6..803e14988d2 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -13,6 +13,25 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +IF(WITH_WSREP AND NOT EMBEDDED_LIBRARY) + BUILD_WITH_WSREP() + SET(WSREP_INCLUDES ${CMAKE_SOURCE_DIR}/wsrep) + SET(WSREP_SOURCES + wsrep_check_opts.cc + wsrep_hton.cc + wsrep_mysqld.cc + wsrep_notify.cc + wsrep_sst.cc + wsrep_utils.cc + wsrep_var.cc + wsrep_binlog.cc + wsrep_applier.cc + wsrep_thd.cc + ) + SET(WSREP_LIB wsrep) +ENDIF() + INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/sql @@ -20,6 +39,7 @@ ${PCRE_INCLUDES} ${ZLIB_INCLUDE_DIR} ${SSL_INCLUDE_DIRS} ${CMAKE_BINARY_DIR}/sql +${WSREP_INCLUDES} ) SET(GEN_SOURCES @@ -91,6 +111,7 @@ SET (SQL_SOURCE ../sql-common/mysql_async.c my_apc.cc my_apc.h rpl_gtid.cc rpl_parallel.cc + ${WSREP_SOURCES} table_cache.cc ${CMAKE_CURRENT_BINARY_DIR}/sql_builtin.cc ${GEN_SOURCES} @@ -112,6 +133,7 @@ DTRACE_INSTRUMENT(sql) TARGET_LINK_LIBRARIES(sql ${MYSQLD_STATIC_PLUGIN_LIBS} mysys mysys_ssl dbug strings vio pcre ${LIBJEMALLOC} ${LIBWRAP} ${LIBCRYPT} ${LIBDL} ${CMAKE_THREAD_LIBS_INIT} + ${WSREP_LIB} ${SSL_LIBRARIES}) IF(WIN32) diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc index d65180a60be..8f00ace7124 100644 --- a/sql/event_data_objects.cc +++ b/sql/event_data_objects.cc @@ -1472,8 +1472,24 @@ end: bool save_tx_read_only= thd->tx_read_only; thd->tx_read_only= false; +#ifdef WITH_WSREP + if (WSREP(thd)) { + // sql_print_information("sizeof(LEX) = %d", sizeof(struct LEX)); + // sizeof(LEX) = 4512, so it's relatively safe to allocate it on stack. + LEX *old_lex= thd->lex, new_lex; + new_lex.sql_command= SQLCOM_DROP_EVENT; + thd->lex= &new_lex; + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); + thd->lex= old_lex; + } +#endif + ret= Events::drop_event(thd, dbname, name, FALSE); +#ifdef WITH_WSREP + WSREP_TO_ISOLATION_END; + error: +#endif thd->tx_read_only= save_tx_read_only; thd->security_ctx->master_access= saved_master_access; } diff --git a/sql/events.cc b/sql/events.cc index 63627b21777..a14f1a6c384 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -1128,7 +1128,20 @@ Events::load_events_from_db(THD *thd) delete et; goto end; } - +#ifdef WITH_WSREP + // when SST from master node who initials event, the event status is ENABLED + // this is problematic because there are two nodes with same events and both enabled. + if (et->originator != thd->variables.server_id) + { + store_record(table, record[1]); + table->field[ET_FIELD_STATUS]-> + store((longlong) Event_parse_data::SLAVESIDE_DISABLED, + TRUE); + (void) table->file->ha_update_row(table->record[1], table->record[0]); + delete et; + continue; + } +#endif /** Since the Event_queue_element object could be deleted inside Event_queue::create_event we should save the value of dropped flag @@ -1174,6 +1187,46 @@ end: DBUG_RETURN(ret); } +#ifdef WITH_WSREP +int wsrep_create_event_query(THD *thd, uchar** buf, size_t* buf_len) +{ + String log_query; + + if (create_query_string(thd, &log_query)) + { + WSREP_WARN("events create string failed: %s", thd->query()); + return 1; + } + return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(), buf, buf_len); +} +static int +wsrep_alter_query_string(THD *thd, String *buf) +{ + /* Append the "ALTER" part of the query */ + if (buf->append(STRING_WITH_LEN("ALTER "))) + return 1; + /* Append definer */ + append_definer(thd, buf, &(thd->lex->definer->user), &(thd->lex->definer->host)); + /* Append the left part of thd->query after event name part */ + if (buf->append(thd->lex->stmt_definition_begin, + thd->lex->stmt_definition_end - + thd->lex->stmt_definition_begin)) + return 1; + + return 0; +} +int wsrep_alter_event_query(THD *thd, uchar** buf, size_t* buf_len) +{ + String log_query; + + if (wsrep_alter_query_string(thd, &log_query)) + { + WSREP_WARN("events alter string failed: %s", thd->query()); + return 1; + } + return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(), buf, buf_len); +} +#endif /* WITH_WSREP */ /** @} (End of group Event_Scheduler) */ diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index f503b2f54e5..3ddd668fd12 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -386,7 +386,13 @@ const char *ha_partition::table_type() const // we can do this since we only support a single engine type return m_file[0]->table_type(); } - +#if defined(WITH_WSREP) && !defined(EMBEDDED_LIBRARY) +int ha_partition::wsrep_db_type() const +{ + // we can do this since we only support a single engine type + return ha_legacy_type(m_file[0]->ht); +} +#endif /* WITH_WSREP && !EMBEDDED_LIBRARY */ /* Destructor method diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 71ae84b06a0..c3c72394374 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -1282,7 +1282,9 @@ public: DBUG_ASSERT(h == m_file[i]->ht); return h; } - +#if defined(WITH_WSREP) && !defined(EMBEDDED_LIBRARY) + virtual int wsrep_db_type() const; +#endif /* WITH_WSREP && !EMBEDDED_LIBRARY */ friend int cmp_key_rowid_part_id(void *ptr, uchar *ref1, uchar *ref2); }; diff --git a/sql/handler.cc b/sql/handler.cc index 56e7da6430d..2b91428460b 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -50,6 +50,9 @@ #include "../storage/maria/ha_maria.h" #endif +#ifdef WITH_WSREP +#include "wsrep_mysqld.h" +#endif /* While we have legacy_db_type, we have this array to check for dups and to find handlerton from legacy_db_type. @@ -1165,10 +1168,27 @@ int ha_prepare(THD *thd) { if ((err= ht->prepare(ht, thd, all))) { +#ifdef WITH_WSREP + if (WSREP(thd) && ht->db_type== DB_TYPE_WSREP) + { + error= 1; + /* avoid sending error, if we need to replay */ + if (thd->wsrep_conflict_state!= MUST_REPLAY) + { + my_error(ER_LOCK_DEADLOCK, MYF(0), err); + } + } + else + { + /* not wsrep hton, bail to native mysql behavior */ +#endif my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); ha_rollback_trans(thd, all); error=1; break; +#ifdef WITH_WSREP + } +#endif } } else @@ -1366,7 +1386,12 @@ int ha_commit_trans(THD *thd, bool all) mdl_request.init(MDL_key::COMMIT, "", "", MDL_INTENTION_EXCLUSIVE, MDL_EXPLICIT); +#ifdef WITH_WSREP + if (!WSREP(thd) && + thd->mdl_context.acquire_lock(&mdl_request, +#else if (thd->mdl_context.acquire_lock(&mdl_request, +#endif /* WITH_WSREP */ thd->variables.lock_wait_timeout)) { ha_rollback_trans(thd, all); @@ -1414,7 +1439,33 @@ int ha_commit_trans(THD *thd, bool all) err= ht->prepare(ht, thd, all); status_var_increment(thd->status_var.ha_prepare_count); if (err) - my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); +#ifdef WITH_WSREP + { + if (WSREP(thd) && ht->db_type== DB_TYPE_WSREP) + { + error= 1; + switch (err) + { + case WSREP_TRX_SIZE_EXCEEDED: + /* give user size exeeded erro from wsrep_api.h */ + my_error(ER_ERROR_DURING_COMMIT, MYF(0), WSREP_SIZE_EXCEEDED); + break; + case WSREP_TRX_CERT_FAIL: + case WSREP_TRX_ERROR: + /* avoid sending error, if we need to replay */ + if (thd->wsrep_conflict_state!= MUST_REPLAY) + { + my_error(ER_LOCK_DEADLOCK, MYF(0), err); + } + } + } + else + /* not wsrep hton, bail to native mysql behavior */ +#endif /* WITH_WSREP */ + my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); +#ifdef WITH_WSREP + } +#endif /* WITH_WSREP */ if (err) goto err; @@ -1425,6 +1476,13 @@ int ha_commit_trans(THD *thd, bool all) DEBUG_SYNC(thd, "ha_commit_trans_after_prepare"); DBUG_EXECUTE_IF("crash_commit_after_prepare", DBUG_SUICIDE();); +#ifdef WITH_WSREP + if (!error && wsrep_is_wsrep_xid(&thd->transaction.xid_state.xid)) + { + // xid was rewritten by wsrep + xid= wsrep_xid_seqno(&thd->transaction.xid_state.xid); + } +#endif // WITH_WSREP if (!is_real_trans) { error= commit_one_phase_2(thd, all, trans, is_real_trans); @@ -1801,7 +1859,13 @@ static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin, got, hton_name(hton)->str); for (int i=0; i < got; i ++) { +#ifdef WITH_WSREP + my_xid x=(wsrep_is_wsrep_xid(&info->list[i]) ? + wsrep_xid_seqno(&info->list[i]) : + info->list[i].get_my_xid()); +#else my_xid x=info->list[i].get_my_xid(); +#endif /* WITH_WSREP */ if (!x) // not "mine" - that is generated by external TM { #ifndef DBUG_OFF @@ -3086,7 +3150,12 @@ int handler::update_auto_increment() variables->auto_increment_increment); auto_inc_intervals_count++; /* Row-based replication does not need to store intervals in binlog */ +#ifdef WITH_WSREP + if (((WSREP(thd) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()) && + !thd->is_current_stmt_binlog_format_row()) +#else if (mysql_bin_log.is_open() && !thd->is_current_stmt_binlog_format_row()) +#endif /* WITH_WSREP */ thd->auto_inc_intervals_in_cur_stmt_for_binlog.append(auto_inc_interval_for_cur_row.minimum(), auto_inc_interval_for_cur_row.values(), variables->auto_increment_increment); @@ -5707,7 +5776,13 @@ static bool check_table_binlog_row_based(THD *thd, TABLE *table) return (thd->is_current_stmt_binlog_format_row() && table->s->cached_row_logging_check && (thd->variables.option_bits & OPTION_BIN_LOG) && +#ifdef WITH_WSREP + /* applier and replayer should not binlog */ + ((WSREP_EMULATE_BINLOG(thd) && (thd->wsrep_exec_mode != REPL_RECV)) || + mysql_bin_log.is_open())); +#else mysql_bin_log.is_open()); +#endif } @@ -5807,6 +5882,17 @@ static int binlog_log_row(TABLE* table, bool error= 0; THD *const thd= table->in_use; +#ifdef WITH_WSREP + /* only InnoDB tables will be replicated through binlog emulation */ + if (WSREP_EMULATE_BINLOG(thd) && + table->file->ht->db_type != DB_TYPE_INNODB && + !(table->file->ht->db_type == DB_TYPE_PARTITION_DB && + (((ha_partition*)(table->file))->wsrep_db_type() == DB_TYPE_INNODB))) + // !strcmp(table->file->table_type(), "InnoDB")) + { + return 0; + } +#endif /* WITH_WSREP */ if (check_table_binlog_row_based(thd, table)) { MY_BITMAP cols; @@ -6136,6 +6222,64 @@ void handler::set_lock_type(enum thr_lock_type lock) table->reginfo.lock_type= lock; } +#ifdef WITH_WSREP +/** + @details + This function makes the storage engine to force the victim transaction + to abort. Currently, only innodb has this functionality, but any SE + implementing the wsrep API should provide this service to support + multi-master operation. + + @param bf_thd brute force THD asking for the abort + @param victim_thd victim THD to be aborted + + @return + always 0 +*/ + +int ha_wsrep_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal) +{ + DBUG_ENTER("ha_wsrep_abort_transaction"); + if (!WSREP(bf_thd) && + !(wsrep_OSU_method_options == WSREP_OSU_RSU && + bf_thd->wsrep_exec_mode == TOTAL_ORDER)) { + DBUG_RETURN(0); + } + + handlerton *hton= installed_htons[DB_TYPE_INNODB]; + if (hton && hton->wsrep_abort_transaction) + { + hton->wsrep_abort_transaction(hton, bf_thd, victim_thd, signal); + } + else + { + WSREP_WARN("cannot abort InnoDB transaction"); + } + + DBUG_RETURN(0); +} + +void ha_wsrep_fake_trx_id(THD *thd) +{ + DBUG_ENTER("ha_wsrep_fake_trx_id"); + if (!WSREP(thd)) + { + DBUG_VOID_RETURN; + } + + handlerton *hton= installed_htons[DB_TYPE_INNODB]; + if (hton && hton->wsrep_fake_trx_id) + { + hton->wsrep_fake_trx_id(hton, thd); + } + else + { + WSREP_WARN("cannot get fake InnoDB transaction ID"); + } + + DBUG_VOID_RETURN; +} +#endif /* WITH_WSREP */ #ifdef TRANS_LOG_MGM_EXAMPLE_CODE /* Example of transaction log management functions based on assumption that logs diff --git a/sql/handler.h b/sql/handler.h index 1e4fe5557b6..15382b5979b 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -439,6 +439,7 @@ enum legacy_db_type DB_TYPE_BINLOG=21, DB_TYPE_PBXT=23, DB_TYPE_PERFORMANCE_SCHEMA=28, + DB_TYPE_WSREP=41, DB_TYPE_ARIA=42, DB_TYPE_TOKUDB=43, DB_TYPE_FIRST_DYNAMIC=44, @@ -1230,6 +1231,13 @@ struct handlerton enum handler_create_iterator_result (*create_iterator)(handlerton *hton, enum handler_iterator_type type, struct handler_iterator *fill_this_in); +#ifdef WITH_WSREP + int (*wsrep_abort_transaction)(handlerton *hton, THD *bf_thd, + THD *victim_thd, my_bool signal); + int (*wsrep_set_checkpoint)(handlerton *hton, const XID* xid); + int (*wsrep_get_checkpoint)(handlerton *hton, XID* xid); + void (*wsrep_fake_trx_id)(handlerton *hton, THD *thd); +#endif /* WITH_WSREP */ /* Optional clauses in the CREATE/ALTER TABLE */ @@ -3962,6 +3970,9 @@ bool key_uses_partial_cols(TABLE_SHARE *table, uint keyno); extern const char *ha_row_type[]; extern MYSQL_PLUGIN_IMPORT const char *tx_isolation_names[]; extern MYSQL_PLUGIN_IMPORT const char *binlog_format_names[]; +#ifdef WITH_WSREP +extern MYSQL_PLUGIN_IMPORT const char *wsrep_binlog_format_names[]; +#endif /* WITH_WSREP */ extern TYPELIB tx_isolation_typelib; extern const char *myisam_stats_method_names[]; extern ulong total_ha, total_ha_2pc; @@ -4080,6 +4091,10 @@ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv); bool ha_rollback_to_savepoint_can_release_mdl(THD *thd); int ha_savepoint(THD *thd, SAVEPOINT *sv); int ha_release_savepoint(THD *thd, SAVEPOINT *sv); +#ifdef WITH_WSREP +int ha_wsrep_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal); +void ha_wsrep_fake_trx_id(THD *thd); +#endif /* WITH_WSREP */ /* these are called by storage engines */ void trans_register_ha(THD *thd, bool all, handlerton *ht); @@ -4110,6 +4125,9 @@ int ha_binlog_end(THD *thd); #define ha_binlog_wait(a) do {} while (0) #define ha_binlog_end(a) do {} while (0) #endif +#ifdef WITH_WSREP +void wsrep_brute_force_aborts(); +#endif const char *get_canonical_filename(handler *file, const char *path, char *tmp_path); diff --git a/sql/lock.cc b/sql/lock.cc index 54c7720e750..7d2cddc9b78 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -84,6 +84,10 @@ #include #include +#ifdef WITH_WSREP +#include "wsrep_mysqld.h" +#endif /* WITH_WSREP */ + /** @defgroup Locking Locking @{ @@ -314,6 +318,10 @@ bool mysql_lock_tables(THD *thd, MYSQL_LOCK *sql_lock, uint flags) /* Copy the lock data array. thr_multi_lock() reorders its contents. */ memmove(sql_lock->locks + sql_lock->lock_count, sql_lock->locks, sql_lock->lock_count * sizeof(*sql_lock->locks)); +#ifdef WITH_WSREP + thd->lock_info.in_lock_tables= thd->in_lock_tables; +#endif + /* Lock on the copied half of the lock data array. */ rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks + sql_lock->lock_count, @@ -324,6 +332,11 @@ bool mysql_lock_tables(THD *thd, MYSQL_LOCK *sql_lock, uint flags) end: THD_STAGE_INFO(thd, stage_after_table_lock); +#ifdef WITH_WSREP + thd_proc_info(thd, "mysql_lock_tables(): unlocking tables II"); +#else /* WITH_WSREP */ + thd_proc_info(thd, 0); +#endif /* WITH_WSREP */ if (thd->killed) { @@ -336,6 +349,9 @@ end: my_error(rc, MYF(0)); thd->set_time_after_lock(); +#ifdef WITH_WSREP + thd_proc_info(thd, "exit mysqld_lock_tables()"); +#endif /* WITH_WSREP */ DBUG_RETURN(rc); } @@ -1052,6 +1068,10 @@ void Global_read_lock::unlock_global_read_lock(THD *thd) { thd->mdl_context.release_lock(m_mdl_blocks_commits_lock); m_mdl_blocks_commits_lock= NULL; +#ifdef WITH_WSREP + wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED; + wsrep->resume(wsrep); +#endif /* WITH_WSREP */ } thd->mdl_context.release_lock(m_mdl_global_shared_lock); m_mdl_global_shared_lock= NULL; @@ -1084,6 +1104,20 @@ bool Global_read_lock::make_global_read_lock_block_commit(THD *thd) If we didn't succeed lock_global_read_lock(), or if we already suceeded make_global_read_lock_block_commit(), do nothing. */ + +#ifdef WITH_WSREP + if (m_mdl_blocks_commits_lock) + { + WSREP_DEBUG("GRL was in block commit mode when entering " + "make_global_read_lock_block_commit"); + thd->mdl_context.release_lock(m_mdl_blocks_commits_lock); + m_mdl_blocks_commits_lock= NULL; + wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED; + wsrep->resume(wsrep); + m_state= GRL_ACQUIRED; + } +#endif /* WITH_WSREP */ + if (m_state != GRL_ACQUIRED) DBUG_RETURN(0); @@ -1096,6 +1130,22 @@ bool Global_read_lock::make_global_read_lock_block_commit(THD *thd) m_mdl_blocks_commits_lock= mdl_request.ticket; m_state= GRL_ACQUIRED_AND_BLOCKS_COMMIT; +#ifdef WITH_WSREP + long long ret = wsrep->pause(wsrep); + if (ret >= 0) + { + wsrep_locked_seqno= ret; + } + else if (ret != -ENOSYS) /* -ENOSYS - no provider */ + { + WSREP_ERROR("Failed to pause provider: %lld (%s)", -ret, strerror(-ret)); + + /* m_mdl_blocks_commits_lock is always NULL here */ + wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED; + my_error(ER_LOCK_DEADLOCK, MYF(0)); + DBUG_RETURN(TRUE); + } +#endif /* WITH_WSREP */ DBUG_RETURN(FALSE); } diff --git a/sql/log.cc b/sql/log.cc index 75a895e25f8..35bb0ffa0c9 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -52,6 +52,9 @@ #include "sql_plugin.h" #include "rpl_handler.h" +#ifdef WITH_WSREP +#include "wsrep_mysqld.h" +#endif /* WITH_WSREP */ #include "debug_sync.h" #include "sql_show.h" #include "my_pthread.h" @@ -512,6 +515,9 @@ private: }; handlerton *binlog_hton; +#ifdef WITH_WSREP +extern handlerton *wsrep_hton; +#endif bool LOGGER::is_log_table_enabled(uint log_table_type) { @@ -526,6 +532,128 @@ bool LOGGER::is_log_table_enabled(uint log_table_type) } } +#ifdef WITH_WSREP +IO_CACHE * get_trans_log(THD * thd) +{ + binlog_cache_mngr *cache_mngr = (binlog_cache_mngr*) + thd_get_ha_data(thd, binlog_hton); + if (cache_mngr) + { + return cache_mngr->get_binlog_cache_log(true); + } + else + { + WSREP_DEBUG("binlog cache not initialized, conn :%ld", thd->thread_id); + return NULL; + } +} + + +bool wsrep_trans_cache_is_empty(THD *thd) +{ + binlog_cache_mngr *const cache_mngr= + (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); + return (!cache_mngr || cache_mngr->trx_cache.empty()); +} + +void thd_binlog_flush_pending_rows_event(THD *thd, bool stmt_end) +{ + thd->binlog_flush_pending_rows_event(stmt_end); +} +void thd_binlog_trx_reset(THD * thd) +{ + /* + todo: fix autocommit select to not call the caller + */ + if (thd_get_ha_data(thd, binlog_hton) != NULL) + { + binlog_cache_mngr *const cache_mngr= + (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); + if (cache_mngr) cache_mngr->reset(false, true); + } + thd->clear_binlog_table_maps(); +} + +void thd_binlog_rollback_stmt(THD * thd) +{ + WSREP_DEBUG("thd_binlog_rollback_stmt :%ld", thd->thread_id); + binlog_cache_mngr *const cache_mngr= + (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); + if (cache_mngr) cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF); +} + +#ifdef REMOVED +/* + Write the contents of a cache to memory buffer. + + This function quite the same as MYSQL_BIN_LOG::write_cache(), + with the exception that here we write in buffer instead of log file. + */ + +int wsrep_write_cache(IO_CACHE *cache, uchar **buf, int *buf_len) +{ + + if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0)) + return ER_ERROR_ON_WRITE; + uint length= my_b_bytes_in_cache(cache); + long long total_length = 0; + uchar *buf_ptr = NULL; + + do + { + /* bail out if buffer grows too large + This is a temporary fix to avoid flooding replication + TODO: remove this check for 0.7.4 release + */ + if (total_length > wsrep_max_ws_size) + { + WSREP_WARN("transaction size limit (%lld) exceeded: %lld", + wsrep_max_ws_size, total_length); + if (reinit_io_cache(cache, WRITE_CACHE, 0, 0, 0)) + { + WSREP_WARN("failed to initialize io-cache"); + } + if (buf_ptr) my_free(*buf); + *buf_len = 0; + return ER_ERROR_ON_WRITE; + } + if (total_length > 0) + { + *buf_len += length; + *buf = (uchar *)my_realloc(*buf, total_length+length, + MYF(MY_ALLOW_ZERO_PTR)); + if (!*buf) + { + WSREP_ERROR("io cache write problem: %d %d", *buf_len, length); + return ER_ERROR_ON_WRITE; + } + buf_ptr = *buf+total_length; + } + else + { + if (buf_ptr != NULL) + { + WSREP_ERROR("io cache alloc error: %d %d", *buf_len, length); + my_free(*buf); + } + if (length > 0) + { + *buf = (uchar *) my_malloc(length, MYF(0)); + buf_ptr = *buf; + *buf_len = length; + } + } + total_length += length; + + memcpy(buf_ptr, cache->read_pos, length); + cache->read_pos=cache->read_end; + } while ((cache->file >= 0) && (length= my_b_fill(cache))); + + return 0; +} +#endif /* REMOVED */ +#endif + /** Check if a given table is opened log table @@ -1577,7 +1705,11 @@ binlog_trans_log_savepos(THD *thd, my_off_t *pos) DBUG_ENTER("binlog_trans_log_savepos"); DBUG_ASSERT(pos != NULL); binlog_cache_mngr *const cache_mngr= thd->binlog_setup_trx_data(); +#ifdef WITH_WSREP + DBUG_ASSERT((WSREP(thd) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()); +#else DBUG_ASSERT(mysql_bin_log.is_open()); +#endif *pos= cache_mngr->trx_cache.get_byte_position(); DBUG_PRINT("return", ("*pos: %lu", (ulong) *pos)); DBUG_VOID_RETURN; @@ -1625,7 +1757,16 @@ binlog_trans_log_truncate(THD *thd, my_off_t pos) int binlog_init(void *p) { binlog_hton= (handlerton *)p; +#ifdef WITH_WSREP + if (WSREP_ON) + binlog_hton->state= SHOW_OPTION_YES; + else + { +#endif /* WITH_WSREP */ binlog_hton->state=opt_bin_log ? SHOW_OPTION_YES : SHOW_OPTION_NO; +#ifdef WITH_WSREP + } +#endif /* WITH_WSREP */ binlog_hton->db_type=DB_TYPE_BINLOG; binlog_hton->savepoint_offset= sizeof(my_off_t); binlog_hton->close_connection= binlog_close_connection; @@ -1745,6 +1886,14 @@ binlog_commit_flush_stmt_cache(THD *thd, bool all, binlog_cache_mngr *cache_mngr) { DBUG_ENTER("binlog_commit_flush_stmt_cache"); +#ifdef WITH_WSREP + if (thd->wsrep_mysql_replicated > 0) + { + WSREP_DEBUG("avoiding binlog_commit_flush_trx_cache: %d", thd->wsrep_mysql_replicated); + return 0; + } +#endif + Query_log_event end_evt(thd, STRING_WITH_LEN("COMMIT"), FALSE, TRUE, TRUE, 0); DBUG_RETURN(binlog_flush_cache(thd, cache_mngr, &end_evt, all, TRUE, FALSE)); @@ -1900,12 +2049,12 @@ static bool trans_cannot_safely_rollback(THD *thd, bool all) return ((thd->variables.option_bits & OPTION_KEEP_LOG) || (trans_has_updated_non_trans_table(thd) && - thd->variables.binlog_format == BINLOG_FORMAT_STMT) || + WSREP_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_STMT) || (cache_mngr->trx_cache.changes_to_non_trans_temp_table() && - thd->variables.binlog_format == BINLOG_FORMAT_MIXED) || + WSREP_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_MIXED) || (trans_has_updated_non_trans_table(thd) && ending_single_stmt_trans(thd,all) && - thd->variables.binlog_format == BINLOG_FORMAT_MIXED)); + WSREP_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_MIXED)); } @@ -1927,6 +2076,9 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all) DBUG_ENTER("binlog_commit"); binlog_cache_mngr *const cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); +#ifdef WITH_WSREP + if (!cache_mngr) DBUG_RETURN(0); +#endif /* WITH_WSREP */ DBUG_PRINT("debug", ("all: %d, in_transaction: %s, all.modified_non_trans_table: %s, stmt.modified_non_trans_table: %s", @@ -1983,6 +2135,9 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) int error= 0; binlog_cache_mngr *const cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); +#ifdef WITH_WSREP + if (!cache_mngr) DBUG_RETURN(0); +#endif /* WITH_WSREP */ DBUG_PRINT("debug", ("all: %s, all.modified_non_trans_table: %s, stmt.modified_non_trans_table: %s", YESNO(all), @@ -2011,8 +2166,12 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) cache_mngr->reset(false, true); DBUG_RETURN(error); } - +#ifdef WITH_WSREP + if (!wsrep_emulate_bin_log && + mysql_bin_log.check_write_error(thd)) +#else if (mysql_bin_log.check_write_error(thd)) +#endif { /* "all == true" means that a "rollback statement" triggered the error and @@ -2043,9 +2202,9 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) else if (ending_trans(thd, all) || (!(thd->variables.option_bits & OPTION_KEEP_LOG) && (!stmt_has_updated_non_trans_table(thd) || - thd->variables.binlog_format != BINLOG_FORMAT_STMT) && + WSREP_FORMAT(thd->variables.binlog_format) != BINLOG_FORMAT_STMT) && (!cache_mngr->trx_cache.changes_to_non_trans_temp_table() || - thd->variables.binlog_format != BINLOG_FORMAT_MIXED))) + WSREP_FORMAT(thd->variables.binlog_format) != BINLOG_FORMAT_MIXED))) error= binlog_truncate_trx_cache(thd, cache_mngr, all); } @@ -2154,6 +2313,9 @@ static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv) int error= 1; char buf[1024]; +#ifdef WITH_WSREP + if (wsrep_emulate_bin_log) DBUG_RETURN(0); +#endif /* WITH_WSREP */ String log_query(buf, sizeof(buf), &my_charset_bin); if (log_query.copy(STRING_WITH_LEN("SAVEPOINT "), &my_charset_bin) || append_identifier(thd, &log_query, @@ -2190,8 +2352,14 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) non-transactional table. Otherwise, truncate the binlog cache starting from the SAVEPOINT command. */ +#ifdef WITH_WSREP + if (!wsrep_emulate_bin_log && + unlikely(trans_has_updated_non_trans_table(thd) || + (thd->variables.option_bits & OPTION_KEEP_LOG))) +#else if (unlikely(trans_has_updated_non_trans_table(thd) || (thd->variables.option_bits & OPTION_KEEP_LOG))) +#endif { char buf[1024]; String log_query(buf, sizeof(buf), &my_charset_bin); @@ -2204,7 +2372,12 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) TRUE, FALSE, TRUE, errcode); DBUG_RETURN(mysql_bin_log.write(&qinfo)); } - binlog_trans_log_truncate(thd, *(my_off_t*)sv); + +#ifdef WITH_WSREP + if (!wsrep_emulate_bin_log) +#endif + binlog_trans_log_truncate(thd, *(my_off_t*)sv); + DBUG_RETURN(0); } @@ -5332,7 +5505,12 @@ int THD::binlog_write_table_map(TABLE *table, bool is_transactional, is_transactional= 1; /* Pre-conditions */ +#ifdef WITH_WSREP + DBUG_ASSERT(is_current_stmt_binlog_format_row() && + (WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open())); +#else DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open()); +#endif DBUG_ASSERT(table->s->table_map_id != ULONG_MAX); Table_map_log_event @@ -5465,7 +5643,11 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd, bool is_transactional) { DBUG_ENTER("MYSQL_BIN_LOG::flush_and_set_pending_rows_event(event)"); +#ifdef WITH_WSREP + DBUG_ASSERT(WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()); +#else DBUG_ASSERT(mysql_bin_log.is_open()); +#endif DBUG_PRINT("enter", ("event: 0x%lx", (long) event)); int error= 0; @@ -5791,7 +5973,13 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate) mostly called if is_open() *was* true a few instructions before, but it could have changed since. */ +#ifdef WITH_WSREP + /* applier and replayer can skip writing binlog events */ + if ((WSREP_EMULATE_BINLOG(thd) && (thd->wsrep_exec_mode != REPL_RECV)) || + is_open()) +#else if (likely(is_open())) +#endif { my_off_t UNINIT_VAR(my_org_b_tell); #ifdef HAVE_REPLICATION @@ -6129,6 +6317,15 @@ int MYSQL_BIN_LOG::rotate(bool force_rotate, bool* check_purge) { int error= 0; DBUG_ENTER("MYSQL_BIN_LOG::rotate"); +#ifdef WITH_WSREP + if (WSREP_ON && wsrep_to_isolation) + { + *check_purge= false; + WSREP_DEBUG("avoiding binlog rotate due to TO isolation: %d", + wsrep_to_isolation); + DBUG_RETURN(0); + } +#endif //todo: fix the macro def and restore safe_mutex_assert_owner(&LOCK_log); *check_purge= false; @@ -6675,6 +6872,9 @@ MYSQL_BIN_LOG::write_transaction_to_binlog(THD *thd, Ha_trx_info *ha_info; DBUG_ENTER("MYSQL_BIN_LOG::write_transaction_to_binlog"); +#ifdef WITH_WSREP + if (wsrep_emulate_bin_log) DBUG_RETURN(0); +#endif /* WITH_WSREP */ entry.thd= thd; entry.cache_mngr= cache_mngr; entry.error= 0; @@ -6683,6 +6883,7 @@ MYSQL_BIN_LOG::write_transaction_to_binlog(THD *thd, entry.using_trx_cache= using_trx_cache; entry.need_unlog= false; ha_info= all ? thd->transaction.all.ha_list : thd->transaction.stmt.ha_list; + for (; ha_info; ha_info= ha_info->next()) { if (ha_info->is_started() && ha_info->ht() != binlog_hton && @@ -8819,7 +9020,14 @@ TC_LOG_BINLOG::log_and_order(THD *thd, my_xid xid, bool all, binlog_cache_mngr *cache_mngr= thd->binlog_setup_trx_data(); if (!cache_mngr) +#ifdef WITH_WSREP + { + WSREP_DEBUG("Skipping empty log_xid: %s", thd->query()); DBUG_RETURN(0); + } +#else + DBUG_RETURN(0); +#endif /* WITH_WSREP */ cache_mngr->using_xa= TRUE; cache_mngr->xa_xid= xid; diff --git a/sql/log.h b/sql/log.h index 67fcf068ec4..411b06bbced 100644 --- a/sql/log.h +++ b/sql/log.h @@ -106,7 +106,10 @@ public: int log_and_order(THD *thd, my_xid xid, bool all, bool need_prepare_ordered, bool need_commit_ordered) { - DBUG_ASSERT(0 /* Internal error - TC_LOG_DUMMY::log_and_order() called */); +#ifndef WITH_WSREP + DBUG_ASSERT(0 /* Internal error - TC_LOG_DUMMY::log_and_order() called + */); +#endif return 1; } int unlog(ulong cookie, my_xid xid) { return 0; } @@ -981,6 +984,22 @@ enum enum_binlog_format { BINLOG_FORMAT_UNSPEC=3 ///< thd_binlog_format() returns it when binlog is closed }; +#ifdef WITH_WSREP +IO_CACHE * get_trans_log(THD * thd); +bool wsrep_trans_cache_is_empty(THD *thd); +void thd_binlog_flush_pending_rows_event(THD *thd, bool stmt_end); +void thd_binlog_trx_reset(THD * thd); +void thd_binlog_rollback_stmt(THD * thd); +#endif /* WITH_WSREP */ + +#if defined(WITH_WSREP) && !defined(EMBEDDED_LIBRARY) +#define WSREP_FORMAT(my_format) \ + ((wsrep_forced_binlog_format != BINLOG_FORMAT_UNSPEC) ? \ + wsrep_forced_binlog_format : my_format) +#else +#define WSREP_FORMAT(my_format) my_format +#endif /* WITH_WSREP && !EMBEDDED_LIBRARY */ + int query_error_code(THD *thd, bool not_killed); uint purge_log_get_error_code(int res); diff --git a/sql/log_event.cc b/sql/log_event.cc index 6a85893803e..e288f4284b7 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -45,6 +45,9 @@ #include #include "compat56.h" +#if WITH_WSREP +#include "wsrep_mysqld.h" +#endif #endif /* MYSQL_CLIENT */ #include @@ -3091,7 +3094,14 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, master_data_written(0) { time_t end_time; - +#ifdef WITH_WSREP + /* + If Query_log_event will contain non trans keyword (not BEGIN, COMMIT, + SAVEPOINT or ROLLBACK) we disable PA for this transaction. + */ + if (!is_trans_keyword()) + thd->wsrep_PA_safe= false; +#endif /* WITH_WSREP */ memset(&user, 0, sizeof(user)); memset(&host, 0, sizeof(host)); @@ -4045,7 +4055,11 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi, uint64 sub_id= 0; rpl_gtid gtid; Relay_log_info const *rli= rgi->rli; +#ifdef WITH_WSREP + Rpl_filter *rpl_filter= (rli->mi) ? rli->mi->rpl_filter: NULL; +#else Rpl_filter *rpl_filter= rli->mi->rpl_filter; +#endif /* WITH_WSREP */ bool current_stmt_is_commit; DBUG_ENTER("Query_log_event::do_apply_event"); @@ -4519,6 +4533,21 @@ Query_log_event::do_shall_skip(rpl_group_info *rgi) DBUG_RETURN(Log_event::EVENT_SKIP_COUNT); } } +#ifdef WITH_WSREP + else if (wsrep_mysql_replication_bundle && WSREP_ON && thd->wsrep_mysql_replicated > 0 && + (!strncasecmp(query , "BEGIN", 5) || !strncasecmp(query , "COMMIT", 6))) + { + if (++thd->wsrep_mysql_replicated < (int)wsrep_mysql_replication_bundle) + { + WSREP_DEBUG("skipping wsrep commit %d", thd->wsrep_mysql_replicated); + DBUG_RETURN(Log_event::EVENT_SKIP_IGNORE); + } + else + { + thd->wsrep_mysql_replicated = 0; + } + } +#endif DBUG_RETURN(Log_event::do_shall_skip(rgi)); } @@ -7348,6 +7377,20 @@ Xid_log_event::do_shall_skip(rpl_group_info *rgi) thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_GTID_BEGIN); DBUG_RETURN(Log_event::EVENT_SKIP_COUNT); } +#ifdef WITH_WSREP + else if (wsrep_mysql_replication_bundle && WSREP_ON) + { + if (++thd->wsrep_mysql_replicated < (int)wsrep_mysql_replication_bundle) + { + WSREP_DEBUG("skipping wsrep commit %d", thd->wsrep_mysql_replicated); + DBUG_RETURN(Log_event::EVENT_SKIP_IGNORE); + } + else + { + thd->wsrep_mysql_replicated = 0; + } + } +#endif DBUG_RETURN(Log_event::do_shall_skip(rgi)); } #endif /* !MYSQL_CLIENT */ @@ -8370,6 +8413,14 @@ err: end_io_cache(&file); if (fd >= 0) mysql_file_close(fd, MYF(0)); +#ifdef WITH_WSREP + if (WSREP(thd)) + thd_proc_info(thd, "exit Create_file_log_event::do_apply_event()"); + else + thd_proc_info(thd, 0); +#else /* WITH_WSREP */ + thd_proc_info(thd, 0); +#endif /* WITH_WSREP */ return error != 0; } #endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */ @@ -8541,6 +8592,14 @@ int Append_block_log_event::do_apply_event(rpl_group_info *rgi) err: if (fd >= 0) mysql_file_close(fd, MYF(0)); +#ifdef WITH_WSREP + if (WSREP(thd)) + thd_proc_info(thd, "exit Append_block_log_event::do_apply_event()"); + else + thd_proc_info(thd, 0); +#else /* WITH_WSREP */ + thd_proc_info(thd, 0); +#endif /* WITH_WSREP */ DBUG_RETURN(error); } #endif @@ -9625,6 +9684,18 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi) if (open_and_lock_tables(thd, rgi->tables_to_lock, FALSE, 0)) { uint actual_error= thd->get_stmt_da()->sql_errno(); +#ifdef WITH_WSREP + if (WSREP(thd)) + { + WSREP_WARN("BF applier failed to open_and_lock_tables: %u, fatal: %d " + "wsrep = (exec_mode: %d conflict_state: %d seqno: %lld)", + thd->get_stmt_da()->sql_errno(), + thd->is_fatal_error, + thd->wsrep_exec_mode, + thd->wsrep_conflict_state, + (long long)wsrep_thd_trx_seqno(thd)); + } +#endif if (thd->is_slave_error || thd->is_fatal_error) { /* @@ -10772,7 +10843,12 @@ check_table_map(rpl_group_info *rgi, RPL_TABLE_LIST *table_list) enum_tbl_map_status res= OK_TO_PROCESS; Relay_log_info *rli= rgi->rli; +#ifdef WITH_WSREP + if ((rgi->thd->slave_thread /* filtering is for slave only */ || + (WSREP(rgi->thd) && rgi->thd->wsrep_applier)) && +#else if (rgi->thd->slave_thread /* filtering is for slave only */ && +#endif /* WITH_WSREP */ (!rli->mi->rpl_filter->db_ok(table_list->db) || (rli->mi->rpl_filter->is_on() && !rli->mi->rpl_filter->tables_ok("", table_list)))) res= FILTERED_OUT; @@ -11520,8 +11596,23 @@ int Write_rows_log_event::do_exec_row(rpl_group_info *rgi) { DBUG_ASSERT(m_table != NULL); +#ifdef WITH_WSREP +#ifdef WSREP_PROC_INFO + char info[64]; + info[sizeof(info) - 1] = '\0'; + snprintf(info, sizeof(info) - 1, "Write_rows_log_event::write_row(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); + const char* tmp = (WSREP(thd)) ? thd_proc_info(thd, info) : NULL; +#else + const char* tmp = (WSREP(thd)) ? + thd_proc_info(thd,"Write_rows_log_event::write_row()") : NULL; +#endif /* WSREP_PROC_INFO */ +#endif /* WITH_WSREP */ int error= write_row(rgi, slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT); +#ifdef WITH_WSREP + if (WSREP(thd)) thd_proc_info(thd, tmp); +#endif /* WITH_WSREP */ if (error && !thd->is_error()) { DBUG_ASSERT(0); @@ -12202,11 +12293,33 @@ int Delete_rows_log_event::do_exec_row(rpl_group_info *rgi) slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers; DBUG_ASSERT(m_table != NULL); +#ifdef WITH_WSREP +#ifdef WSREP_PROC_INFO + char info[64]; + info[sizeof(info) - 1] = '\0'; + snprintf(info, sizeof(info) - 1, "Delete_rows_log_event::find_row(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); + const char* tmp = (WSREP(thd)) ? thd_proc_info(thd, info) : NULL; +#else + const char* tmp = (WSREP(thd)) ? + thd_proc_info(thd,"Delete_rows_log_event::find_row()") : NULL; +#endif /* WSREP_PROC_INFO */ +#endif /* WITH_WSREP */ if (!(error= find_row(rgi))) { /* Delete the record found, located in record[0] */ +#ifdef WITH_WSREP +#ifdef WSREP_PROC_INFO + snprintf(info, sizeof(info) - 1, + "Delete_rows_log_event::ha_delete_row(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); + if (WSREP(thd)) thd_proc_info(thd, info); +#else + if (WSREP(thd)) thd_proc_info(thd,"Delete_rows_log_event::ha_delete_row()"); +#endif /* WSREP_PROC_INFO */ +#endif /* WITH_WSREP */ if (invoke_triggers && process_triggers(TRG_EVENT_DELETE, TRG_ACTION_BEFORE, FALSE)) error= HA_ERR_GENERIC; // in case if error is not set yet @@ -12217,6 +12330,9 @@ int Delete_rows_log_event::do_exec_row(rpl_group_info *rgi) error= HA_ERR_GENERIC; // in case if error is not set yet m_table->file->ha_index_or_rnd_end(); } +#ifdef WITH_WSREP + if (WSREP(thd)) thd_proc_info(thd, tmp); +#endif /* WITH_WSREP */ return error; } @@ -12346,6 +12462,18 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers; DBUG_ASSERT(m_table != NULL); +#ifdef WITH_WSREP +#ifdef WSREP_PROC_INFO + char info[64]; + info[sizeof(info) - 1] = '\0'; + snprintf(info, sizeof(info) - 1, "Update_rows_log_event::find_row(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); + const char* tmp = (WSREP(thd)) ? thd_proc_info(thd, info) : NULL; +#else + const char* tmp = (WSREP(thd)) ? + thd_proc_info(thd,"Update_rows_log_event::find_row()") : NULL; +#endif /* WSREP_PROC_INFO */ +#endif /* WITH_WSREP */ int error= find_row(rgi); if (error) { @@ -12372,6 +12500,17 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) store_record(m_table,record[1]); m_curr_row= m_curr_row_end; +#ifdef WITH_WSREP +#ifdef WSREP_PROC_INFO + snprintf(info, sizeof(info) - 1, + "Update_rows_log_event::unpack_current_row(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); + if (WSREP(thd)) thd_proc_info(thd, info); +#else + if (WSREP(thd)) + thd_proc_info(thd,"Update_rows_log_event::unpack_current_row()"); +#endif /* WSREP_PROC_INFO */ +#endif /* WITH_WSREP */ /* this also updates m_curr_row_end */ if ((error= unpack_current_row(rgi))) goto err; @@ -12390,6 +12529,17 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) DBUG_DUMP("new values", m_table->record[0], m_table->s->reclength); #endif +#ifdef WITH_WSREP +#ifdef WSREP_PROC_INFO + snprintf(info, sizeof(info) - 1, + "Update_rows_log_event::ha_update_row(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); + if (WSREP(thd)) thd_proc_info(thd, info); +#else + if (WSREP(thd)) thd_proc_info(thd,"Update_rows_log_event::ha_update_row()"); +#endif /* WSREP_PROC_INFO */ +#endif /* WITH_WSREP */ + if (invoke_triggers && process_triggers(TRG_EVENT_UPDATE, TRG_ACTION_BEFORE, TRUE)) { @@ -12405,6 +12555,9 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) process_triggers(TRG_EVENT_UPDATE, TRG_ACTION_AFTER, TRUE)) error= HA_ERR_GENERIC; // in case if error is not set yet +#ifdef WITH_WSREP + if (WSREP(thd)) thd_proc_info(thd, tmp); +#endif /* WITH_WSREP */ err: m_table->file->ha_index_or_rnd_end(); return error; @@ -12495,6 +12648,48 @@ void Incident_log_event::pack_info(THD *thd, Protocol *protocol) protocol->store(buf, bytes, &my_charset_bin); } #endif +#if WITH_WSREP && !defined(MYSQL_CLIENT) +Format_description_log_event *wsrep_format_desc; // TODO: free them at the end +/* + read the first event from (*buf). The size of the (*buf) is (*buf_len). + At the end (*buf) is shitfed to point to the following event or NULL and + (*buf_len) will be changed to account just being read bytes of the 1st event. +*/ +#define WSREP_MAX_ALLOWED_PACKET 1024*1024*1024 // current protocol max + +Log_event* wsrep_read_log_event( + char **arg_buf, size_t *arg_buf_len, + const Format_description_log_event *description_event) +{ + DBUG_ENTER("wsrep_read_log_event"); + char *head= (*arg_buf); + + uint data_len = uint4korr(head + EVENT_LEN_OFFSET); + char *buf= (*arg_buf); + const char *error= 0; + Log_event *res= 0; + + if (data_len > WSREP_MAX_ALLOWED_PACKET) + { + error = "Event too big"; + goto err; + } + + res= Log_event::read_log_event(buf, data_len, &error, description_event, false); + +err: + if (!res) + { + DBUG_ASSERT(error != 0); + sql_print_error("Error in Log_event::read_log_event(): " + "'%s', data_len: %d, event_type: %d", + error,data_len,head[EVENT_TYPE_OFFSET]); + } + (*arg_buf)+= data_len; + (*arg_buf_len)-= data_len; + DBUG_RETURN(res); +} +#endif #ifdef MYSQL_CLIENT diff --git a/sql/mdl.cc b/sql/mdl.cc index 2c2d64e96b2..2172e34cd2a 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -23,6 +23,18 @@ #include #include +#ifdef WITH_WSREP +#include "wsrep_mysqld.h" +#include "wsrep_thd.h" +extern "C" my_thread_id wsrep_thd_thread_id(THD *thd); +extern "C" char *wsrep_thd_query(THD *thd); +void sql_print_information(const char *format, ...) + ATTRIBUTE_FORMAT(printf, 1, 2); + +extern bool +wsrep_grant_mdl_exception(MDL_context *requestor_ctx, + MDL_ticket *ticket); +#endif /* WITH_WSREP */ #ifdef HAVE_PSI_INTERFACE static PSI_mutex_key key_MDL_map_mutex; static PSI_mutex_key key_MDL_wait_LOCK_wait_status; @@ -1497,11 +1509,54 @@ void MDL_lock::Ticket_list::add_ticket(MDL_ticket *ticket) called by other threads. */ DBUG_ASSERT(ticket->get_lock()); +#ifdef WITH_WSREP + if ((this == &(ticket->get_lock()->m_waiting)) && + wsrep_thd_is_BF((void *)(ticket->get_ctx()->wsrep_get_thd()), false)) + { + Ticket_iterator itw(ticket->get_lock()->m_waiting); + Ticket_iterator itg(ticket->get_lock()->m_granted); + + MDL_ticket *waiting, *granted; + MDL_ticket *prev=NULL; + bool added= false; + + while ((waiting= itw++) && !added) + { + if (!wsrep_thd_is_BF((void *)(waiting->get_ctx()->wsrep_get_thd()), true)) + { + WSREP_DEBUG("MDL add_ticket inserted before: %lu %s", + wsrep_thd_thread_id(waiting->get_ctx()->wsrep_get_thd()), + wsrep_thd_query(waiting->get_ctx()->wsrep_get_thd())); + m_list.insert_after(prev, ticket); + added= true; + } + prev= waiting; + } + if (!added) m_list.push_back(ticket); + + while ((granted= itg++)) + { + if (granted->get_ctx() != ticket->get_ctx() && + granted->is_incompatible_when_granted(ticket->get_type())) + { + if (!wsrep_grant_mdl_exception(ticket->get_ctx(), granted)) + { + WSREP_DEBUG("MDL victim killed at add_ticket"); + } + } + } + } + else + { +#endif /* WITH_WSREP */ /* Add ticket to the *back* of the queue to ensure fairness among requests with the same priority. */ m_list.push_back(ticket); +#ifdef WITH_WSREP + } +#endif /* WITH_WSREP */ m_bitmap|= MDL_BIT(ticket->get_type()); } @@ -1842,6 +1897,9 @@ MDL_lock::can_grant_lock(enum_mdl_type type_arg, bool can_grant= FALSE; bitmap_t waiting_incompat_map= incompatible_waiting_types_bitmap()[type_arg]; bitmap_t granted_incompat_map= incompatible_granted_types_bitmap()[type_arg]; +#ifdef WITH_WSREP + bool wsrep_can_grant= TRUE; +#endif /* WITH_WSREP */ /* New lock request can be satisfied iff: @@ -1864,12 +1922,59 @@ MDL_lock::can_grant_lock(enum_mdl_type type_arg, { if (ticket->get_ctx() != requestor_ctx && ticket->is_incompatible_when_granted(type_arg)) +#ifdef WITH_WSREP + { + if (wsrep_thd_is_BF((void *)(requestor_ctx->wsrep_get_thd()),false) && + key.mdl_namespace() == MDL_key::GLOBAL) + { + WSREP_DEBUG("global lock granted for BF: %lu %s", + wsrep_thd_thread_id(requestor_ctx->wsrep_get_thd()), + wsrep_thd_query(requestor_ctx->wsrep_get_thd())); + can_grant = true; + } + else if (!wsrep_grant_mdl_exception(requestor_ctx, ticket)) + { + wsrep_can_grant= FALSE; + if (wsrep_log_conflicts) + { + MDL_lock * lock = ticket->get_lock(); + WSREP_INFO( + "MDL conflict db=%s table=%s ticket=%d solved by %s", + lock->key.db_name(), lock->key.name(), ticket->get_type(), "abort" + ); + } + } + else + { + can_grant= TRUE; + } + } +#else break; +#endif /* WITH_WSREP */ } +#ifdef WITH_WSREP + if ((ticket == NULL) && wsrep_can_grant) +#else if (ticket == NULL) /* Incompatible locks are our own. */ +#endif /* WITH_WSREP */ + can_grant= TRUE; } } +#ifdef WITH_WSREP + else + { + if (wsrep_thd_is_BF((void *)(requestor_ctx->wsrep_get_thd()), false) && + key.mdl_namespace() == MDL_key::GLOBAL) + { + WSREP_DEBUG("global lock granted for BF (waiting queue): %lu %s", + wsrep_thd_thread_id(requestor_ctx->wsrep_get_thd()), + wsrep_thd_query(requestor_ctx->wsrep_get_thd())); + can_grant = true; + } + } +#endif /* WITH_WSREP */ return can_grant; } @@ -2914,7 +3019,12 @@ void MDL_context::release_locks_stored_before(enum_mdl_duration duration, DBUG_VOID_RETURN; } - +#ifdef WITH_WSREP +void MDL_context::release_explicit_locks() +{ + release_locks_stored_before(MDL_EXPLICIT, NULL); +} +#endif /** Release all explicit locks in the context which correspond to the same name/object as this lock request. @@ -3222,3 +3332,35 @@ void MDL_context::set_transaction_duration_for_all_locks() ticket->m_duration= MDL_TRANSACTION; #endif } +#ifdef WITH_WSREP +void MDL_ticket::wsrep_report(bool debug) +{ + if (debug) + { + const PSI_stage_info *psi_stage = m_lock->key.get_wait_state_name(); + + WSREP_DEBUG("MDL ticket: type: %s space: %s db: %s name: %s (%s)", + (get_type() == MDL_INTENTION_EXCLUSIVE) ? "intention exclusive" : + ((get_type() == MDL_SHARED) ? "shared" : + ((get_type() == MDL_SHARED_HIGH_PRIO ? "shared high prio" : + ((get_type() == MDL_SHARED_READ) ? "shared read" : + ((get_type() == MDL_SHARED_WRITE) ? "shared write" : + ((get_type() == MDL_SHARED_NO_WRITE) ? "shared no write" : + ((get_type() == MDL_SHARED_NO_READ_WRITE) ? "shared no read write" : + ((get_type() == MDL_EXCLUSIVE) ? "exclusive" : + "UNKNOWN")))))))), + (m_lock->key.mdl_namespace() == MDL_key::GLOBAL) ? "GLOBAL" : + ((m_lock->key.mdl_namespace() == MDL_key::SCHEMA) ? "SCHEMA" : + ((m_lock->key.mdl_namespace() == MDL_key::TABLE) ? "TABLE" : + ((m_lock->key.mdl_namespace() == MDL_key::TABLE) ? "FUNCTION" : + ((m_lock->key.mdl_namespace() == MDL_key::TABLE) ? "PROCEDURE" : + ((m_lock->key.mdl_namespace() == MDL_key::TABLE) ? "TRIGGER" : + ((m_lock->key.mdl_namespace() == MDL_key::TABLE) ? "EVENT" : + ((m_lock->key.mdl_namespace() == MDL_key::COMMIT) ? "COMMIT" : + (char *)"UNKNOWN"))))))), + m_lock->key.db_name(), + m_lock->key.name(), + psi_stage->m_name); + } +} +#endif /* WITH_WSREP */ diff --git a/sql/mdl.h b/sql/mdl.h index 47c587eb3be..639a8966b33 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -586,6 +586,9 @@ public: MDL_ticket *next_in_lock; MDL_ticket **prev_in_lock; public: +#ifdef WITH_WSREP + void wsrep_report(bool debug); +#endif /* WITH_WSREP */ bool has_pending_conflicting_lock() const; MDL_context *get_ctx() const { return m_ctx; } @@ -774,6 +777,13 @@ public: m_tickets[MDL_EXPLICIT].is_empty()); } +#ifdef WITH_WSREP + inline bool has_transactional_locks() const + { + return !m_tickets[MDL_TRANSACTION].is_empty(); + } +#endif /* WITH_WSREP */ + MDL_savepoint mdl_savepoint() { return MDL_savepoint(m_tickets[MDL_STATEMENT].front(), @@ -786,6 +796,9 @@ public: void release_statement_locks(); void release_transactional_locks(); +#ifdef WITH_WSREP + void release_explicit_locks(); +#endif void rollback_to_savepoint(const MDL_savepoint &mdl_savepoint); MDL_context_owner *get_owner() { return m_owner; } @@ -919,6 +932,9 @@ private: MDL_ticket **out_ticket); public: +#ifdef WITH_WSREP + THD *wsrep_get_thd() const { return get_thd(); } +#endif void find_deadlock(); ulong get_thread_id() const { return thd_get_thread_id(get_thd()); } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 066dae224eb..b2cbeebae49 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -71,6 +71,13 @@ #include "scheduler.h" #include #include "debug_sync.h" +#ifdef WITH_WSREP +#include "wsrep_mysqld.h" +#include "wsrep_var.h" +#include "wsrep_thd.h" +#include "wsrep_sst.h" +ulong wsrep_running_threads = 0; // # of currently running wsrep threads +#endif #include "sql_callback.h" #include "threadpool.h" @@ -360,7 +367,11 @@ static char *default_character_set_name; static char *character_set_filesystem_name; static char *lc_messages; static char *lc_time_names_name; +#ifndef WITH_WSREP static char *my_bind_addr_str; +#else +char *my_bind_addr_str; +#endif /* WITH_WSREP */ static char *default_collation_name; char *default_storage_engine, *default_tmp_storage_engine; static char compiled_default_collation_name[]= MYSQL_DEFAULT_COLLATION_NAME; @@ -372,6 +383,9 @@ static DYNAMIC_ARRAY all_options; /* Global variables */ +#ifdef WITH_WSREP +ulong my_bind_addr; +#endif /* WITH_WSREP */ bool opt_bin_log, opt_bin_log_used=0, opt_ignore_builtin_innodb= 0; my_bool opt_log, opt_slow_log, debug_assert_if_crashed_table= 0, opt_help= 0; static my_bool opt_abort; @@ -465,6 +479,10 @@ ulong opt_binlog_rows_event_max_size; my_bool opt_master_verify_checksum= 0; my_bool opt_slave_sql_verify_checksum= 1; const char *binlog_format_names[]= {"MIXED", "STATEMENT", "ROW", NullS}; +#ifdef WITH_WSREP +const char *wsrep_binlog_format_names[]= + {"MIXED", "STATEMENT", "ROW", "NONE", NullS}; +#endif /*WITH_WSREP */ #ifdef HAVE_INITGROUPS volatile sig_atomic_t calling_initgroups= 0; /**< Used in SIGSEGV handler. */ #endif @@ -730,6 +748,23 @@ mysql_cond_t COND_server_started; int mysqld_server_started=0, mysqld_server_initialized= 0; File_parser_dummy_hook file_parser_dummy_hook; +#ifdef WITH_WSREP +mysql_mutex_t LOCK_wsrep_ready; +mysql_cond_t COND_wsrep_ready; +mysql_mutex_t LOCK_wsrep_sst; +mysql_cond_t COND_wsrep_sst; +mysql_mutex_t LOCK_wsrep_sst_init; +mysql_cond_t COND_wsrep_sst_init; +mysql_mutex_t LOCK_wsrep_rollback; +mysql_cond_t COND_wsrep_rollback; +wsrep_aborting_thd_t wsrep_aborting_thd= NULL; +mysql_mutex_t LOCK_wsrep_replaying; +mysql_cond_t COND_wsrep_replaying; +mysql_mutex_t LOCK_wsrep_slave_threads; +mysql_mutex_t LOCK_wsrep_desync; +int wsrep_replaying= 0; +static void wsrep_close_threads(THD* thd); +#endif /* WITH_WSREP */ /* replication parameters, if master_host is not NULL, we are a slave */ uint report_port= 0; @@ -868,6 +903,12 @@ PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list, key_LOCK_error_messages, key_LOG_INFO_lock, key_LOCK_thread_count, key_LOCK_thread_cache, key_PARTITION_LOCK_auto_inc; +#ifdef WITH_WSREP +PSI_mutex_key key_LOCK_wsrep_rollback, key_LOCK_wsrep_thd, + key_LOCK_wsrep_replaying, key_LOCK_wsrep_ready, key_LOCK_wsrep_sst, + key_LOCK_wsrep_sst_thread, key_LOCK_wsrep_sst_init, + key_LOCK_wsrep_slave_threads, key_LOCK_wsrep_desync; +#endif PSI_mutex_key key_RELAYLOG_LOCK_index; PSI_mutex_key key_LOCK_slave_state, key_LOCK_binlog_state, key_LOCK_rpl_thread, key_LOCK_rpl_thread_pool, key_LOCK_parallel_entry; @@ -942,6 +983,18 @@ static PSI_mutex_info all_server_mutexes[]= { &key_LOCK_prepare_ordered, "LOCK_prepare_ordered", PSI_FLAG_GLOBAL}, { &key_LOCK_commit_ordered, "LOCK_commit_ordered", PSI_FLAG_GLOBAL}, { &key_LOG_INFO_lock, "LOG_INFO::lock", 0}, +#ifdef WITH_WSREP + { &key_LOCK_wsrep_ready, "LOCK_wsrep_ready", PSI_FLAG_GLOBAL}, + { &key_LOCK_wsrep_sst, "LOCK_wsrep_sst", PSI_FLAG_GLOBAL}, + { &key_LOCK_wsrep_sst_thread, "wsrep_sst_thread", 0}, + { &key_LOCK_wsrep_sst_init, "LOCK_wsrep_sst_init", PSI_FLAG_GLOBAL}, + { &key_LOCK_wsrep_sst, "LOCK_wsrep_sst", PSI_FLAG_GLOBAL}, + { &key_LOCK_wsrep_rollback, "LOCK_wsrep_rollback", PSI_FLAG_GLOBAL}, + { &key_LOCK_wsrep_thd, "THD::LOCK_wsrep_thd", 0}, + { &key_LOCK_wsrep_replaying, "LOCK_wsrep_replaying", PSI_FLAG_GLOBAL}, + { &key_LOCK_wsrep_slave_threads, "LOCK_wsrep_slave_threads", PSI_FLAG_GLOBAL}, + { &key_LOCK_wsrep_desync, "LOCK_wsrep_desync", PSI_FLAG_GLOBAL}, +#endif { &key_LOCK_thread_count, "LOCK_thread_count", PSI_FLAG_GLOBAL}, { &key_LOCK_thread_cache, "LOCK_thread_cache", PSI_FLAG_GLOBAL}, { &key_PARTITION_LOCK_auto_inc, "HA_DATA_PARTITION::LOCK_auto_inc", 0}, @@ -988,6 +1041,11 @@ PSI_cond_key key_BINLOG_COND_xid_list, key_BINLOG_update_cond, key_TABLE_SHARE_cond, key_user_level_lock_cond, key_COND_thread_count, key_COND_thread_cache, key_COND_flush_thread_cache, key_BINLOG_COND_queue_busy; +#ifdef WITH_WSREP +PSI_cond_key key_COND_wsrep_rollback, key_COND_wsrep_thd, + key_COND_wsrep_replaying, key_COND_wsrep_ready, key_COND_wsrep_sst, + key_COND_wsrep_sst_init, key_COND_wsrep_sst_thread; +#endif /* WITH_WSREP */ PSI_cond_key key_RELAYLOG_update_cond, key_COND_wakeup_ready, key_COND_wait_commit; PSI_cond_key key_RELAYLOG_COND_queue_busy; @@ -1037,6 +1095,15 @@ static PSI_cond_info all_server_conds[]= { &key_user_level_lock_cond, "User_level_lock::cond", 0}, { &key_COND_thread_count, "COND_thread_count", PSI_FLAG_GLOBAL}, { &key_COND_thread_cache, "COND_thread_cache", PSI_FLAG_GLOBAL}, +#ifdef WITH_WSREP + { &key_COND_wsrep_ready, "COND_wsrep_ready", PSI_FLAG_GLOBAL}, + { &key_COND_wsrep_sst, "COND_wsrep_sst", PSI_FLAG_GLOBAL}, + { &key_COND_wsrep_sst_init, "COND_wsrep_sst_init", PSI_FLAG_GLOBAL}, + { &key_COND_wsrep_sst_thread, "wsrep_sst_thread", 0}, + { &key_COND_wsrep_rollback, "COND_wsrep_rollback", PSI_FLAG_GLOBAL}, + { &key_COND_wsrep_thd, "THD::COND_wsrep_thd", 0}, + { &key_COND_wsrep_replaying, "COND_wsrep_replaying", PSI_FLAG_GLOBAL}, +#endif { &key_COND_flush_thread_cache, "COND_flush_thread_cache", PSI_FLAG_GLOBAL}, { &key_COND_rpl_thread, "COND_rpl_thread", 0}, { &key_COND_rpl_thread_queue, "COND_rpl_thread_queue", 0}, @@ -1622,6 +1689,11 @@ static void close_connections(void) if (tmp->slave_thread) continue; +#ifdef WITH_WSREP + /* skip wsrep system threads as well */ + if (WSREP(tmp) && (tmp->wsrep_exec_mode==REPL_RECV || tmp->wsrep_applier)) + continue; +#endif tmp->killed= KILL_SERVER_HARD; MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (tmp)); mysql_mutex_lock(&tmp->LOCK_thd_data); @@ -1697,6 +1769,33 @@ static void close_connections(void) tmp->main_security_ctx.user : "")); close_connection(tmp,ER_SERVER_SHUTDOWN); } +#endif +#ifdef WITH_WSREP + /* + * TODO: this code block may turn out redundant. wsrep->disconnect() + * should terminate slave threads gracefully, and we don't need + * to signal them here. + * The code here makes sure mysqld will not hang during shutdown + * even if wsrep provider has problems in shutting down. + */ + if (WSREP(tmp) && tmp->wsrep_exec_mode==REPL_RECV) + { + sql_print_information("closing wsrep system thread"); + tmp->killed= KILL_CONNECTION; + MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (tmp)); + if (tmp->mysys_var) + { + tmp->mysys_var->abort=1; + mysql_mutex_lock(&tmp->mysys_var->mutex); + if (tmp->mysys_var->current_cond) + { + mysql_mutex_lock(tmp->mysys_var->current_mutex); + mysql_cond_broadcast(tmp->mysys_var->current_cond); + mysql_mutex_unlock(tmp->mysys_var->current_mutex); + } + mysql_mutex_unlock(&tmp->mysys_var->mutex); + } + } #endif DBUG_PRINT("quit",("Unlocking LOCK_thread_count")); mysql_mutex_unlock(&LOCK_thread_count); @@ -1851,8 +1950,15 @@ static void __cdecl kill_server(int sig_ptr) } } #endif +#ifdef WITH_WSREP + if (WSREP_ON) wsrep_stop_replication(NULL); +#endif close_connections(); +#ifdef WITH_WSREP + if (wsrep_inited == 1) + wsrep_deinit(true); +#endif if (sig != MYSQL_KILL_SIGNAL && sig != 0) unireg_abort(1); /* purecov: inspected */ @@ -1947,6 +2053,25 @@ extern "C" void unireg_abort(int exit_code) usage(); if (exit_code) sql_print_error("Aborting\n"); +#ifdef WITH_WSREP + if (wsrep) + { + /* This is an abort situation, we cannot expect to gracefully close all + * wsrep threads here, we can only diconnect from service */ + wsrep_close_client_connections(FALSE); + shutdown_in_progress= 1; + THD* thd(0); + wsrep->disconnect(wsrep); + WSREP_INFO("Service disconnected."); + wsrep_close_threads(thd); /* this won't close all threads */ + sleep(1); /* so give some time to exit for those which can */ + WSREP_INFO("Some threads may fail to exit."); + + /* In bootstrap mode we deinitialize wsrep here. */ + if (opt_bootstrap && wsrep_inited) + wsrep_deinit(true); + } +#endif // WITH_WSREP clean_up(!opt_abort && (exit_code || !opt_bootstrap)); /* purecov: inspected */ DBUG_PRINT("quit",("done with cleanup in unireg_abort")); mysqld_exit(exit_code); @@ -2166,6 +2291,20 @@ static void clean_up_mutexes() mysql_cond_destroy(&COND_thread_count); mysql_cond_destroy(&COND_thread_cache); mysql_cond_destroy(&COND_flush_thread_cache); +#ifdef WITH_WSREP + (void) mysql_mutex_destroy(&LOCK_wsrep_ready); + (void) mysql_cond_destroy(&COND_wsrep_ready); + (void) mysql_mutex_destroy(&LOCK_wsrep_sst); + (void) mysql_cond_destroy(&COND_wsrep_sst); + (void) mysql_mutex_destroy(&LOCK_wsrep_sst_init); + (void) mysql_cond_destroy(&COND_wsrep_sst_init); + (void) mysql_mutex_destroy(&LOCK_wsrep_rollback); + (void) mysql_cond_destroy(&COND_wsrep_rollback); + (void) mysql_mutex_destroy(&LOCK_wsrep_replaying); + (void) mysql_cond_destroy(&COND_wsrep_replaying); + (void) mysql_mutex_destroy(&LOCK_wsrep_slave_threads); + (void) mysql_mutex_destroy(&LOCK_wsrep_desync); +#endif mysql_mutex_destroy(&LOCK_server_started); mysql_cond_destroy(&COND_server_started); mysql_mutex_destroy(&LOCK_prepare_ordered); @@ -2481,6 +2620,10 @@ static MYSQL_SOCKET activate_tcp_port(uint port) socket_errno); unireg_abort(1); } +#if defined(WITH_WSREP) && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) + (void) fcntl(mysql_socket_getfd(ip_sock), F_SETFD, FD_CLOEXEC); +#endif /* WITH_WSREP */ + DBUG_RETURN(ip_sock); } @@ -2607,6 +2750,9 @@ static void network_init(void) if (mysql_socket_listen(unix_sock,(int) back_log) < 0) sql_print_warning("listen() on Unix socket failed with error %d", socket_errno); +#if defined(WITH_WSREP) && defined(HAVE_FCNTL) + (void) fcntl(mysql_socket_getfd(unix_sock), F_SETFD, FD_CLOEXEC); +#endif /* WITH_WSREP */ } #endif DBUG_PRINT("info",("server started")); @@ -2681,12 +2827,21 @@ void thd_cleanup(THD *thd) void dec_connection_count(THD *thd) { - mysql_mutex_lock(&LOCK_connection_count); - (*thd->scheduler->connection_count)--; - mysql_mutex_unlock(&LOCK_connection_count); +#ifdef WITH_WSREP + /* + Do not decrement when its wsrep system thread. wsrep_applier is set for + applier as well as rollbacker threads. + */ + if (!thd->wsrep_applier) +#endif /* WITH_WSREP */ + { + DBUG_ASSERT(*thd->scheduler->connection_count > 0); + mysql_mutex_lock(&LOCK_connection_count); + (*thd->scheduler->connection_count)--; + mysql_mutex_unlock(&LOCK_connection_count); + } } - /* Delete THD and decrement thread counters, including thread_running */ @@ -2851,10 +3006,19 @@ static bool cache_thread() bool one_thread_per_connection_end(THD *thd, bool put_in_cache) { DBUG_ENTER("one_thread_per_connection_end"); +#ifdef WITH_WSREP + const bool wsrep_applier(thd->wsrep_applier); +#endif + unlink_thd(thd); /* Mark that current_thd is not valid anymore */ set_current_thd(0); + +#ifdef WITH_WSREP + if (put_in_cache && cache_thread() && !wsrep_applier) +#else if (put_in_cache && cache_thread()) +#endif /* WITH_WSREP */ DBUG_RETURN(0); // Thread is reused /* @@ -3975,7 +4139,13 @@ static int init_common_variables() } else opt_log_basename= glob_hostname; - +#ifdef WITH_WSREP + if (0 == wsrep_node_name || 0 == wsrep_node_name[0]) + { + my_free((void *)wsrep_node_name); + wsrep_node_name= my_strdup(glob_hostname, MYF(MY_WME)); + } +#endif /* WITH_WSREP */ if (!*pidfile_name) { strmake(pidfile_name, opt_log_basename, sizeof(pidfile_name)-5); @@ -4035,7 +4205,11 @@ static int init_common_variables() compile_time_assert(sizeof(com_status_vars)/sizeof(com_status_vars[0]) - 1 == SQLCOM_END + 8); #endif - +#ifdef WITH_WSREP + /* This is a protection against mutually incompatible option values. */ + if (WSREP_ON && wsrep_check_opts (remaining_argc, remaining_argv)) + global_system_variables.wsrep_on= 0; +#endif /* WITH_WSREP */ if (get_options(&remaining_argc, &remaining_argv)) return 1; set_server_version(); @@ -4430,6 +4604,28 @@ static int init_thread_environment() rpl_init_gtid_waiting(); #endif +#ifdef WITH_WSREP + mysql_mutex_init(key_LOCK_wsrep_ready, + &LOCK_wsrep_ready, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_wsrep_ready, &COND_wsrep_ready, NULL); + mysql_mutex_init(key_LOCK_wsrep_sst, + &LOCK_wsrep_sst, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_wsrep_sst, &COND_wsrep_sst, NULL); + mysql_mutex_init(key_LOCK_wsrep_sst_init, + &LOCK_wsrep_sst_init, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_wsrep_sst_init, &COND_wsrep_sst_init, NULL); + mysql_mutex_init(key_LOCK_wsrep_rollback, + &LOCK_wsrep_rollback, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_wsrep_rollback, &COND_wsrep_rollback, NULL); + mysql_mutex_init(key_LOCK_wsrep_replaying, + &LOCK_wsrep_replaying, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_wsrep_replaying, &COND_wsrep_replaying, NULL); + mysql_mutex_init(key_LOCK_wsrep_slave_threads, + &LOCK_wsrep_slave_threads, MY_MUTEX_INIT_FAST); + mysql_mutex_init(key_LOCK_wsrep_desync, + &LOCK_wsrep_desync, MY_MUTEX_INIT_FAST); +#endif + DBUG_RETURN(0); } @@ -4727,10 +4923,18 @@ static int init_server_components() /* need to configure logging before initializing storage engines */ if (!opt_bin_log_used) { +#ifdef WITH_WSREP + if (!WSREP_ON && opt_log_slave_updates) +#else if (opt_log_slave_updates) +#endif sql_print_warning("You need to use --log-bin to make " "--log-slave-updates work."); +#ifdef WITH_WSREP + if (!WSREP_ON && binlog_format_used) +#else if (binlog_format_used) +#endif sql_print_warning("You need to use --log-bin to make " "--binlog-format work."); } @@ -4805,10 +5009,67 @@ a file name for --log-bin-index option", opt_binlog_index_name); { opt_bin_logname= my_once_strdup(buf, MYF(MY_WME)); } +#ifdef WITH_WSREP /* WSREP BEFORE SE */ + /* + Wsrep initialization must happen at this point, because: + - opt_bin_logname must be known when starting replication + since SST may need it + - SST may modify binlog index file, so it must be opened + after SST has happened + */ + } + if (!wsrep_recovery) + { + if (opt_bootstrap) // bootsrap option given - disable wsrep functionality + { + wsrep_provider_init(WSREP_NONE); + if (wsrep_init()) unireg_abort(1); + } + else // full wsrep initialization + { + // add basedir/bin to PATH to resolve wsrep script names + char* const tmp_path((char*)alloca(strlen(mysql_home) + + strlen("/bin") + 1)); + if (tmp_path) + { + strcpy(tmp_path, mysql_home); + strcat(tmp_path, "/bin"); + wsrep_prepend_PATH(tmp_path); + } + else + { + WSREP_ERROR("Could not append %s/bin to PATH", mysql_home); + } + + if (wsrep_before_SE()) + { + set_ports(); // this is also called in network_init() later but we need + // to know mysqld_port now - lp:1071882 + wsrep_init_startup(true); + } + } + } + if (opt_bin_log) + { + /* + Variable ln is not defined at this scope. We use opt_bin_logname instead. + It should be the same as ln since + - mysql_bin_log.generate_name() returns first argument if new log name + is not generated + - if new log name is generated, return value is assigned to ln and copied + to opt_bin_logname above + */ + if (mysql_bin_log.open_index_file(opt_binlog_index_name, opt_bin_logname, + TRUE)) + { + unireg_abort(1); + } +#else if (mysql_bin_log.open_index_file(opt_binlog_index_name, ln, TRUE)) { unireg_abort(1); } +#endif /* WITH_WSREP */ } /* call ha_init_key_cache() on all key caches to init them */ @@ -4930,10 +5191,29 @@ a file name for --log-bin-index option", opt_binlog_index_name); internal_tmp_table_max_key_segments= myisam_max_key_segments(); #endif +#ifdef WITH_WSREP + if (!opt_bin_log) + { + wsrep_emulate_bin_log= 1; + } +#endif tc_log= (total_ha_2pc > 1 ? (opt_bin_log ? (TC_LOG *) &mysql_bin_log : +#ifdef WITH_WSREP + (WSREP_ON ? + (TC_LOG *) &tc_log_dummy : + (TC_LOG *) &tc_log_mmap)) : +#else (TC_LOG *) &tc_log_mmap) : +#endif (TC_LOG *) &tc_log_dummy); +#ifdef WITH_WSREP + WSREP_DEBUG("Initial TC log open: %s", + (tc_log == &mysql_bin_log) ? "binlog" : + (tc_log == &tc_log_mmap) ? "mmap" : + (tc_log == &tc_log_dummy) ? "dummy" : "unknown" + ); +#endif if (tc_log->open(opt_bin_log ? opt_bin_logname : opt_tc_log_file)) { @@ -5016,6 +5296,468 @@ static void create_shutdown_thread() #endif /* EMBEDDED_LIBRARY */ +#ifdef WITH_WSREP +typedef void (*wsrep_thd_processor_fun)(THD *); + +pthread_handler_t start_wsrep_THD(void *arg) +{ + THD *thd; + rpl_sql_thread_info sql_info(NULL); + wsrep_thd_processor_fun processor= (wsrep_thd_processor_fun)arg; + + if (my_thread_init()) + { + WSREP_ERROR("Could not initialize thread"); + return(NULL); + } + + if (!(thd= new THD(true))) + { + return(NULL); + } + mysql_mutex_lock(&LOCK_thread_count); + thd->thread_id=thread_id++; + + thd->real_id=pthread_self(); // Keep purify happy + thread_count++; + thread_created++; + threads.append(thd); + + my_net_init(&thd->net,(st_vio*) 0, MYF(0)); + + DBUG_PRINT("wsrep",(("creating thread %lld"), (long long)thd->thread_id)); + thd->prior_thr_create_utime= thd->start_utime= microsecond_interval_timer(); + (void) mysql_mutex_unlock(&LOCK_thread_count); + + /* from bootstrap()... */ + thd->bootstrap=1; + thd->max_client_packet_length= thd->net.max_packet; + thd->security_ctx->master_access= ~(ulong)0; + thd->system_thread_info.rpl_sql_info= &sql_info; + + /* from handle_one_connection... */ + pthread_detach_this_thread(); + + mysql_thread_set_psi_id(thd->thread_id); + thd->thr_create_utime= microsecond_interval_timer(); + if (MYSQL_CALLBACK_ELSE(thread_scheduler, init_new_connection_thread, (), 0)) + { + close_connection(thd, ER_OUT_OF_RESOURCES); + statistic_increment(aborted_connects,&LOCK_status); + MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0)); + + return(NULL); + } + +// + /* + handle_one_connection() is normally the only way a thread would + start and would always be on the very high end of the stack , + therefore, the thread stack always starts at the address of the + first local variable of handle_one_connection, which is thd. We + need to know the start of the stack so that we could check for + stack overruns. + */ + DBUG_PRINT("wsrep", ("handle_one_connection called by thread %lld\n", + (long long)thd->thread_id)); + /* now that we've called my_thread_init(), it is safe to call DBUG_* */ + + thd->thread_stack= (char*) &thd; + if (thd->store_globals()) + { + close_connection(thd, ER_OUT_OF_RESOURCES); + statistic_increment(aborted_connects,&LOCK_status); + MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0)); + delete thd; + + return(NULL); + } + + thd->system_thread= SYSTEM_THREAD_SLAVE_SQL; + thd->security_ctx->skip_grants(); + + /* handle_one_connection() again... */ + //thd->version= refresh_version; + thd->proc_info= 0; + thd->set_command(COM_SLEEP); + thd->set_time(); + thd->init_for_queries(); + + mysql_mutex_lock(&LOCK_thread_count); + wsrep_running_threads++; + mysql_cond_broadcast(&COND_thread_count); + mysql_mutex_unlock(&LOCK_thread_count); + + processor(thd); + + close_connection(thd, 0); + + mysql_mutex_lock(&LOCK_thread_count); + wsrep_running_threads--; + WSREP_DEBUG("wsrep running threads now: %lu", wsrep_running_threads); + mysql_cond_broadcast(&COND_thread_count); + mysql_mutex_unlock(&LOCK_thread_count); + + // Note: We can't call THD destructor without crashing + // if plugins have not been initialized. However, in most of the + // cases this means that pre SE initialization SST failed and + // we are going to exit anyway. + if (plugins_are_initialized) + { + net_end(&thd->net); + MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 1)); + } + else + { + // TODO: lightweight cleanup to get rid of: + // 'Error in my_thread_global_end(): 2 threads didn't exit' + // at server shutdown + } + + my_thread_end(); + if (thread_handling > SCHEDULER_ONE_THREAD_PER_CONNECTION) + { + mysql_mutex_lock(&LOCK_thread_count); + delete thd; + thread_count--; + mysql_mutex_unlock(&LOCK_thread_count); + } + return(NULL); +} + +/**/ +static bool abort_replicated(THD *thd) +{ + bool ret_code= false; + if (thd->wsrep_query_state== QUERY_COMMITTING) + { + if (wsrep_debug) WSREP_INFO("aborting replicated trx: %lu", thd->real_id); + + (void)wsrep_abort_thd(thd, thd, TRUE); + ret_code= true; + } + return ret_code; +} +/**/ +static inline bool is_client_connection(THD *thd) +{ +#if REMOVE +// REMOVE THIS LATER (lp:777201). Below we had to add an explicit check for +// wsrep_applier since wsrep_exec_mode didn't seem to always work +if (thd->wsrep_applier && thd->wsrep_exec_mode != REPL_RECV) +WSREP_WARN("applier has wsrep_exec_mode = %d", thd->wsrep_exec_mode); + + if ( thd->slave_thread || /* declared as mysql slave */ + thd->system_thread || /* declared as system thread */ + !thd->vio_ok() || /* server internal thread */ + thd->wsrep_exec_mode==REPL_RECV || /* applier or replaying thread */ + thd->wsrep_applier || /* wsrep slave applier */ + !thd->variables.wsrep_on) /* client, but fenced outside wsrep */ + return false; + + return true; +#else + return (thd->wsrep_client_thread && thd->variables.wsrep_on); +#endif /* REMOVE */ +} + +static inline bool is_replaying_connection(THD *thd) +{ + bool ret; + + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + ret= (thd->wsrep_conflict_state == REPLAYING) ? true : false; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + + return ret; +} + +static inline bool is_committing_connection(THD *thd) +{ + bool ret; + + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + ret= (thd->wsrep_query_state == QUERY_COMMITTING) ? true : false; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + + return ret; +} + +static bool have_client_connections() +{ + THD *tmp; + + I_List_iterator it(threads); + while ((tmp=it++)) + { + DBUG_PRINT("quit",("Informing thread %ld that it's time to die", + tmp->thread_id)); + if (is_client_connection(tmp) && tmp->killed == KILL_CONNECTION) + { + (void)abort_replicated(tmp); + return true; + } + } + return false; +} + +/* + returns the number of wsrep appliers running. + However, the caller (thd parameter) is not taken in account + */ +static int have_wsrep_appliers(THD *thd) +{ + int ret= 0; + THD *tmp; + + I_List_iterator it(threads); + while ((tmp=it++)) + { + ret+= (tmp != thd && tmp->wsrep_applier); + } + return ret; +} + +static void wsrep_close_thread(THD *thd) +{ + thd->killed= KILL_CONNECTION; + MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (thd)); + if (thd->mysys_var) + { + thd->mysys_var->abort=1; + mysql_mutex_lock(&thd->mysys_var->mutex); + if (thd->mysys_var->current_cond) + { + mysql_mutex_lock(thd->mysys_var->current_mutex); + mysql_cond_broadcast(thd->mysys_var->current_cond); + mysql_mutex_unlock(thd->mysys_var->current_mutex); + } + mysql_mutex_unlock(&thd->mysys_var->mutex); + } +} + +static my_bool have_committing_connections() +{ + THD *tmp; + mysql_mutex_lock(&LOCK_thread_count); // For unlink from list + + I_List_iterator it(threads); + while ((tmp=it++)) + { + if (!is_client_connection(tmp)) + continue; + + if (is_committing_connection(tmp)) + { + mysql_mutex_unlock(&LOCK_thread_count); + return TRUE; + } + } + mysql_mutex_unlock(&LOCK_thread_count); + return FALSE; +} + +int wsrep_wait_committing_connections_close(int wait_time) +{ + int sleep_time= 100; + + while (have_committing_connections() && wait_time > 0) + { + WSREP_DEBUG("wait for committing transaction to close: %d", wait_time); + my_sleep(sleep_time); + wait_time -= sleep_time; + } + if (have_committing_connections()) + { + return 1; + } + return 0; +} + +void wsrep_close_client_connections(my_bool wait_to_end) +{ + /* + First signal all threads that it's time to die + */ + + THD *tmp; + mysql_mutex_lock(&LOCK_thread_count); // For unlink from list + + bool kill_cached_threads_saved= kill_cached_threads; + kill_cached_threads= true; // prevent future threads caching + mysql_cond_broadcast(&COND_thread_cache); // tell cached threads to die + + I_List_iterator it(threads); + while ((tmp=it++)) + { + DBUG_PRINT("quit",("Informing thread %ld that it's time to die", + tmp->thread_id)); + /* We skip slave threads & scheduler on this first loop through. */ + if (!is_client_connection(tmp)) + continue; + + if (is_replaying_connection(tmp)) + { + tmp->killed= KILL_CONNECTION; + continue; + } + + /* replicated transactions must be skipped */ + if (abort_replicated(tmp)) + continue; + + WSREP_DEBUG("closing connection %ld", tmp->thread_id); + wsrep_close_thread(tmp); + } + mysql_mutex_unlock(&LOCK_thread_count); + + if (thread_count) + sleep(2); // Give threads time to die + + mysql_mutex_lock(&LOCK_thread_count); + /* + Force remaining threads to die by closing the connection to the client + */ + + I_List_iterator it2(threads); + while ((tmp=it2++)) + { +#ifndef __bsdi__ // Bug in BSDI kernel + if (is_client_connection(tmp) && + !abort_replicated(tmp) && + !is_replaying_connection(tmp)) + { + WSREP_INFO("killing local connection: %ld",tmp->thread_id); + close_connection(tmp,0); + } +#endif + } + + DBUG_PRINT("quit",("Waiting for threads to die (count=%u)",thread_count)); + if (wsrep_debug) + WSREP_INFO("waiting for client connections to close: %u", thread_count); + + while (wait_to_end && have_client_connections()) + { + mysql_cond_wait(&COND_thread_count, &LOCK_thread_count); + DBUG_PRINT("quit",("One thread died (count=%u)", thread_count)); + } + + kill_cached_threads= kill_cached_threads_saved; + + mysql_mutex_unlock(&LOCK_thread_count); + + /* All client connection threads have now been aborted */ +} + +void wsrep_close_applier(THD *thd) +{ + WSREP_DEBUG("closing applier %ld", thd->thread_id); + wsrep_close_thread(thd); +} + +static void wsrep_close_threads(THD *thd) +{ + THD *tmp; + mysql_mutex_lock(&LOCK_thread_count); // For unlink from list + + I_List_iterator it(threads); + while ((tmp=it++)) + { + DBUG_PRINT("quit",("Informing thread %ld that it's time to die", + tmp->thread_id)); + /* We skip slave threads & scheduler on this first loop through. */ + if (tmp->wsrep_applier && tmp != thd) + { + WSREP_DEBUG("closing wsrep thread %ld", tmp->thread_id); + wsrep_close_thread (tmp); + } + } + + mysql_mutex_unlock(&LOCK_thread_count); +} + +void wsrep_close_applier_threads(int count) +{ + THD *tmp; + mysql_mutex_lock(&LOCK_thread_count); // For unlink from list + + I_List_iterator it(threads); + while ((tmp=it++) && count) + { + DBUG_PRINT("quit",("Informing thread %ld that it's time to die", + tmp->thread_id)); + /* We skip slave threads & scheduler on this first loop through. */ + if (tmp->wsrep_applier) + { + WSREP_DEBUG("closing wsrep applier thread %ld", tmp->thread_id); + tmp->wsrep_applier_closing= TRUE; + count--; + } + } + + mysql_mutex_unlock(&LOCK_thread_count); +} + +void wsrep_wait_appliers_close(THD *thd) +{ + /* Wait for wsrep appliers to gracefully exit */ + mysql_mutex_lock(&LOCK_thread_count); + while (have_wsrep_appliers(thd) > 1) + // 1 is for rollbacker thread which needs to be killed explicitly. + // This gotta be fixed in a more elegant manner if we gonna have arbitrary + // number of non-applier wsrep threads. + { + if (thread_handling > SCHEDULER_ONE_THREAD_PER_CONNECTION) + { + mysql_mutex_unlock(&LOCK_thread_count); + my_sleep(100); + mysql_mutex_lock(&LOCK_thread_count); + } + else + mysql_cond_wait(&COND_thread_count,&LOCK_thread_count); + DBUG_PRINT("quit",("One applier died (count=%u)",thread_count)); + } + mysql_mutex_unlock(&LOCK_thread_count); + /* Now kill remaining wsrep threads: rollbacker */ + wsrep_close_threads (thd); + /* and wait for them to die */ + mysql_mutex_lock(&LOCK_thread_count); + while (have_wsrep_appliers(thd) > 0) + { + if (thread_handling > SCHEDULER_ONE_THREAD_PER_CONNECTION) + { + mysql_mutex_unlock(&LOCK_thread_count); + my_sleep(100); + mysql_mutex_lock(&LOCK_thread_count); + } + else + mysql_cond_wait(&COND_thread_count,&LOCK_thread_count); + DBUG_PRINT("quit",("One thread died (count=%u)",thread_count)); + } + mysql_mutex_unlock(&LOCK_thread_count); + + /* All wsrep applier threads have now been aborted. However, if this thread + is also applier, we are still running... + */ +} + +void wsrep_kill_mysql(THD *thd) +{ + if (mysqld_server_started) + { + if (!shutdown_in_progress) + { + WSREP_INFO("starting shutdown"); + kill_mysql(); + } + } + else + { + unireg_abort(1); + } +} +#endif /* WITH_WSREP */ #if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY) static void handle_connections_methods() @@ -5192,6 +5934,9 @@ int mysqld_main(int argc, char **argv) return 1; } #endif +#ifdef WITH_WSREP + wsrep_filter_new_cluster (&argc, argv); +#endif /* WITH_WSREP */ orig_argc= argc; orig_argv= argv; @@ -5408,6 +6153,15 @@ int mysqld_main(int argc, char **argv) } #endif +#ifdef WITH_WSREP /* WSREP AFTER SE */ + if (wsrep_recovery) + { + select_thread_in_use= 0; + wsrep_recover(); + unireg_abort(0); + } +#endif /* WITH_WSREP */ + /* init signals & alarm After this we can't quit by a simple unireg_abort @@ -5464,7 +6218,32 @@ int mysqld_main(int argc, char **argv) if (Events::init(opt_noacl || opt_bootstrap)) unireg_abort(1); +#ifdef WITH_WSREP /* WSREP AFTER SE */ if (opt_bootstrap) + { + /*! bootstrap wsrep init was taken care of above */ + } + else + { + wsrep_SE_initialized(); + + if (wsrep_before_SE()) + { + /*! in case of no SST wsrep waits in view handler callback */ + wsrep_SE_init_grab(); + wsrep_SE_init_done(); + /*! in case of SST wsrep waits for wsrep->sst_received */ + wsrep_sst_continue(); + } + else + { + wsrep_init_startup (false); + } + + wsrep_create_appliers(wsrep_slave_threads - 1); + } +#endif /* WITH_WSREP */ + if (opt_bootstrap) { select_thread_in_use= 0; // Allow 'kill' to work bootstrap(mysql_stdin); @@ -5531,6 +6310,9 @@ int mysqld_main(int argc, char **argv) #ifndef __WIN__ #ifdef EXTRA_DEBUG2 sql_print_error("Before Lock_thread_count"); +#endif +#ifdef WITH_WSREP + WSREP_DEBUG("Before Lock_thread_count"); #endif mysql_mutex_lock(&LOCK_thread_count); DBUG_PRINT("quit", ("Got thread_count mutex")); @@ -5797,6 +6579,9 @@ static void bootstrap(MYSQL_FILE *file) DBUG_ENTER("bootstrap"); THD *thd= new THD; +#ifdef WITH_WSREP + thd->variables.wsrep_on= 0; +#endif thd->bootstrap=1; my_net_init(&thd->net,(st_vio*) 0, MYF(0)); thd->max_client_packet_length= thd->net.max_packet; @@ -6198,6 +6983,9 @@ void handle_connections_sockets() sleep(1); // Give other threads some time continue; } +#if defined(WITH_WSREP) && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) + (void) fcntl(mysql_socket_getfd(new_sock), F_SETFD, FD_CLOEXEC); +#endif /* WITH_WSREP */ #ifdef HAVE_LIBWRAP { @@ -7970,6 +8758,21 @@ SHOW_VAR status_vars[]= { {"Uptime", (char*) &show_starttime, SHOW_SIMPLE_FUNC}, #ifdef ENABLED_PROFILING {"Uptime_since_flush_status",(char*) &show_flushstatustime, SHOW_SIMPLE_FUNC}, +#endif +#ifdef WITH_WSREP + {"wsrep_connected", (char*) &wsrep_connected, SHOW_BOOL}, + {"wsrep_ready", (char*) &wsrep_ready, SHOW_BOOL}, + {"wsrep_cluster_state_uuid", (char*) &wsrep_cluster_state_uuid,SHOW_CHAR_PTR}, + {"wsrep_cluster_conf_id", (char*) &wsrep_cluster_conf_id, SHOW_LONGLONG}, + {"wsrep_cluster_status", (char*) &wsrep_cluster_status, SHOW_CHAR_PTR}, + {"wsrep_cluster_size", (char*) &wsrep_cluster_size, SHOW_LONG_NOFLUSH}, + {"wsrep_local_index", (char*) &wsrep_local_index, SHOW_LONG_NOFLUSH}, + {"wsrep_local_bf_aborts", (char*) &wsrep_show_bf_aborts, SHOW_SIMPLE_FUNC}, + {"wsrep_provider_name", (char*) &wsrep_provider_name, SHOW_CHAR_PTR}, + {"wsrep_provider_version", (char*) &wsrep_provider_version, SHOW_CHAR_PTR}, + {"wsrep_provider_vendor", (char*) &wsrep_provider_vendor, SHOW_CHAR_PTR}, + {"wsrep_thread_count", (char*) &wsrep_running_threads, SHOW_LONG_NOFLUSH}, + {"wsrep", (char*) &wsrep_show_status, SHOW_FUNC}, #endif {NullS, NullS, SHOW_LONG} }; @@ -8313,6 +9116,10 @@ static int mysql_init_variables(void) if (!(tmpenv = getenv("MY_BASEDIR_VERSION"))) tmpenv = DEFAULT_MYSQL_HOME; strmake_buf(mysql_home, tmpenv); +#endif +#ifdef WITH_WSREP + if (WSREP_ON && wsrep_init_vars()) + return 1; #endif return 0; } @@ -8561,6 +9368,14 @@ mysqld_get_one_option(int optid, case OPT_LOWER_CASE_TABLE_NAMES: lower_case_table_names_used= 1; break; +#ifdef WITH_WSREP + case OPT_WSREP_START_POSITION: + wsrep_start_position_init (argument); + break; + case OPT_WSREP_SST_AUTH: + wsrep_sst_auth_init (argument); + break; +#endif #if defined(ENABLED_DEBUG_SYNC) case OPT_DEBUG_SYNC_TIMEOUT: /* @@ -9029,6 +9844,9 @@ void set_server_version(void) #ifdef EMBEDDED_LIBRARY end= strmov(end, "-embedded"); #endif +#ifdef WITH_WSREP + end= strmov(end, "-wsrep"); +#endif #ifndef DBUG_OFF if (!strstr(MYSQL_SERVER_SUFFIX_STR, "-debug")) end= strmov(end, "-debug"); @@ -9321,6 +10139,9 @@ void refresh_status(THD *thd) /* Reset some global variables */ reset_status_vars(); +#ifdef WITH_WSREP + wsrep->stats_reset(wsrep); +#endif /* WITH_WSREP */ /* Reset the counters of all key caches (default and named). */ process_key_caches(reset_key_cache_counters, 0); diff --git a/sql/mysqld.h b/sql/mysqld.h index a1656a49047..d00fa5c57a6 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -241,6 +241,11 @@ extern PSI_mutex_key key_PAGE_lock, key_LOCK_sync, key_LOCK_active, key_LOCK_pool, key_LOCK_pending_checkpoint; #endif /* HAVE_MMAP */ +#ifdef WITH_WSREP +extern PSI_mutex_key key_LOCK_wsrep_thd; +extern PSI_cond_key key_COND_wsrep_thd; +#endif /* WITH_WSREP */ + #ifdef HAVE_OPENSSL extern PSI_mutex_key key_LOCK_des_key_file; #endif @@ -595,6 +600,15 @@ enum options_mysqld OPT_WANT_CORE, OPT_MYSQL_COMPATIBILITY, OPT_MYSQL_TO_BE_IMPLEMENTED, +#ifdef WITH_WSREP + OPT_WSREP_PROVIDER, + OPT_WSREP_PROVIDER_OPTIONS, + OPT_WSREP_CLUSTER_ADDRESS, + OPT_WSREP_START_POSITION, + OPT_WSREP_SST_AUTH, + OPT_WSREP_RECOVER, +#endif /* WITH_WSREP */ + OPT_which_is_always_the_last }; #endif @@ -752,4 +766,9 @@ extern uint internal_tmp_table_max_key_segments; extern uint volatile global_disable_checkpoint; extern my_bool opt_help; +#ifdef WITH_WSREP +#include "my_pthread.h" +pthread_handler_t start_wsrep_THD(void*); +#endif /* WITH_WSREP */ + #endif /* MYSQLD_INCLUDED */ diff --git a/sql/protocol.cc b/sql/protocol.cc index 2400dadfadc..af2accfd146 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -488,6 +488,14 @@ static uchar *net_store_length_fast(uchar *packet, uint length) void Protocol::end_statement() { +#ifdef WITH_WSREP + /*sanity check, can be removed before 1.0 release */ + if (WSREP(thd) && thd->wsrep_conflict_state== REPLAYING) + { + WSREP_ERROR("attempting net_end_statement while replaying"); + return; + } +#endif DBUG_ENTER("Protocol::end_statement"); DBUG_ASSERT(! thd->get_stmt_da()->is_sent()); bool error= FALSE; diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index a6d93d10f11..b82dbb07a42 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -307,7 +307,11 @@ unpack_row(rpl_group_info *rgi, uint16 const metadata= tabledef->field_metadata(i); #ifndef DBUG_OFF uchar const *const old_pack_ptr= pack_ptr; -#endif +#else +#ifdef WITH_WSREP + uchar const *const old_pack_ptr= pack_ptr; +#endif /* WITH_WSREP */ +#endif /* !DBUF_OFF */ pack_ptr= f->unpack(f->ptr, pack_ptr, row_end, metadata); DBUG_PRINT("debug", ("field: %s; metadata: 0x%x;" " pack_ptr: 0x%lx; pack_ptr': 0x%lx; bytes: %d", @@ -316,6 +320,20 @@ unpack_row(rpl_group_info *rgi, (int) (pack_ptr - old_pack_ptr))); if (!pack_ptr) { +#ifdef WITH_WSREP + /* + Debug message to troubleshoot bug: + https://mariadb.atlassian.net/browse/MDEV-4404 + */ + WSREP_WARN("ROW event unpack field: %s metadata: 0x%x;" + " pack_ptr: 0x%lx; conv_table %p conv_field %p table %s" + " row_end: 0x%lx", + f->field_name, metadata, + (ulong) old_pack_ptr, conv_table, conv_field, + (table_found) ? "found" : "not found", (ulong)row_end + ); +#endif /* WITH_WSREP */ + rgi->rli->report(ERROR_LEVEL, ER_SLAVE_CORRUPT_EVENT, "Could not read field '%s' of table '%s.%s'", f->field_name, table->s->db.str, diff --git a/sql/set_var.cc b/sql/set_var.cc index 5c1e00af33e..7ad5dc31f6e 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -556,7 +556,11 @@ int mysql_del_sys_var_chain(sys_var *first) static int show_cmp(SHOW_VAR *a, SHOW_VAR *b) { +#ifdef WITH_WSREP + return my_strcasecmp(system_charset_info, a->name, b->name); +#else return strcmp(a->name, b->name); +#endif /* WITH_WSREP */ } diff --git a/sql/set_var.h b/sql/set_var.h index bb92e555aa7..e72a8af6210 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -249,6 +249,9 @@ public: int check(THD *thd); int update(THD *thd); int light_check(THD *thd); +#ifdef WITH_WSREP + int wsrep_store_variable(THD *thd); +#endif }; @@ -355,6 +358,9 @@ extern sys_var *Sys_autocommit_ptr; CHARSET_INFO *get_old_charset_by_name(const char *old_name); +#ifdef WITH_WSREP +int sql_set_wsrep_variables(THD *thd, List *var_list); +#endif int sys_var_init(); int sys_var_add_options(DYNAMIC_ARRAY *long_options, int parse_flags); void sys_var_end(void); diff --git a/sql/slave.cc b/sql/slave.cc index f7d019a6c39..54a32f320c0 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -53,6 +53,9 @@ // Create_file_log_event, // Format_description_log_event +#ifdef WITH_WSREP +#include "wsrep_mysqld.h" +#endif #ifdef HAVE_REPLICATION #include "rpl_tblmap.h" @@ -4367,6 +4370,9 @@ pthread_handler_t handle_slave_sql(void *arg) my_off_t saved_skip= 0; Master_info *mi= ((Master_info*)arg); Relay_log_info* rli = &mi->rli; +#ifdef WITH_WSREP + my_bool wsrep_node_dropped= FALSE; +#endif /* WITH_WSREP */ const char *errmsg; rpl_group_info *serial_rgi; rpl_sql_thread_info sql_info(mi->rpl_filter); @@ -4374,6 +4380,9 @@ pthread_handler_t handle_slave_sql(void *arg) // needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff my_thread_init(); DBUG_ENTER("handle_slave_sql"); +#ifdef WITH_WSREP + wsrep_restart_point: +#endif /* WITH_WSREP */ LINT_INIT(saved_master_log_pos); LINT_INIT(saved_log_pos); @@ -4503,6 +4512,11 @@ pthread_handler_t handle_slave_sql(void *arg) } #endif +#ifdef WITH_WSREP + thd->wsrep_exec_mode= LOCAL_STATE; + /* synchronize with wsrep replication */ + if (WSREP_ON) wsrep_ready_wait(); +#endif DBUG_PRINT("master_info",("log_file_name: %s position: %s", rli->group_master_log_name, llstr(rli->group_master_log_pos,llbuff))); @@ -4609,7 +4623,16 @@ log '%s' at position %s, relay log '%s' position: %s%s", RPL_LOG_NAME, DBUG_PRINT("info", ("exec_relay_log_event() failed")); // do not scare the user if SQL thread was simply killed or stopped if (!sql_slave_killed(serial_rgi)) + { slave_output_error_info(rli, thd); +#ifdef WITH_WSREP + uint32 const last_errno= rli->last_error().number; + if (WSREP_ON && last_errno == ER_UNKNOWN_COM_ERROR) + { + wsrep_node_dropped= TRUE; + } +#endif /* WITH_WSREP */ + } goto err; } } @@ -4694,6 +4717,27 @@ err_during_init: delete serial_rgi; delete thd; mysql_mutex_unlock(&LOCK_thread_count); +#ifdef WITH_WSREP + /* if slave stopped due to node going non primary, we set global flag to + trigger automatic restart of slave when node joins back to cluster + */ + if (wsrep_node_dropped && wsrep_restart_slave) + { + if (wsrep_ready) + { + WSREP_INFO("Slave error due to node temporarily non-primary" + "SQL slave will continue"); + wsrep_node_dropped= FALSE; + mysql_mutex_unlock(&rli->run_lock); + goto wsrep_restart_point; + } else { + WSREP_INFO("Slave error due to node going non-primary"); + WSREP_INFO("wsrep_restart_slave was set and therefore slave will be " + "automatically restarted when node joins back to cluster"); + wsrep_restart_slave_activated= TRUE; + } + } +#endif /* WITH_WSREP */ /* Note: the order of the broadcast and unlock calls below (first broadcast, then unlock) is important. Otherwise a killer_thread can execute between the calls and diff --git a/sql/sp.cc b/sql/sp.cc index 188b311ae86..b5b543ead0e 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -2271,3 +2271,37 @@ sp_load_for_information_schema(THD *thd, TABLE *proc_table, String *db, thd->lex= old_lex; return sp; } +#ifdef WITH_WSREP +int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len) +{ + String log_query; + sp_head *sp = thd->lex->sphead; + ulong saved_mode= thd->variables.sql_mode; + String retstr(64); + retstr.set_charset(system_charset_info); + + log_query.set_charset(system_charset_info); + + if (sp->m_type == TYPE_ENUM_FUNCTION) + { + sp_returns_type(thd, retstr, sp); + } + + if (!create_string(thd, &log_query, + sp->m_type, + (sp->m_explicit_name ? sp->m_db.str : NULL), + (sp->m_explicit_name ? sp->m_db.length : 0), + sp->m_name.str, sp->m_name.length, + sp->m_params.str, sp->m_params.length, + retstr.c_ptr(), retstr.length(), + sp->m_body.str, sp->m_body.length, + sp->m_chistics, &(thd->lex->definer->user), + &(thd->lex->definer->host), + saved_mode)) + { + WSREP_WARN("SP create string failed: %s", thd->query()); + return 1; + } + return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(), buf, buf_len); +} +#endif /* WITH_WSREP */ diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 106036e1e83..2491c019e6a 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2559,7 +2559,13 @@ int check_alter_user(THD *thd, const char *host, const char *user) my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables"); goto end; } + +#ifdef WITH_WSREP + if ((!WSREP(thd) || !thd->wsrep_applier) && + !thd->slave_thread && !thd->security_ctx->priv_user[0]) +#else if (!thd->slave_thread && !thd->security_ctx->priv_user[0]) +#endif /* WITH_WSREP */ { my_message(ER_PASSWORD_ANONYMOUS_USER, ER(ER_PASSWORD_ANONYMOUS_USER), MYF(0)); @@ -2571,6 +2577,9 @@ int check_alter_user(THD *thd, const char *host, const char *user) goto end; } if (!thd->slave_thread && +#ifdef WITH_WSREP + (!WSREP(thd) || !thd->wsrep_applier) && +#endif /* WITH_WSREP */ (strcmp(thd->security_ctx->priv_user, user) || my_strcasecmp(system_charset_info, host, thd->security_ctx->priv_host))) @@ -2635,10 +2644,13 @@ bool change_password(THD *thd, const char *host, const char *user, TABLE_LIST tables[TABLES_MAX]; /* Buffer should be extended when password length is extended. */ char buff[512]; - ulong query_length; + ulong query_length=0; enum_binlog_format save_binlog_format; uint new_password_len= (uint) strlen(new_password); - int result; + int result=0; +#ifdef WITH_WSREP + const CSET_STRING query_save = thd->query_string; +#endif /* WITH_WSREP */ DBUG_ENTER("change_password"); DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'", host,user,new_password)); @@ -2646,6 +2658,18 @@ bool change_password(THD *thd, const char *host, const char *user, if (check_change_password(thd, host, user, new_password, new_password_len)) DBUG_RETURN(1); +#ifdef WITH_WSREP + if (WSREP(thd) && !thd->wsrep_applier) + { + query_length= sprintf(buff, "SET PASSWORD FOR '%-.120s'@'%-.120s'='%-.120s'", + user ? user : "", + host ? host : "", + new_password); + thd->set_query_inner(buff, query_length, system_charset_info); + + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, (char*)"user", NULL); + } +#endif /* WITH_WSREP */ if ((result= open_grant_tables(thd, tables, TL_WRITE, Table_user))) DBUG_RETURN(result != 1); @@ -2711,6 +2735,12 @@ end: thd->restore_stmt_binlog_format(save_binlog_format); DBUG_RETURN(result); + +#ifdef WITH_WSREP + error: + WSREP_ERROR("Replication of SET PASSWORD failed: %s", buff); + DBUG_RETURN(result); +#endif /* WITH_WSREP */ } int acl_check_set_default_role(THD *thd, const char *host, const char *user) @@ -2727,8 +2757,11 @@ int acl_set_default_role(THD *thd, const char *host, const char *user, int result= 1; int error; bool clear_role= FALSE; + char buff[512]; enum_binlog_format save_binlog_format; - +#ifdef WITH_WSREP + const CSET_STRING query_save = thd->query_string; +#endif /* WITH_WSREP */ DBUG_ENTER("acl_set_default_role"); DBUG_PRINT("enter",("host: '%s' user: '%s' rolename: '%s'", @@ -2823,7 +2856,6 @@ int acl_set_default_role(THD *thd, const char *host, const char *user, result= 0; if (mysql_bin_log.is_open()) { - char buff[512]; int query_length= sprintf(buff,"SET DEFAULT ROLE '%-.120s' FOR '%-.120s'@'%-.120s'", safe_str(acl_user->default_rolename.str), @@ -2835,9 +2867,23 @@ int acl_set_default_role(THD *thd, const char *host, const char *user, } end: close_mysql_tables(thd); +#ifdef WITH_WSREP + if (WSREP(thd) && !thd->wsrep_applier) + { + WSREP_TO_ISOLATION_END; + + thd->query_string = query_save; + thd->wsrep_exec_mode = LOCAL_STATE; + } +#endif /* WITH_WSREP */ thd->restore_stmt_binlog_format(save_binlog_format); DBUG_RETURN(result); +#ifdef WITH_WSREP + error: + WSREP_ERROR("Replication of SET PASSWORD failed: %s", buff); + DBUG_RETURN(result); +#endif /* WITH_WSREP */ } diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index 34a076cc327..ee70914d331 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -1143,6 +1143,9 @@ bool Sql_cmd_analyze_table::execute(THD *thd) FALSE, UINT_MAX, FALSE)) goto error; thd->enable_slow_log= opt_log_slow_admin_statements; +#ifdef WITH_WSREP + WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL); +#endif res= mysql_admin_table(thd, first_table, &m_lex->check_opt, "analyze", lock_type, 1, 0, 0, 0, &handler::ha_analyze, 0); @@ -1230,6 +1233,7 @@ bool Sql_cmd_repair_table::execute(THD *thd) FALSE, UINT_MAX, FALSE)) goto error; /* purecov: inspected */ thd->enable_slow_log= opt_log_slow_admin_statements; + WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL) res= mysql_admin_table(thd, first_table, &m_lex->check_opt, "repair", TL_WRITE, 1, MY_TEST(m_lex->check_opt.sql_flags & TT_USEFRM), diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc index 97b9c127c22..8b4f4ab9963 100644 --- a/sql/sql_alter.cc +++ b/sql/sql_alter.cc @@ -18,7 +18,9 @@ // mysql_exchange_partition #include "sql_base.h" // open_temporary_tables #include "sql_alter.h" - +#ifdef WITH_WSREP +#include "wsrep_mysqld.h" +#endif /* WITH_WSREP */ Alter_info::Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root) :drop_list(rhs.drop_list, mem_root), alter_list(rhs.alter_list, mem_root), @@ -303,6 +305,21 @@ bool Sql_cmd_alter_table::execute(THD *thd) thd->enable_slow_log= opt_log_slow_admin_statements; +#ifdef WITH_WSREP + TABLE *find_temporary_table(THD *thd, const TABLE_LIST *tl); + + if (WSREP(thd) && + (!thd->is_current_stmt_binlog_format_row() || + !find_temporary_table(thd, first_table)) && + wsrep_to_isolation_begin(thd, + lex->name.str ? select_lex->db : NULL, + lex->name.str ? lex->name.str : NULL, + first_table)) + { + WSREP_WARN("ALTER TABLE isolation failure"); + DBUG_RETURN(TRUE); + } +#endif /* WITH_WSREP */ result= mysql_alter_table(thd, select_lex->db, lex->name.str, &create_info, first_table, @@ -311,6 +328,8 @@ bool Sql_cmd_alter_table::execute(THD *thd) select_lex->order_list.first, lex->ignore); +#ifdef WITH_WSREP +#endif /* WITH_WSREP */ DBUG_RETURN(result); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index d60506dcad7..373adf2596e 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -62,6 +62,10 @@ #include #endif +#ifdef WITH_WSREP +#include "wsrep_mysqld.h" +#include "wsrep_thd.h" +#endif // WITH_WSREP bool No_such_table_error_handler::handle_condition(THD *, @@ -3557,7 +3561,7 @@ thr_lock_type read_lock_type_for_table(THD *thd, */ bool log_on= mysql_bin_log.is_open() && thd->variables.sql_log_bin; ulong binlog_format= thd->variables.binlog_format; - if ((log_on == FALSE) || (binlog_format == BINLOG_FORMAT_ROW) || + if ((log_on == FALSE) || (WSREP_FORMAT(binlog_format) == BINLOG_FORMAT_ROW) || (table_list->table->s->table_category == TABLE_CATEGORY_LOG) || (table_list->table->s->table_category == TABLE_CATEGORY_PERFORMANCE) || !(is_update_query(prelocking_ctx->sql_command) || @@ -4584,9 +4588,36 @@ restart: } } } +#ifdef WITH_WSREP + if ((thd->lex->sql_command== SQLCOM_INSERT || + thd->lex->sql_command== SQLCOM_INSERT_SELECT || + thd->lex->sql_command== SQLCOM_REPLACE || + thd->lex->sql_command== SQLCOM_REPLACE_SELECT || + thd->lex->sql_command== SQLCOM_UPDATE || + thd->lex->sql_command== SQLCOM_UPDATE_MULTI || + thd->lex->sql_command== SQLCOM_LOAD || + thd->lex->sql_command== SQLCOM_DELETE) && + wsrep_replicate_myisam && + (*start) && + (*start)->table && (*start)->table->file->ht->db_type == DB_TYPE_MYISAM) + { + WSREP_TO_ISOLATION_BEGIN(NULL, NULL, (*start)); + } + error: +#endif err: THD_STAGE_INFO(thd, stage_after_opening_tables); + +#ifdef WITH_WSREP + if (WSREP(thd)) + thd_proc_info(thd, "exit open_tables()"); + else + thd_proc_info(thd, 0); +#else /* WITH_WSREP */ + thd_proc_info(thd, 0); +#endif /* WITH_WSREP */ + free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block if (error && *table_to_open) @@ -5040,6 +5071,16 @@ end: close_thread_tables(thd); } THD_STAGE_INFO(thd, stage_after_opening_tables); + +#ifdef WITH_WSREP + if (WSREP(thd)) + thd_proc_info(thd, "End opening table"); + else + thd_proc_info(thd, 0); +#else /* WITH_WSREP */ + thd_proc_info(thd, 0); +#endif /* WITH_WSREP */ + DBUG_RETURN(table); } @@ -5303,7 +5344,7 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count, We can solve these problems in mixed mode by switching to binlogging if at least one updated table is used by sub-statement */ - if (thd->variables.binlog_format != BINLOG_FORMAT_ROW && tables && + if (WSREP_FORMAT(thd->variables.binlog_format) != BINLOG_FORMAT_ROW && tables && has_write_table_with_auto_increment(thd->lex->first_not_own_table())) thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_AUTOINC_COLUMNS); } @@ -8993,7 +9034,19 @@ bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use, (e.g. see partitioning code). */ if (!thd_table->needs_reopen()) +#ifdef WITH_WSREP + { + signalled|= mysql_lock_abort_for_thread(thd, thd_table); + if (thd && WSREP(thd) && wsrep_thd_is_BF((void *)thd, true)) + { + WSREP_DEBUG("remove_table_from_cache: %llu", + (unsigned long long) thd->real_id); + wsrep_abort_thd((void *)thd, (void *)in_use, FALSE); + } + } +#else signalled|= mysql_lock_abort_for_thread(thd, thd_table); +#endif } mysql_mutex_unlock(&in_use->LOCK_thd_data); } diff --git a/sql/sql_builtin.cc.in b/sql/sql_builtin.cc.in index 63850650ac9..2de475b0a76 100644 --- a/sql/sql_builtin.cc.in +++ b/sql/sql_builtin.cc.in @@ -25,7 +25,11 @@ extern #endif builtin_maria_plugin @mysql_mandatory_plugins@ @mysql_optional_plugins@ - builtin_maria_binlog_plugin, builtin_maria_mysql_password_plugin; + builtin_maria_binlog_plugin, +#ifdef WITH_WSREP + builtin_wsrep_plugin@mysql_plugin_defs@, +#endif /* WITH_WSREP */ + builtin_maria_mysql_password_plugin; struct st_maria_plugin *mysql_optional_plugins[]= { @@ -35,5 +39,8 @@ struct st_maria_plugin *mysql_optional_plugins[]= struct st_maria_plugin *mysql_mandatory_plugins[]= { builtin_maria_binlog_plugin, builtin_maria_mysql_password_plugin, +#ifdef WITH_WSREP + builtin_wsrep_plugin@mysql_plugin_defs@, +#endif /* WITH_WSREP */ @mysql_mandatory_plugins@ 0 }; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 8d6ddc0bb08..aef03199503 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -64,6 +64,10 @@ #include "sql_parse.h" // is_update_query #include "sql_callback.h" #include "lock.h" +#ifdef WITH_WSREP +#include "wsrep_mysqld.h" +#include "wsrep_thd.h" +#endif #include "sql_connect.h" /* @@ -816,6 +820,176 @@ char *thd_get_error_context_description(THD *thd, char *buffer, return buffer; } +#ifdef WITH_WSREP +extern int wsrep_on(void *thd) +{ + return (int)(WSREP(((THD*)thd))); +} +extern "C" bool wsrep_thd_is_wsrep_on(THD *thd) +{ + return thd->variables.wsrep_on; +} + +extern "C" bool wsrep_consistency_check(void *thd) +{ + return ((THD*)thd)->wsrep_consistency_check == CONSISTENCY_CHECK_RUNNING; +} + +extern "C" void wsrep_thd_set_exec_mode(THD *thd, enum wsrep_exec_mode mode) +{ + thd->wsrep_exec_mode= mode; +} +extern "C" void wsrep_thd_set_query_state( + THD *thd, enum wsrep_query_state state) +{ + thd->wsrep_query_state= state; +} +extern "C" void wsrep_thd_set_conflict_state( + THD *thd, enum wsrep_conflict_state state) +{ + thd->wsrep_conflict_state= state; +} + + +extern "C" enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd) +{ + return thd->wsrep_exec_mode; +} + +extern "C" const char *wsrep_thd_exec_mode_str(THD *thd) +{ + return + (!thd) ? "void" : + (thd->wsrep_exec_mode == LOCAL_STATE) ? "local" : + (thd->wsrep_exec_mode == REPL_RECV) ? "applier" : + (thd->wsrep_exec_mode == TOTAL_ORDER) ? "total order" : + (thd->wsrep_exec_mode == LOCAL_COMMIT) ? "local commit" : "void"; +} + +extern "C" enum wsrep_query_state wsrep_thd_query_state(THD *thd) +{ + return thd->wsrep_query_state; +} + +extern "C" const char *wsrep_thd_query_state_str(THD *thd) +{ + return + (!thd) ? "void" : + (thd->wsrep_query_state == QUERY_IDLE) ? "idle" : + (thd->wsrep_query_state == QUERY_EXEC) ? "executing" : + (thd->wsrep_query_state == QUERY_COMMITTING) ? "committing" : + (thd->wsrep_query_state == QUERY_EXITING) ? "exiting" : + (thd->wsrep_query_state == QUERY_ROLLINGBACK) ? "rolling back" : "void"; +} + +extern "C" enum wsrep_conflict_state wsrep_thd_conflict_state(THD *thd) +{ + return thd->wsrep_conflict_state; +} +extern "C" const char *wsrep_thd_conflict_state_str(THD *thd) +{ + return + (!thd) ? "void" : + (thd->wsrep_conflict_state == NO_CONFLICT) ? "no conflict" : + (thd->wsrep_conflict_state == MUST_ABORT) ? "must abort" : + (thd->wsrep_conflict_state == ABORTING) ? "aborting" : + (thd->wsrep_conflict_state == MUST_REPLAY) ? "must replay" : + (thd->wsrep_conflict_state == REPLAYING) ? "replaying" : + (thd->wsrep_conflict_state == RETRY_AUTOCOMMIT) ? "retrying" : + (thd->wsrep_conflict_state == CERT_FAILURE) ? "cert failure" : "void"; +} + +extern "C" wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd) +{ + return &thd->wsrep_ws_handle; +} + +extern "C" void wsrep_thd_LOCK(THD *thd) +{ + mysql_mutex_lock(&thd->LOCK_wsrep_thd); +} +extern "C" void wsrep_thd_UNLOCK(THD *thd) +{ + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); +} +extern "C" time_t wsrep_thd_query_start(THD *thd) +{ + return thd->query_start(); +} +extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd) +{ + return thd->wsrep_rand; +} +extern "C" my_thread_id wsrep_thd_thread_id(THD *thd) +{ + return thd->thread_id; +} +extern "C" wsrep_seqno_t wsrep_thd_trx_seqno(THD *thd) +{ + return (thd) ? thd->wsrep_trx_meta.gtid.seqno : WSREP_SEQNO_UNDEFINED; +} +extern "C" query_id_t wsrep_thd_query_id(THD *thd) +{ + return thd->query_id; +} +extern "C" char *wsrep_thd_query(THD *thd) +{ + return (thd) ? thd->query() : NULL; +} +extern "C" query_id_t wsrep_thd_wsrep_last_query_id(THD *thd) +{ + return thd->wsrep_last_query_id; +} +extern "C" void wsrep_thd_set_wsrep_last_query_id(THD *thd, query_id_t id) +{ + thd->wsrep_last_query_id= id; +} +extern "C" void wsrep_thd_awake(THD *thd, my_bool signal) +{ + if (signal) + { + mysql_mutex_lock(&thd->LOCK_thd_data); + thd->awake(KILL_QUERY); + mysql_mutex_unlock(&thd->LOCK_thd_data); + } + else + { + mysql_mutex_lock(&LOCK_wsrep_replaying); + mysql_cond_broadcast(&COND_wsrep_replaying); + mysql_mutex_unlock(&LOCK_wsrep_replaying); + } +} +extern "C" int wsrep_thd_retry_counter(THD *thd) +{ + return(thd->wsrep_retry_counter); +} + +extern int +wsrep_trx_order_before(void *thd1, void *thd2) +{ + if (wsrep_thd_trx_seqno((THD*)thd1) < wsrep_thd_trx_seqno((THD*)thd2)) { + WSREP_DEBUG("BF conflict, order: %lld %lld\n", + (long long)wsrep_thd_trx_seqno((THD*)thd1), + (long long)wsrep_thd_trx_seqno((THD*)thd2)); + return 1; + } + WSREP_DEBUG("waiting for BF, trx order: %lld %lld\n", + (long long)wsrep_thd_trx_seqno((THD*)thd1), + (long long)wsrep_thd_trx_seqno((THD*)thd2)); + return 0; +} +extern "C" int +wsrep_trx_is_aborting(void *thd_ptr) +{ + if (thd_ptr) { + if ((((THD *)thd_ptr)->wsrep_conflict_state == MUST_ABORT) || + (((THD *)thd_ptr)->wsrep_conflict_state == ABORTING)) { + return 1; + } + } + return 0; +} +#endif #if MARIA_PLUGIN_INTERFACE_VERSION < 0x0200 /** @@ -859,7 +1033,7 @@ bool Drop_table_error_handler::handle_condition(THD *thd, } -THD::THD() +THD::THD(bool is_applier) :Statement(&main_lex, &main_mem_root, STMT_CONVENTIONAL_EXECUTION, /* statement id */ 0), rli_fake(0), rgi_fake(0), rgi_slave(NULL), @@ -889,6 +1063,16 @@ THD::THD() bootstrap(0), derived_tables_processing(FALSE), spcont(NULL), +#ifdef WITH_WSREP + wsrep_applier(is_applier), + wsrep_applier_closing(false), + wsrep_client_thread(false), + wsrep_po_handle(WSREP_PO_INITIALIZER), + wsrep_po_cnt(0), + wsrep_po_in_trans(false), + wsrep_apply_format(0), + wsrep_apply_toi(false), +#endif m_parser_state(NULL), #if defined(ENABLED_DEBUG_SYNC) debug_sync_control(0), @@ -1004,6 +1188,22 @@ THD::THD() m_command=COM_CONNECT; *scramble= '\0'; +#ifdef WITH_WSREP + mysql_mutex_init(key_LOCK_wsrep_thd, &LOCK_wsrep_thd, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_wsrep_thd, &COND_wsrep_thd, NULL); + wsrep_ws_handle.trx_id = WSREP_UNDEFINED_TRX_ID; + wsrep_ws_handle.opaque = NULL; + wsrep_retry_counter = 0; + wsrep_PA_safe = true; + wsrep_retry_query = NULL; + wsrep_retry_query_len = 0; + wsrep_retry_command = COM_CONNECT; + wsrep_consistency_check = NO_CONSISTENCY_CHECK; + wsrep_status_vars = 0; + wsrep_mysql_replicated = 0; + wsrep_TOI_pre_query = NULL; + wsrep_TOI_pre_query_len = 0; +#endif /* Call to init() below requires fully initialized Open_tables_state. */ reset_open_tables_state(this); @@ -1043,6 +1243,13 @@ THD::THD() my_rnd_init(&rand, tmp + (ulong) &rand, tmp + (ulong) ::global_query_id); substitute_null_with_insert_id = FALSE; thr_lock_info_init(&lock_info); /* safety: will be reset after start */ +#ifdef WITH_WSREP + lock_info.mysql_thd= (void *)this; + lock_info.in_lock_tables= false; +#ifdef WSREP_PROC_INFO + wsrep_info[sizeof(wsrep_info) - 1] = '\0'; /* make sure it is 0-terminated */ +#endif /* WSREP_PROC_INFO */ +#endif /* WITH_WSREP */ m_internal_handler= NULL; m_binlog_invoker= INVOKER_NONE; @@ -1387,7 +1594,24 @@ void THD::init(void) bzero((char *) &org_status_var, sizeof(org_status_var)); start_bytes_received= 0; last_commit_gtid.seq_no= 0; +#ifdef WITH_WSREP + wsrep_exec_mode= wsrep_applier ? REPL_RECV : LOCAL_STATE; + wsrep_conflict_state= NO_CONFLICT; + wsrep_query_state= QUERY_IDLE; + wsrep_last_query_id= 0; + wsrep_trx_meta.gtid= WSREP_GTID_UNDEFINED; + wsrep_trx_meta.depends_on= WSREP_SEQNO_UNDEFINED; + wsrep_converted_lock_session= false; + wsrep_retry_counter= 0; + wsrep_rli= NULL; + wsrep_rgi= NULL; + wsrep_PA_safe= true; + wsrep_consistency_check = NO_CONSISTENCY_CHECK; + wsrep_mysql_replicated = 0; + wsrep_TOI_pre_query = NULL; + wsrep_TOI_pre_query_len = 0; +#endif if (variables.sql_log_bin) variables.option_bits|= OPTION_BIN_LOG; else @@ -1582,6 +1806,14 @@ THD::~THD() mysql_mutex_lock(&LOCK_thd_data); mysql_mutex_unlock(&LOCK_thd_data); +#ifdef WITH_WSREP + mysql_mutex_lock(&LOCK_wsrep_thd); + mysql_mutex_unlock(&LOCK_wsrep_thd); + mysql_mutex_destroy(&LOCK_wsrep_thd); + if (wsrep_rli) delete wsrep_rli; + if (wsrep_rgi) delete wsrep_rgi; + if (wsrep_status_vars) wsrep->stats_free(wsrep, wsrep_status_vars); +#endif /* Close connection */ #ifndef EMBEDDED_LIBRARY if (net.vio) @@ -1760,6 +1992,9 @@ void THD::awake(killed_state state_to_set) /* Interrupt target waiting inside a storage engine. */ if (state_to_set != NOT_KILLED) +#ifdef WITH_WSREP + /* TODO: prevent applier close here */ +#endif /* WITH_WSREP */ ha_kill_query(this, thd_kill_level(this)); /* Broadcast a condition to kick the target if it is waiting on it. */ @@ -1892,7 +2127,19 @@ bool THD::notify_shared_lock(MDL_context_owner *ctx_in_use, (e.g. see partitioning code). */ if (!thd_table->needs_reopen()) +#ifdef WITH_WSREP + { signalled|= mysql_lock_abort_for_thread(this, thd_table); + if (this && WSREP(this) && wsrep_thd_is_BF((void *)this, FALSE)) + { + WSREP_DEBUG("remove_table_from_cache: %llu", + (unsigned long long) this->real_id); + wsrep_abort_thd((void *)this, (void *)in_use, FALSE); + } + } +#else + signalled|= mysql_lock_abort_for_thread(this, thd_table); +#endif } mysql_mutex_unlock(&in_use->LOCK_thd_data); } @@ -2074,6 +2321,13 @@ void THD::cleanup_after_query() /* reset table map for multi-table update */ table_map_for_update= 0; m_binlog_invoker= INVOKER_NONE; +#ifdef WITH_WSREP + if (TOTAL_ORDER == wsrep_exec_mode) + { + wsrep_exec_mode = LOCAL_STATE; + } + //wsrep_trx_seqno = 0; +#endif /* WITH_WSREP */ #ifndef EMBEDDED_LIBRARY if (rgi_slave) @@ -2496,6 +2750,13 @@ bool sql_exchange::escaped_given(void) bool select_send::send_result_set_metadata(List &list, uint flags) { bool res; +#ifdef WITH_WSREP + if (WSREP(thd) && thd->wsrep_retry_query) + { + WSREP_DEBUG("skipping select metadata"); + return FALSE; + } +#endif /* WITH_WSREP */ if (!(res= thd->protocol->send_result_set_metadata(&list, flags))) is_result_set_started= 1; return res; @@ -4241,8 +4502,13 @@ extern "C" int thd_non_transactional_update(const MYSQL_THD thd) extern "C" int thd_binlog_format(const MYSQL_THD thd) { +#ifdef WITH_WSREP + if (((WSREP(thd) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()) && + (thd->variables.option_bits & OPTION_BIN_LOG)) +#else if (mysql_bin_log.is_open() && (thd->variables.option_bits & OPTION_BIN_LOG)) - return (int) thd->variables.binlog_format; +#endif + return (int) WSREP_FORMAT(thd->variables.binlog_format); else return BINLOG_FORMAT_UNSPEC; } @@ -4972,7 +5238,7 @@ int THD::decide_logging_format(TABLE_LIST *tables) binlog by filtering rules. */ if (mysql_bin_log.is_open() && (variables.option_bits & OPTION_BIN_LOG) && - !(variables.binlog_format == BINLOG_FORMAT_STMT && + !(WSREP_FORMAT(variables.binlog_format) == BINLOG_FORMAT_STMT && !binlog_filter->db_ok(db))) { /* @@ -5182,7 +5448,7 @@ int THD::decide_logging_format(TABLE_LIST *tables) */ my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE), MYF(0)); } - else if (variables.binlog_format == BINLOG_FORMAT_ROW && + else if (WSREP_FORMAT(variables.binlog_format) == BINLOG_FORMAT_ROW && sqlcom_can_generate_row_events(this)) { /* @@ -5211,7 +5477,7 @@ int THD::decide_logging_format(TABLE_LIST *tables) else { /* binlog_format = STATEMENT */ - if (variables.binlog_format == BINLOG_FORMAT_STMT) + if (WSREP_FORMAT(variables.binlog_format) == BINLOG_FORMAT_STMT) { if (lex->is_stmt_row_injection()) { @@ -5228,7 +5494,14 @@ int THD::decide_logging_format(TABLE_LIST *tables) 5. Error: Cannot modify table that uses a storage engine limited to row-logging when binlog_format = STATEMENT */ +#ifdef WITH_WSREP + if (!WSREP(this) || wsrep_exec_mode == LOCAL_STATE) + { +#endif /* WITH_WSREP */ my_error((error= ER_BINLOG_STMT_MODE_AND_ROW_ENGINE), MYF(0), ""); +#ifdef WITH_WSREP + } +#endif /* WITH_WSREP */ } else if (is_write && (unsafe_flags= lex->get_stmt_unsafe_flags()) != 0) { @@ -5340,7 +5613,7 @@ int THD::decide_logging_format(TABLE_LIST *tables) "and binlog_filter->db_ok(db) = %d", mysql_bin_log.is_open(), (variables.option_bits & OPTION_BIN_LOG), - variables.binlog_format, + WSREP_FORMAT(variables.binlog_format), binlog_filter->db_ok(db))); #endif @@ -5577,7 +5850,13 @@ int THD::binlog_write_row(TABLE* table, bool is_trans, MY_BITMAP const* cols, size_t colcnt, uchar const *record) { +#ifdef WITH_WSREP + DBUG_ASSERT(is_current_stmt_binlog_format_row() && + ((WSREP(this) && wsrep_emulate_bin_log) || + mysql_bin_log.is_open())); +#else DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open()); +#endif /* Pack records into format for transfer. We are allocating more @@ -5611,7 +5890,13 @@ int THD::binlog_update_row(TABLE* table, bool is_trans, const uchar *before_record, const uchar *after_record) { +#ifdef WITH_WSREP + DBUG_ASSERT(is_current_stmt_binlog_format_row() && + ((WSREP(this) && wsrep_emulate_bin_log) + || mysql_bin_log.is_open())); +#else DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open()); +#endif size_t const before_maxlen = max_row_length(table, before_record); size_t const after_maxlen = max_row_length(table, after_record); @@ -5660,7 +5945,13 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans, MY_BITMAP const* cols, size_t colcnt, uchar const *record) { +#ifdef WITH_WSREP + DBUG_ASSERT(is_current_stmt_binlog_format_row() && + ((WSREP(this) && wsrep_emulate_bin_log) + || mysql_bin_log.is_open())); +#else DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open()); +#endif /* Pack records into format for transfer. We are allocating more @@ -5695,7 +5986,11 @@ int THD::binlog_remove_pending_rows_event(bool clear_maps, { DBUG_ENTER("THD::binlog_remove_pending_rows_event"); +#ifdef WITH_WSREP + if (!(WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open())) +#else if (!mysql_bin_log.is_open()) +#endif DBUG_RETURN(0); /* Ensure that all events in a GTID group are in the same cache */ @@ -5718,7 +6013,11 @@ int THD::binlog_flush_pending_rows_event(bool stmt_end, bool is_transactional) mode: it might be the case that we left row-based mode before flushing anything (e.g., if we have explicitly locked tables). */ +#ifdef WITH_WSREP + if (!(WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open())) +#else if (!mysql_bin_log.is_open()) +#endif DBUG_RETURN(0); /* Ensure that all events in a GTID group are in the same cache */ @@ -5970,7 +6269,12 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg, DBUG_ENTER("THD::binlog_query"); DBUG_PRINT("enter", ("qtype: %s query: '%-.*s'", show_query_type(qtype), (int) query_len, query_arg)); +#ifdef WITH_WSREP + DBUG_ASSERT(query_arg && (WSREP_EMULATE_BINLOG(this) + || mysql_bin_log.is_open())); +#else DBUG_ASSERT(query_arg && mysql_bin_log.is_open()); +#endif /* If this is withing a BEGIN ... COMMIT group, don't log it */ if (variables.option_bits & OPTION_GTID_BEGIN) diff --git a/sql/sql_class.h b/sql/sql_class.h index f3537086132..0f8ac303f3d 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -57,6 +57,18 @@ void set_thd_stage_info(void *thd, #include "my_apc.h" #include "rpl_gtid.h" +#ifdef WITH_WSREP +#include "wsrep_mysqld.h" +struct wsrep_thd_shadow { + ulonglong options; + uint server_status; + enum wsrep_exec_mode wsrep_exec_mode; + Vio *vio; + ulong tx_isolation; + char *db; + size_t db_length; +}; +#endif class Reprepare_observer; class Relay_log_info; struct rpl_group_info; @@ -638,6 +650,11 @@ typedef struct system_variables ulong wt_timeout_short, wt_deadlock_search_depth_short; ulong wt_timeout_long, wt_deadlock_search_depth_long; +#ifdef WITH_WSREP + my_bool wsrep_on; + my_bool wsrep_causal_reads; + ulong wsrep_retry_autocommit; +#endif double long_query_time_double; my_bool pseudo_slave_mode; @@ -2072,7 +2089,7 @@ public: int is_current_stmt_binlog_format_row() const { DBUG_ASSERT(current_stmt_binlog_format == BINLOG_FORMAT_STMT || current_stmt_binlog_format == BINLOG_FORMAT_ROW); - return current_stmt_binlog_format == BINLOG_FORMAT_ROW; + return (WSREP_FORMAT((ulong)current_stmt_binlog_format) == BINLOG_FORMAT_ROW); } enum binlog_filter_state @@ -2725,6 +2742,48 @@ public: query_id_t first_query_id; } binlog_evt_union; +#ifdef WITH_WSREP + const bool wsrep_applier; /* dedicated slave applier thread */ + bool wsrep_applier_closing; /* applier marked to close */ + bool wsrep_client_thread; /* to identify client threads*/ + enum wsrep_exec_mode wsrep_exec_mode; + query_id_t wsrep_last_query_id; + enum wsrep_query_state wsrep_query_state; + enum wsrep_conflict_state wsrep_conflict_state; + mysql_mutex_t LOCK_wsrep_thd; + mysql_cond_t COND_wsrep_thd; + // changed from wsrep_seqno_t to wsrep_trx_meta_t in wsrep API rev 75 + // wsrep_seqno_t wsrep_trx_seqno; + wsrep_trx_meta_t wsrep_trx_meta; + uint32 wsrep_rand; + Relay_log_info* wsrep_rli; + rpl_group_info* wsrep_rgi; + bool wsrep_converted_lock_session; + wsrep_ws_handle_t wsrep_ws_handle; +#ifdef WSREP_PROC_INFO + char wsrep_info[128]; /* string for dynamic proc info */ +#endif /* WSREP_PROC_INFO */ + ulong wsrep_retry_counter; // of autocommit + bool wsrep_PA_safe; + char* wsrep_retry_query; + size_t wsrep_retry_query_len; + enum enum_server_command wsrep_retry_command; + enum wsrep_consistency_check_mode + wsrep_consistency_check; + wsrep_stats_var* wsrep_status_vars; + int wsrep_mysql_replicated; + const char* wsrep_TOI_pre_query; /* a query to apply before + the actual TOI query */ + size_t wsrep_TOI_pre_query_len; + wsrep_po_handle_t wsrep_po_handle; + size_t wsrep_po_cnt; + my_bool wsrep_po_in_trans; +#ifdef GTID_SUPPORT + rpl_sid wsrep_po_sid; +#endif /* GTID_SUPPORT */ + void* wsrep_apply_format; + bool wsrep_apply_toi; /* applier processing in TOI */ +#endif /* WITH_WSREP */ /** Internal parser state. Note that since the parser is not re-entrant, we keep only one parser @@ -2756,7 +2815,8 @@ public: /* Debug Sync facility. See debug_sync.cc. */ struct st_debug_sync_control *debug_sync_control; #endif /* defined(ENABLED_DEBUG_SYNC) */ - THD(); + THD(bool is_applier= false); + ~THD(); void init(void); @@ -3270,7 +3330,7 @@ public: tests fail and so force them to propagate the lex->binlog_row_based_if_mixed upwards to the caller. */ - if ((variables.binlog_format == BINLOG_FORMAT_MIXED) && + if ((WSREP_FORMAT(variables.binlog_format) == BINLOG_FORMAT_MIXED) && (in_sub_stmt == 0)) set_current_stmt_binlog_format_row(); @@ -3322,7 +3382,7 @@ public: show_system_thread(system_thread))); if (in_sub_stmt == 0) { - if (variables.binlog_format == BINLOG_FORMAT_ROW) + if (WSREP_FORMAT(variables.binlog_format) == BINLOG_FORMAT_ROW) set_current_stmt_binlog_format_row(); else if (temporary_tables == NULL) set_current_stmt_binlog_format_stmt(); diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 433f3303ad7..357294a567a 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -44,6 +44,9 @@ HASH global_index_stats; extern mysql_mutex_t LOCK_global_user_client_stats; extern mysql_mutex_t LOCK_global_table_stats; extern mysql_mutex_t LOCK_global_index_stats; +#ifdef WITH_WSREP +#include "wsrep_mysqld.h" +#endif /* Get structure for logging connection data for the current user @@ -1172,6 +1175,17 @@ bool login_connection(THD *thd) void end_connection(THD *thd) { NET *net= &thd->net; +#ifdef WITH_WSREP + if (WSREP(thd)) + { + wsrep_status_t rcode= wsrep->free_connection(wsrep, thd->thread_id); + if (rcode) { + WSREP_WARN("wsrep failed to free connection context: %lu, code: %d", + thd->thread_id, rcode); + } + } + thd->wsrep_client_thread= 0; +#endif plugin_thdvar_cleanup(thd); if (thd->user_connect) @@ -1307,6 +1321,9 @@ bool thd_prepare_connection(THD *thd) (char *) thd->security_ctx->host_or_ip); prepare_new_connection_state(thd); +#ifdef WITH_WSREP + thd->wsrep_client_thread= 1; +#endif /* WITH_WSREP */ return FALSE; } @@ -1381,6 +1398,14 @@ void do_handle_one_connection(THD *thd_arg) } end_connection(thd); +#ifdef WITH_WSREP + if (WSREP(thd)) + { + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + thd->wsrep_query_state= QUERY_EXITING; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } +#endif end_thread: close_connection(thd); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 38fb897c4f8..9a6ca541706 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -646,7 +646,11 @@ cleanup: /* See similar binlogging code in sql_update.cc, for comments */ if ((error < 0) || thd->transaction.stmt.modified_non_trans_table) { +#ifdef WITH_WSREP + if ((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open())) +#else if (mysql_bin_log.is_open()) +#endif { int errcode= 0; if (error < 0) @@ -1113,7 +1117,11 @@ void multi_delete::abort_result_set() /* there is only side effects; to binlog with the error */ +#ifdef WITH_WSREP + if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) +#else if (mysql_bin_log.is_open()) +#endif { int errcode= query_error_code(thd, thd->killed == NOT_KILLED); /* possible error of writing binary log is ignored deliberately */ @@ -1289,7 +1297,11 @@ bool multi_delete::send_eof() } if ((local_error == 0) || thd->transaction.stmt.modified_non_trans_table) { +#ifdef WITH_WSREP + if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) +#else if (mysql_bin_log.is_open()) +#endif { int errcode= 0; if (local_error == 0) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index d61af758ced..2097f636dd2 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1014,7 +1014,11 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, thd->transaction.stmt.modified_non_trans_table || was_insert_delayed) { +#ifdef WITH_WSREP + if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) +#else if (mysql_bin_log.is_open()) +#endif { int errcode= 0; if (error <= 0) @@ -3195,6 +3199,12 @@ bool Delayed_insert::handle_inserts(void) mysql_cond_broadcast(&cond_client); // If waiting clients } } +#ifdef WITH_WSREP + if (WSREP((&thd))) + thd_proc_info(&thd, "insert done"); + else +#endif /* WITH_WSREP */ + thd_proc_info(&thd, 0); mysql_mutex_unlock(&mutex); /* @@ -3647,8 +3657,15 @@ bool select_insert::send_eof() DBUG_PRINT("enter", ("trans_table=%d, table_type='%s'", trans_table, table->file->table_type())); +#ifdef WITH_WSREP + error= (thd->wsrep_conflict_state == MUST_ABORT || + thd->wsrep_conflict_state == CERT_FAILURE) ? -1 : + (thd->locked_tables_mode <= LTM_LOCK_TABLES ? + table->file->ha_end_bulk_insert() : 0); +#else error= (thd->locked_tables_mode <= LTM_LOCK_TABLES ? table->file->ha_end_bulk_insert() : 0); +#endif /* WITH_WSREP */ if (!error && thd->is_error()) error= thd->get_stmt_da()->sql_errno(); @@ -3676,8 +3693,13 @@ bool select_insert::send_eof() events are in the transaction cache and will be written when ha_autocommit_or_rollback() is issued below. */ +#ifdef WITH_WSREP + if ((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) && + (!error || thd->transaction.stmt.modified_non_trans_table)) +#else if (mysql_bin_log.is_open() && (!error || thd->transaction.stmt.modified_non_trans_table)) +#endif { int errcode= 0; if (!error) @@ -3761,7 +3783,11 @@ void select_insert::abort_result_set() { if (!can_rollback_data()) thd->transaction.all.modified_non_trans_table= TRUE; +#ifdef WITH_WSREP + if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) +#else if (mysql_bin_log.is_open()) +#endif { int errcode= query_error_code(thd, thd->killed == NOT_KILLED); /* error of writing binary log is ignored */ @@ -4169,7 +4195,11 @@ select_create::binlog_show_create_table(TABLE **tables, uint count) create_info->table_was_deleted); DBUG_ASSERT(result == 0); /* store_create_info() always return 0 */ +#ifdef WITH_WSREP + if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) +#else if (mysql_bin_log.is_open()) +#endif /* WITH_WSREP */ { int errcode= query_error_code(thd, thd->killed == NOT_KILLED); result= thd->binlog_query(THD::STMT_QUERY_TYPE, @@ -4179,6 +4209,9 @@ select_create::binlog_show_create_table(TABLE **tables, uint count) /* suppress_use */ FALSE, errcode); } +#ifdef WITH_WSREP + ha_wsrep_fake_trx_id(thd); +#endif return result; } @@ -4208,6 +4241,18 @@ bool select_create::send_eof() trans_commit_stmt(thd); if (!(thd->variables.option_bits & OPTION_GTID_BEGIN)) trans_commit_implicit(thd); +#ifdef WITH_WSREP + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + if (thd->wsrep_conflict_state != NO_CONFLICT) + { + WSREP_DEBUG("select_create commit failed, thd: %lu err: %d %s", + thd->thread_id, thd->wsrep_conflict_state, thd->query()); + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + abort_result_set(); + return TRUE; + } + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); +#endif /* WITH_WSREP */ } else if (!thd->is_current_stmt_binlog_format_row()) table->s->table_creation_was_logged= 1; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index cd9f9238f71..ea6817ad0b2 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1579,6 +1579,17 @@ int lex_one_token(void *arg, THD *thd) } else { +#ifdef WITH_WSREP + if (version == 99997 && thd->wsrep_exec_mode == LOCAL_STATE) + { + WSREP_DEBUG("consistency check: %s", thd->query()); + thd->wsrep_consistency_check= CONSISTENCY_CHECK_DECLARED; + lip->yySkipn(5); + lip->set_echo(TRUE); + state=MY_LEX_START; + break; /* Do not treat contents as a comment. */ + } +#endif /* WITH_WSREP */ /* Patch and skip the conditional comment to avoid it being propagated infinitely (eg. to a slave). diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 019fd55e3d8..ad8418d5b59 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -103,6 +103,12 @@ #include "../storage/maria/ha_maria.h" #endif +#ifdef WITH_WSREP +#include "wsrep_mysqld.h" +#include "wsrep_thd.h" +static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length, + Parser_state *parser_state); +#endif /* WITH_WSREP */ /** @defgroup Runtime_Environment Runtime Environment @{ @@ -889,7 +895,18 @@ bool do_command(THD *thd) NET *net= &thd->net; enum enum_server_command command; DBUG_ENTER("do_command"); - +#ifdef WITH_WSREP + if (WSREP(thd)) + { + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + thd->wsrep_query_state= QUERY_IDLE; + if (thd->wsrep_conflict_state==MUST_ABORT) + { + wsrep_client_rollback(thd); + } + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } +#endif /* WITH_WSREP */ /* indicator of uninitialized lex => normal flow of errors handling (see my_message_sql) @@ -937,13 +954,50 @@ bool do_command(THD *thd) thd->m_server_idle= TRUE; packet_length= my_net_read(net); thd->m_server_idle= FALSE; +#ifdef WITH_WSREP + if (WSREP(thd)) { + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + /* these THD's are aborted or are aborting during being idle */ + if (thd->wsrep_conflict_state == ABORTING) + { + while (thd->wsrep_conflict_state == ABORTING) { + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + my_sleep(1000); + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + } + thd->store_globals(); + } + else if (thd->wsrep_conflict_state == ABORTED) + { + thd->store_globals(); + } + + thd->wsrep_query_state= QUERY_EXEC; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } + + if ((WSREP(thd) && packet_length == packet_error) || + (!WSREP(thd) && (packet_length == packet_error))) +#else if (packet_length == packet_error) +#endif /* WITH_WSREP */ { DBUG_PRINT("info",("Got error %d reading command from socket %s", net->error, vio_description(net->vio))); +#ifdef WITH_WSREP + if (WSREP(thd)) { + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + if (thd->wsrep_conflict_state == MUST_ABORT) + { + DBUG_PRINT("wsrep",("aborted for wsrep rollback: %lu", thd->real_id)); + wsrep_client_rollback(thd); + } + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } +#endif /* WITH_WSREP */ /* Instrument this broken statement as "statement/com/error" */ thd->m_statement_psi= MYSQL_REFINE_STATEMENT(thd->m_statement_psi, com_statement_info[COM_END]. @@ -998,12 +1052,68 @@ bool do_command(THD *thd) vio_description(net->vio), command, command_name[command].str)); +#ifdef WITH_WSREP + if (WSREP(thd)) { + /* + * bail out if DB snapshot has not been installed. We however, + * allow queries "SET" and "SHOW", they are trapped later in execute_command + */ + if (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready && + command != COM_QUERY && + command != COM_PING && + command != COM_QUIT && + command != COM_PROCESS_INFO && + command != COM_PROCESS_KILL && + command != COM_SET_OPTION && + command != COM_SHUTDOWN && + command != COM_SLEEP && + command != COM_STATISTICS && + command != COM_TIME && + command != COM_END + ) { + my_message(ER_UNKNOWN_COM_ERROR, + "WSREP has not yet prepared node for application use", + MYF(0)); + thd->protocol->end_statement(); + return_value= FALSE; + goto out; + } + } +#endif /* WITH_WSREP */ /* Restore read timeout value */ my_net_set_read_timeout(net, thd->variables.net_read_timeout); DBUG_ASSERT(packet_length); DBUG_ASSERT(!thd->apc_target.is_enabled()); return_value= dispatch_command(command, thd, packet+1, (uint) (packet_length-1)); +#ifdef WITH_WSREP + if (WSREP(thd)) { + while (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT) + { + WSREP_DEBUG("Retry autocommit for: %s\n", thd->wsrep_retry_query); + CHARSET_INFO *current_charset = thd->variables.character_set_client; + if (!is_supported_parser_charset(current_charset)) + { + /* Do not use non-supported parser character sets */ + WSREP_WARN("Current client character set is non-supported parser " + "character set: %s", current_charset->csname); + thd->variables.character_set_client = &my_charset_latin1; + WSREP_WARN("For retry temporally setting character set to : %s", + my_charset_latin1.csname); + } + return_value= dispatch_command(command, thd, thd->wsrep_retry_query, + thd->wsrep_retry_query_len); + thd->variables.character_set_client = current_charset; + } + } + if (thd->wsrep_retry_query && thd->wsrep_conflict_state != REPLAYING) + { + my_free(thd->wsrep_retry_query); + thd->wsrep_retry_query = NULL; + thd->wsrep_retry_query_len = 0; + thd->wsrep_retry_command = COM_CONNECT; + } +#endif /* WITH_WSREP */ DBUG_ASSERT(!thd->apc_target.is_enabled()); out: @@ -1081,6 +1191,33 @@ static my_bool deny_updates_if_read_only_option(THD *thd, DBUG_RETURN(FALSE); } +#ifdef WITH_WSREP +static my_bool wsrep_read_only_option(THD *thd, TABLE_LIST *all_tables) +{ + int opt_readonly_saved = opt_readonly; + ulong flag_saved = (ulong)(thd->security_ctx->master_access & SUPER_ACL); + + opt_readonly = 0; + thd->security_ctx->master_access &= ~SUPER_ACL; + + my_bool ret = !deny_updates_if_read_only_option(thd, all_tables); + + opt_readonly = opt_readonly_saved; + thd->security_ctx->master_access |= flag_saved; + + return ret; +} + +static void wsrep_copy_query(THD *thd) +{ + thd->wsrep_retry_command = thd->get_command(); + thd->wsrep_retry_query_len = thd->query_length(); + thd->wsrep_retry_query = (char *)my_malloc( + thd->wsrep_retry_query_len + 1, MYF(0)); + strncpy(thd->wsrep_retry_query, thd->query(), thd->wsrep_retry_query_len); + thd->wsrep_retry_query[thd->wsrep_retry_query_len] = '\0'; +} +#endif /* WITH_WSREP */ /** Perform one connection-level (COM_XXXX) command. @@ -1110,6 +1247,42 @@ bool dispatch_command(enum enum_server_command command, THD *thd, DBUG_ENTER("dispatch_command"); DBUG_PRINT("info", ("command: %d", command)); +#ifdef WITH_WSREP + if (WSREP(thd)) { + if (!thd->in_multi_stmt_transaction_mode()) + { + thd->wsrep_PA_safe= true; + } + + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + thd->wsrep_query_state= QUERY_EXEC; + if (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT) + { + thd->wsrep_conflict_state= NO_CONFLICT; + } + if (thd->wsrep_conflict_state== MUST_ABORT) + { + wsrep_client_rollback(thd); + } + if (thd->wsrep_conflict_state== ABORTED) + { + my_error(ER_LOCK_DEADLOCK, MYF(0), "wsrep aborted transaction"); + WSREP_DEBUG("Deadlock error for: %s", thd->query()); + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + thd->killed = NOT_KILLED; + thd->mysys_var->abort = 0; + thd->wsrep_conflict_state = NO_CONFLICT; + thd->wsrep_retry_counter = 0; + /* + Increment threads running to compensate dec_thread_running() called + after dispatch_end label. + */ + inc_thread_running(); + goto dispatch_end; + } + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } +#endif /* WITH_WSREP */ #if defined(ENABLED_PROFILING) thd->profiling.start_new_query(); #endif @@ -1306,7 +1479,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (parser_state.init(thd, thd->query(), thd->query_length())) break; +#ifdef WITH_WSREP + wsrep_mysql_parse(thd, thd->query(), thd->query_length(), &parser_state); +#else mysql_parse(thd, thd->query(), thd->query_length(), &parser_state); +#endif /* WITH_WSREP */ while (!thd->killed && (parser_state.m_lip.found_semicolon != NULL) && ! thd->is_error()) @@ -1380,10 +1557,19 @@ bool dispatch_command(enum enum_server_command command, THD *thd, Count each statement from the client. */ statistic_increment(thd->status_var.questions, &LOCK_status); +#ifdef WITH_WSREP + if (!WSREP(thd)) + thd->set_time(); /* Reset the query start time. */ +#else thd->set_time(); /* Reset the query start time. */ +#endif /* WITH_WSREP */ parser_state.reset(beginning_of_next_stmt, length); /* TODO: set thd->lex->sql_command to SQLCOM_END here */ +#ifdef WITH_WSREP + wsrep_mysql_parse(thd, beginning_of_next_stmt, length, &parser_state); +#else mysql_parse(thd, beginning_of_next_stmt, length, &parser_state); +#endif /* WITH_WSREP */ } DBUG_PRINT("info",("query ready")); @@ -1720,6 +1906,26 @@ bool dispatch_command(enum enum_server_command command, THD *thd, my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0)); break; } +#ifdef WITH_WSREP + dispatch_end: + + if (WSREP(thd)) { + /* wsrep BF abort in query exec phase */ + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + if ((thd->wsrep_conflict_state != REPLAYING) && + (thd->wsrep_conflict_state != RETRY_AUTOCOMMIT)) + { + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + thd->update_server_status(); + thd->protocol->end_statement(); + query_cache_end_of_result(thd); + } + else + { + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } + } else { /* if (WSREP(thd))... */ +#endif /* WITH_WSREP */ DBUG_ASSERT(thd->derived_tables == NULL && (thd->open_tables == NULL || (thd->locked_tables_mode == LTM_LOCK_TABLES))); @@ -1729,6 +1935,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->update_server_status(); thd->protocol->end_statement(); query_cache_end_of_result(thd); +#ifdef WITH_WSREP + } +#endif /* WITH_WSREP */ if (!thd->is_error() && !thd->killed_errno()) mysql_audit_general(thd, MYSQL_AUDIT_GENERAL_RESULT, 0, 0); @@ -2180,6 +2389,13 @@ err: return TRUE; } +#ifdef WITH_WSREP +static bool wsrep_is_show_query(enum enum_sql_command command) +{ + DBUG_ASSERT(command >= 0 && command <= SQLCOM_END); + return (sql_command_flags[command] & CF_STATUS_COMMAND) != 0; +} +#endif /* WITH_WSREP */ /** Execute command saved in thd and lex->sql_command. @@ -2381,7 +2597,67 @@ mysql_execute_command(THD *thd) #ifdef HAVE_REPLICATION } /* endif unlikely slave */ #endif +#ifdef WITH_WSREP + if (WSREP(thd)) { + /* + change LOCK TABLE WRITE to transaction + */ + if (lex->sql_command== SQLCOM_LOCK_TABLES && wsrep_convert_LOCK_to_trx) + { + for (TABLE_LIST *table= all_tables; table; table= table->next_global) + { + if (table->lock_type >= TL_WRITE_ALLOW_WRITE) + { + lex->sql_command= SQLCOM_BEGIN; + thd->wsrep_converted_lock_session= true; + break; + } + } + } + if (lex->sql_command== SQLCOM_UNLOCK_TABLES && + thd->wsrep_converted_lock_session) + { + thd->wsrep_converted_lock_session= false; + lex->sql_command= SQLCOM_COMMIT; + lex->tx_release= TVL_NO; + } + /* + * bail out if DB snapshot has not been installed. We however, + * allow SET and SHOW queries + */ + if (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready && + lex->sql_command != SQLCOM_SET_OPTION && + !wsrep_is_show_query(lex->sql_command)) + { +#if DIRTY_HACK + /* Dirty hack for lp:1002714 - trying to recognize mysqldump connection + * and allow it to continue. Actuall mysqldump_magic_str may be longer + * and is obviously version dependent and may be issued by any client + * connection after which connection becomes non-replicating. */ + static char const mysqldump_magic_str[]= +"SELECT LOGFILE_GROUP_NAME, FILE_NAME, TOTAL_EXTENTS, INITIAL_SIZE, ENGINE, EXTRA FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'UNDO LOG' AND FILE_NAME IS NOT NULL"; + static const size_t mysqldump_magic_str_len= sizeof(mysqldump_magic_str) -1; + if (SQLCOM_SELECT != lex->sql_command || + thd->query_length() < mysqldump_magic_str_len || + strncmp(thd->query(), mysqldump_magic_str, mysqldump_magic_str_len)) + { +#endif /* DIRTY_HACK */ + my_message(ER_UNKNOWN_COM_ERROR, + "WSREP has not yet prepared node for application use", + MYF(0)); + goto error; +#if DIRTY_HACK + } + else + { + /* mysqldump connection, allow all further queries to pass */ + thd->variables.wsrep_on= FALSE; + } +#endif /* DIRTY_HACK */ + } + } +#endif /* WITH_WSREP */ status_var_increment(thd->status_var.com_stat[lex->sql_command]); thd->progress.report_to_client= MY_TEST(sql_command_flags[lex->sql_command] & CF_REPORT_PROGRESS); @@ -2423,7 +2699,13 @@ mysql_execute_command(THD *thd) { /* Commit the normal transaction if one is active. */ if (trans_commit_implicit(thd)) + { + thd->mdl_context.release_transactional_locks(); +#ifdef WITH_WSREP + WSREP_DEBUG("implicit commit failed, MDL released: %lu", thd->thread_id); +#endif /* WITH_WSREP */ goto error; + } /* Release metadata locks acquired in this transaction. */ thd->mdl_context.release_transactional_locks(); } @@ -2481,6 +2763,9 @@ mysql_execute_command(THD *thd) #endif case SQLCOM_SHOW_STATUS: { +#ifdef WITH_WSREP + if (WSREP_CLIENT(thd) && wsrep_causal_wait(thd)) goto error; +#endif /* WITH_WSREP */ execute_show_status(thd, all_tables); break; } @@ -2513,6 +2798,10 @@ mysql_execute_command(THD *thd) } case SQLCOM_SHOW_STATUS_PROC: case SQLCOM_SHOW_STATUS_FUNC: +#ifdef WITH_WSREP + if (WSREP_CLIENT(thd) && wsrep_causal_wait(thd)) goto error; +#endif /* WITH_WSREP */ + case SQLCOM_SHOW_DATABASES: case SQLCOM_SHOW_TABLES: case SQLCOM_SHOW_TRIGGERS: @@ -2521,17 +2810,27 @@ mysql_execute_command(THD *thd) case SQLCOM_SHOW_PLUGINS: case SQLCOM_SHOW_FIELDS: case SQLCOM_SHOW_KEYS: +#ifndef WITH_WSREP case SQLCOM_SHOW_VARIABLES: case SQLCOM_SHOW_CHARSETS: case SQLCOM_SHOW_COLLATIONS: case SQLCOM_SHOW_STORAGE_ENGINES: case SQLCOM_SHOW_PROFILE: +#endif /* WITH_WSREP */ case SQLCOM_SHOW_CLIENT_STATS: case SQLCOM_SHOW_USER_STATS: case SQLCOM_SHOW_TABLE_STATS: case SQLCOM_SHOW_INDEX_STATS: case SQLCOM_SELECT: - { +#ifdef WITH_WSREP + if (WSREP_CLIENT(thd) && wsrep_causal_wait(thd)) goto error; + case SQLCOM_SHOW_VARIABLES: + case SQLCOM_SHOW_CHARSETS: + case SQLCOM_SHOW_COLLATIONS: + case SQLCOM_SHOW_STORAGE_ENGINES: + case SQLCOM_SHOW_PROFILE: +#endif /* WITH_WSREP */ + { thd->status_var.last_query_cost= 0.0; /* @@ -2902,7 +3201,7 @@ case SQLCOM_PREPARE: */ if (thd->query_name_consts && mysql_bin_log.is_open() && - thd->variables.binlog_format == BINLOG_FORMAT_STMT && + WSREP_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_STMT && !mysql_bin_log.is_query_in_union(thd, thd->query_id)) { List_iterator_fast it(select_lex->item_list); @@ -3017,6 +3316,15 @@ case SQLCOM_PREPARE: } else { +#ifdef WITH_WSREP + /* in STATEMENT format, we probably have to replicate also temporary + tables, like mysql replication does + */ + if (!thd->is_current_stmt_binlog_format_row() || + !(create_info.options & HA_LEX_CREATE_TMP_TABLE)) + WSREP_TO_ISOLATION_BEGIN(create_table->db, create_table->table_name, + NULL) +#endif /* WITH_WSREP */ /* Regular CREATE TABLE */ res= mysql_create_table(thd, create_table, &create_info, &alter_info); @@ -3055,6 +3363,7 @@ end_with_restore_list: DBUG_ASSERT(first_table == all_tables && first_table != 0); if (check_one_table_access(thd, INDEX_ACL, all_tables)) goto error; /* purecov: inspected */ + WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL) /* Currently CREATE INDEX or DROP INDEX cause a full table rebuild and thus classify as slow administrative statements just like @@ -3172,6 +3481,7 @@ end_with_restore_list: #endif /* HAVE_REPLICATION */ case SQLCOM_RENAME_TABLE: { + WSREP_TO_ISOLATION_BEGIN(0, 0, first_table) if (execute_rename_table(thd, first_table, all_tables)) goto error; break; @@ -3199,6 +3509,10 @@ end_with_restore_list: goto error; #else { +#ifdef WITH_WSREP + if (WSREP_CLIENT(thd) && wsrep_causal_wait(thd)) goto error; +#endif /* WITH_WSREP */ + /* Access check: SHOW CREATE TABLE require any privileges on the table level (ie @@ -3261,6 +3575,10 @@ end_with_restore_list: case SQLCOM_CHECKSUM: { DBUG_ASSERT(first_table == all_tables && first_table != 0); +#ifdef WITH_WSREP + if (WSREP_CLIENT(thd) && wsrep_causal_wait(thd)) goto error; +#endif /* WITH_WSREP */ + if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE)) goto error; /* purecov: inspected */ @@ -3471,6 +3789,15 @@ end_with_restore_list: DBUG_ASSERT(first_table == all_tables && first_table != 0); if ((res= insert_precheck(thd, all_tables))) break; +#ifdef WITH_WSREP + if (lex->sql_command == SQLCOM_INSERT_SELECT && + thd->wsrep_consistency_check == CONSISTENCY_CHECK_DECLARED) + { + thd->wsrep_consistency_check = CONSISTENCY_CHECK_RUNNING; + WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL); + } + +#endif /* INSERT...SELECT...ON DUPLICATE KEY UPDATE/REPLACE SELECT/ INSERT...IGNORE...SELECT can be unsafe, unless ORDER BY PRIMARY KEY @@ -3687,6 +4014,18 @@ end_with_restore_list: /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */ thd->variables.option_bits|= OPTION_KEEP_LOG; } +#ifdef WITH_WSREP + for (TABLE_LIST *table= all_tables; table; table= table->next_global) + { + if (!lex->drop_temporary && + (!thd->is_current_stmt_binlog_format_row() || + !find_temporary_table(thd, table))) + { + WSREP_TO_ISOLATION_BEGIN(NULL, NULL, all_tables); + break; + } + } +#endif /* WITH_WSREP */ /* If we are a slave, we should add IF EXISTS if the query executed on the master without an error. This will help a slave to @@ -3891,6 +4230,7 @@ end_with_restore_list: #endif if (check_access(thd, CREATE_ACL, lex->name.str, NULL, NULL, 1, 0)) break; + WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL) res= mysql_create_db(thd, lex->name.str, &create_info, 0); break; } @@ -3922,6 +4262,7 @@ end_with_restore_list: #endif if (check_access(thd, DROP_ACL, lex->name.str, NULL, NULL, 1, 0)) break; + WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL) res= mysql_rm_db(thd, lex->name.str, lex->check_exists, 0); break; } @@ -3953,6 +4294,7 @@ end_with_restore_list: res= 1; break; } + WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL) res= mysql_upgrade_db(thd, db); if (!res) my_ok(thd); @@ -3988,6 +4330,7 @@ end_with_restore_list: #endif if (check_access(thd, ALTER_ACL, db->str, NULL, NULL, 1, 0)) break; + WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL) res= mysql_alter_db(thd, db->str, &create_info); break; } @@ -4026,6 +4369,7 @@ end_with_restore_list: if (res) break; + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) switch (lex->sql_command) { case SQLCOM_CREATE_EVENT: { @@ -4060,6 +4404,7 @@ end_with_restore_list: lex->spname->m_name); break; case SQLCOM_DROP_EVENT: + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) if (!(res= Events::drop_event(thd, lex->spname->m_db, lex->spname->m_name, lex->check_exists))) @@ -4074,6 +4419,7 @@ end_with_restore_list: if (check_access(thd, INSERT_ACL, "mysql", NULL, NULL, 1, 0)) break; #ifdef HAVE_DLOPEN + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) if (!(res = mysql_create_function(thd, &lex->udf))) my_ok(thd); #else @@ -4089,6 +4435,7 @@ end_with_restore_list: if (check_access(thd, INSERT_ACL, "mysql", NULL, NULL, 1, 1) && check_global_access(thd,CREATE_USER_ACL)) break; + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) /* Conditionally writes to binlog */ if (!(res= mysql_create_user(thd, lex->users_list, lex->sql_command == SQLCOM_CREATE_ROLE))) @@ -4102,6 +4449,7 @@ end_with_restore_list: check_global_access(thd,CREATE_USER_ACL)) break; /* Conditionally writes to binlog */ + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) if (!(res= mysql_drop_user(thd, lex->users_list, lex->sql_command == SQLCOM_DROP_ROLE))) my_ok(thd); @@ -4113,6 +4461,7 @@ end_with_restore_list: check_global_access(thd,CREATE_USER_ACL)) break; /* Conditionally writes to binlog */ + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) if (!(res= mysql_rename_user(thd, lex->users_list))) my_ok(thd); break; @@ -4124,6 +4473,7 @@ end_with_restore_list: break; /* Conditionally writes to binlog */ + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) if (!(res = mysql_revoke_all(thd, lex->users_list))) my_ok(thd); break; @@ -4206,6 +4556,7 @@ end_with_restore_list: lex->type == TYPE_ENUM_PROCEDURE, 0)) goto error; /* Conditionally writes to binlog */ + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) res= mysql_routine_grant(thd, all_tables, lex->type == TYPE_ENUM_PROCEDURE, lex->users_list, grants, @@ -4219,6 +4570,7 @@ end_with_restore_list: all_tables, FALSE, UINT_MAX, FALSE)) goto error; /* Conditionally writes to binlog */ + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) res= mysql_table_grant(thd, all_tables, lex->users_list, lex->columns, lex->grant, lex->sql_command == SQLCOM_REVOKE); @@ -4234,6 +4586,7 @@ end_with_restore_list: } else { + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) /* Conditionally writes to binlog */ res= mysql_grant(thd, select_lex->db, lex->users_list, lex->grant, lex->sql_command == SQLCOM_REVOKE, @@ -4402,15 +4755,29 @@ end_with_restore_list: able to open it (with SQLCOM_HA_OPEN) in the first place. */ unit->set_limit(select_lex); +#ifdef WITH_WSREP + { char* tmp_info= NULL; + if (WSREP(thd)) tmp_info = (char *)thd_proc_info(thd, "mysql_ha_read()"); +#endif /* WITH_WSREP */ res= mysql_ha_read(thd, first_table, lex->ha_read_mode, lex->ident.str, lex->insert_list, lex->ha_rkey_mode, select_lex->where, unit->select_limit_cnt, unit->offset_limit_cnt); +#ifdef WITH_WSREP + if (WSREP(thd)) thd_proc_info(thd, tmp_info); + } +#endif /* WITH_WSREP */ break; case SQLCOM_BEGIN: DBUG_PRINT("info", ("Executing SQLCOM_BEGIN thd: %p", thd)); if (trans_begin(thd, lex->start_transaction_opt)) + { + thd->mdl_context.release_transactional_locks(); +#ifdef WITH_WSREP + WSREP_DEBUG("BEGIN failed, MDL released: %lu", thd->thread_id); +#endif /* WITH_WSREP */ goto error; + } my_ok(thd); break; case SQLCOM_COMMIT: @@ -4424,7 +4791,13 @@ end_with_restore_list: (thd->variables.completion_type == 2 && lex->tx_release != TVL_NO)); if (trans_commit(thd)) + { + thd->mdl_context.release_transactional_locks(); +#ifdef WITH_WSREP + WSREP_DEBUG("COMMIT failed, MDL released: %lu", thd->thread_id); +#endif /* WITH_WSREP */ goto error; + } thd->mdl_context.release_transactional_locks(); /* Begin transaction with the same isolation level. */ if (tx_chain) @@ -4444,7 +4817,20 @@ end_with_restore_list: thd->killed= KILL_CONNECTION; thd->print_aborted_warning(3, "RELEASE"); } +#ifdef WITH_WSREP + if (WSREP(thd)) { + + if (thd->wsrep_conflict_state == NO_CONFLICT || + thd->wsrep_conflict_state == REPLAYING) + { + my_ok(thd); + } + } else { +#endif /* WITH_WSREP */ my_ok(thd); +#ifdef WITH_WSREP + } +#endif /* WITH_WSREP */ break; } case SQLCOM_ROLLBACK: @@ -4459,7 +4845,13 @@ end_with_restore_list: lex->tx_release != TVL_NO)); if (trans_rollback(thd)) + { + thd->mdl_context.release_transactional_locks(); +#ifdef WITH_WSREP + WSREP_DEBUG("rollback failed, MDL released: %lu", thd->thread_id); +#endif /* WITH_WSREP */ goto error; + } thd->mdl_context.release_transactional_locks(); /* Begin transaction with the same isolation level. */ if (tx_chain) @@ -4476,8 +4868,18 @@ end_with_restore_list: /* Disconnect the current client connection. */ if (tx_release) thd->killed= KILL_CONNECTION; - my_ok(thd); - break; +#ifdef WITH_WSREP + if (WSREP(thd)) { + if (thd->wsrep_conflict_state == NO_CONFLICT) { + my_ok(thd); + } + } else { +#endif /* WITH_WSREP */ + my_ok(thd); +#ifdef WITH_WSREP + } +#endif /* WITH_WSREP */ + break; } case SQLCOM_RELEASE_SAVEPOINT: if (trans_release_savepoint(thd, lex->ident)) @@ -4545,6 +4947,7 @@ end_with_restore_list: if (sp_process_definer(thd)) goto create_sp_error; + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) res= (sp_result= sp_create_routine(thd, lex->sphead->m_type, lex->sphead)); switch (sp_result) { case SP_OK: { @@ -4826,6 +5229,7 @@ create_sp_error: if (check_routine_access(thd, ALTER_PROC_ACL, db, name, lex->sql_command == SQLCOM_DROP_PROCEDURE, 0)) goto error; + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) /* Conditionally writes to binlog */ sp_result= sp_drop_routine(thd, type, lex->spname); @@ -4943,6 +5347,7 @@ create_sp_error: Note: SQLCOM_CREATE_VIEW also handles 'ALTER VIEW' commands as specified through the thd->lex->create_view_mode flag. */ + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) res= mysql_create_view(thd, first_table, thd->lex->create_view_mode); break; } @@ -4951,12 +5356,14 @@ create_sp_error: if (check_table_access(thd, DROP_ACL, all_tables, FALSE, UINT_MAX, FALSE)) goto error; /* Conditionally writes to binlog. */ + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) res= mysql_drop_view(thd, first_table, thd->lex->drop_mode); break; } case SQLCOM_CREATE_TRIGGER: { /* Conditionally writes to binlog. */ + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) res= mysql_create_or_drop_trigger(thd, all_tables, 1); break; @@ -4964,6 +5371,7 @@ create_sp_error: case SQLCOM_DROP_TRIGGER: { /* Conditionally writes to binlog. */ + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) res= mysql_create_or_drop_trigger(thd, all_tables, 0); break; } @@ -4984,7 +5392,13 @@ create_sp_error: break; case SQLCOM_XA_COMMIT: if (trans_xa_commit(thd)) + { + thd->mdl_context.release_transactional_locks(); +#ifdef WITH_WSREP + WSREP_DEBUG("XA commit failed, MDL released: %lu", thd->thread_id); +#endif /* WITH_WSREP */ goto error; + } thd->mdl_context.release_transactional_locks(); /* We've just done a commit, reset transaction @@ -4996,7 +5410,13 @@ create_sp_error: break; case SQLCOM_XA_ROLLBACK: if (trans_xa_rollback(thd)) + { + thd->mdl_context.release_transactional_locks(); +#ifdef WITH_WSREP + WSREP_DEBUG("XA rollback failed, MDL released: %lu", thd->thread_id); +#endif /* WITH_WSREP */ goto error; + } thd->mdl_context.release_transactional_locks(); /* We've just done a rollback, reset transaction @@ -5016,11 +5436,13 @@ create_sp_error: my_ok(thd); break; case SQLCOM_INSTALL_PLUGIN: + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) if (! (res= mysql_install_plugin(thd, &thd->lex->comment, &thd->lex->ident))) my_ok(thd); break; case SQLCOM_UNINSTALL_PLUGIN: + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) if (! (res= mysql_uninstall_plugin(thd, &thd->lex->comment, &thd->lex->ident))) my_ok(thd); @@ -5169,6 +5591,9 @@ finish: /* Free tables */ close_thread_tables(thd); +#ifdef WITH_WSREP + thd->wsrep_consistency_check= NO_CONSISTENCY_CHECK; +#endif /* WITH_WSREP */ #ifndef DBUG_OFF if (lex->sql_command != SQLCOM_SET_OPTION && ! thd->in_sub_stmt) @@ -5222,6 +5647,22 @@ finish: { thd->mdl_context.release_statement_locks(); } + WSREP_TO_ISOLATION_END; + +#ifdef WITH_WSREP + /* + Force release of transactional locks if not in active MST and wsrep is on. + */ + if (WSREP(thd) && + ! thd->in_sub_stmt && + ! thd->in_active_multi_stmt_transaction() && + thd->mdl_context.has_transactional_locks()) + { + WSREP_DEBUG("Forcing release of transactional locks for thd %lu", + thd->thread_id); + thd->mdl_context.release_transactional_locks(); + } +#endif /* WITH_WSREP */ DBUG_RETURN(res || thd->is_error()); } @@ -5322,6 +5763,9 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables) status_var_increment(thd->status_var.empty_queries); else status_var_add(thd->status_var.rows_sent, thd->get_sent_row_count()); +#ifdef WITH_WSREP + if (lex->sql_command == SQLCOM_SHOW_STATUS) wsrep_free_status(thd); +#endif /* WITH_WSREP */ return res; } @@ -6160,6 +6604,26 @@ void THD::reset_for_next_command() thd->auto_inc_intervals_in_cur_stmt_for_binlog.empty(); thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0; +#ifdef WITH_WSREP + /* + Autoinc variables should be adjusted only for locally executed + transactions. Appliers and replayers are either processing ROW + events or get autoinc variable values from Query_log_event. + */ + if (WSREP(thd) && thd->wsrep_exec_mode == LOCAL_STATE) { + if (wsrep_auto_increment_control) + { + if (thd->variables.auto_increment_offset != + global_system_variables.auto_increment_offset) + thd->variables.auto_increment_offset= + global_system_variables.auto_increment_offset; + if (thd->variables.auto_increment_increment != + global_system_variables.auto_increment_increment) + thd->variables.auto_increment_increment= + global_system_variables.auto_increment_increment; + } + } +#endif /* WITH_WSREP */ thd->query_start_used= 0; thd->query_start_sec_part_used= 0; thd->is_fatal_error= thd->time_zone_used= 0; @@ -6363,6 +6827,109 @@ void mysql_init_multi_delete(LEX *lex) lex->query_tables_last= &lex->query_tables; } +#ifdef WITH_WSREP +static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length, + Parser_state *parser_state) +{ + bool is_autocommit= + !thd->in_multi_stmt_transaction_mode() && + thd->wsrep_conflict_state == NO_CONFLICT && + !thd->wsrep_applier && + wsrep_read_only_option(thd, thd->lex->query_tables); + + do + { + if (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT) + { + thd->wsrep_conflict_state= NO_CONFLICT; + /* Performance Schema Interface instrumentation, begin */ + thd->m_statement_psi= MYSQL_REFINE_STATEMENT(thd->m_statement_psi, + com_statement_info[thd->get_command()].m_key); + MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, thd->query(), + thd->query_length()); + } + mysql_parse(thd, rawbuf, length, parser_state); + + if (WSREP(thd)) { + /* wsrep BF abort in query exec phase */ + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + if (thd->wsrep_conflict_state == MUST_ABORT) { + wsrep_client_rollback(thd); + + WSREP_DEBUG("abort in exec query state, avoiding autocommit"); + } + + if (thd->wsrep_conflict_state== MUST_REPLAY) + { + wsrep_replay_transaction(thd); + } + + /* setting error code for BF aborted trxs */ + if (thd->wsrep_conflict_state == ABORTED || + thd->wsrep_conflict_state == CERT_FAILURE) + { + mysql_reset_thd_for_next_command(thd); + thd->killed= NOT_KILLED; + if (is_autocommit && + thd->lex->sql_command != SQLCOM_SELECT && + (thd->wsrep_retry_counter < thd->variables.wsrep_retry_autocommit)) + { + WSREP_DEBUG("wsrep retrying AC query: %s", + (thd->query()) ? thd->query() : "void"); + + /* Performance Schema Interface instrumentation, end */ + MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da()); + thd->m_statement_psi= NULL; + close_thread_tables(thd); + + thd->wsrep_conflict_state= RETRY_AUTOCOMMIT; + thd->wsrep_retry_counter++; // grow + wsrep_copy_query(thd); + thd->set_time(); + parser_state->reset(rawbuf, length); + } + else + { + WSREP_DEBUG("%s, thd: %lu is_AC: %d, retry: %lu - %lu SQL: %s", + (thd->wsrep_conflict_state == ABORTED) ? + "BF Aborted" : "cert failure", + thd->thread_id, is_autocommit, thd->wsrep_retry_counter, + thd->variables.wsrep_retry_autocommit, thd->query()); + my_error(ER_LOCK_DEADLOCK, MYF(0), "wsrep aborted transaction"); + thd->killed= NOT_KILLED; + thd->wsrep_conflict_state= NO_CONFLICT; + if (thd->wsrep_conflict_state != REPLAYING) + thd->wsrep_retry_counter= 0; // reset + } + } + else + { + set_if_smaller(thd->wsrep_retry_counter, 0); // reset; eventually ok + } + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } + + /* If retry is requested clean up explain structure */ + if (thd->wsrep_conflict_state == RETRY_AUTOCOMMIT && thd->lex->explain) + delete_explain_query(thd->lex); + + } while (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT); + + if (thd->wsrep_retry_query) + { + WSREP_DEBUG("releasing retry_query: conf %d sent %d kill %d errno %d SQL %s", + thd->wsrep_conflict_state, + thd->get_stmt_da()->is_sent(), + thd->killed, + thd->get_stmt_da()->is_error() ? thd->get_stmt_da()->sql_errno() : 0, + thd->wsrep_retry_query); + my_free(thd->wsrep_retry_query); + thd->wsrep_retry_query = NULL; + thd->wsrep_retry_query_len = 0; + thd->wsrep_retry_command = COM_CONNECT; + } +} +#endif /* WITH_WSREP */ /* When you modify mysql_parse(), you may need to mofify @@ -7392,8 +7959,14 @@ kill_one_thread(THD *thd, longlong id, killed_state kill_signal, killed_type typ faster and do a harder kill than KILL_SYSTEM_THREAD; */ +#ifdef WITH_WSREP + if (((thd->security_ctx->master_access & SUPER_ACL) || + thd->security_ctx->user_matches(tmp->security_ctx)) && + !wsrep_thd_is_BF((void *)tmp, true)) +#else if ((thd->security_ctx->master_access & SUPER_ACL) || thd->security_ctx->user_matches(tmp->security_ctx)) +#endif /* WITH_WSREP */ { tmp->awake(kill_signal); error=0; diff --git a/sql/sql_parse.h b/sql/sql_parse.h index 926a4d800ad..773ede9edee 100644 --- a/sql/sql_parse.h +++ b/sql/sql_parse.h @@ -202,6 +202,22 @@ inline bool is_supported_parser_charset(CHARSET_INFO *cs) { return MY_TEST(cs->mbminlen == 1); } +#ifdef WITH_WSREP + +#define WSREP_MYSQL_DB (char *)"mysql" +#define WSREP_TO_ISOLATION_BEGIN(db_, table_, table_list_) \ + if (WSREP(thd) && wsrep_to_isolation_begin(thd, db_, table_, table_list_)) goto error; + +#define WSREP_TO_ISOLATION_END \ + if (WSREP(thd) || (thd && thd->wsrep_exec_mode==TOTAL_ORDER)) \ + wsrep_to_isolation_end(thd); + +#else + +#define WSREP_TO_ISOLATION_BEGIN(db_, table_, table_list_) +#define WSREP_TO_ISOLATION_END + +#endif /* WITH_WSREP */ #endif /* SQL_PARSE_INCLUDED */ diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc index 8c59febeb77..ac67291fbd1 100644 --- a/sql/sql_partition_admin.cc +++ b/sql/sql_partition_admin.cc @@ -763,6 +763,19 @@ bool Sql_cmd_alter_table_truncate_partition::execute(THD *thd) if (check_one_table_access(thd, DROP_ACL, first_table)) DBUG_RETURN(TRUE); +#ifdef WITH_WSREP + TABLE *find_temporary_table(THD *thd, const TABLE_LIST *tl); + + if ((!thd->is_current_stmt_binlog_format_row() || + !find_temporary_table(thd, first_table)) && + wsrep_to_isolation_begin( + thd, first_table->db, first_table->table_name, NULL) + ) + { + WSREP_WARN("ALTER TABLE isolation failure"); + DBUG_RETURN(TRUE); + } +#endif /* WITH_WSREP */ if (open_tables(thd, &first_table, &table_counter, 0)) DBUG_RETURN(true); diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index b2dd38ad720..3ebed0643a5 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -3087,6 +3087,9 @@ void plugin_thdvar_init(THD *thd) thd->variables.dynamic_variables_size= 0; thd->variables.dynamic_variables_ptr= 0; +#ifdef WITH_WSREP + if (!WSREP(thd) || !thd->wsrep_applier) { +#endif mysql_mutex_lock(&LOCK_plugin); thd->variables.table_plugin= intern_plugin_lock(NULL, global_system_variables.table_plugin); @@ -3096,6 +3099,9 @@ void plugin_thdvar_init(THD *thd) intern_plugin_unlock(NULL, old_table_plugin); intern_plugin_unlock(NULL, old_tmp_table_plugin); mysql_mutex_unlock(&LOCK_plugin); +#ifdef WITH_WSREP + } +#endif DBUG_VOID_RETURN; } diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index ebceae70ee5..8a6de8b6693 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -3547,7 +3547,9 @@ Prepared_statement::set_parameters(String *expanded_query, return res; } - +#ifdef WITH_WSREP +void wsrep_replay_transaction(THD *thd); +#endif /* WITH_WSREP */ /** Execute a prepared statement. Re-prepare it a limited number of times if necessary. @@ -3626,6 +3628,22 @@ reexecute: error= execute(expanded_query, open_cursor) || thd->is_error(); thd->m_reprepare_observer= NULL; +#ifdef WITH_WSREP + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + switch (thd->wsrep_conflict_state) + { + case CERT_FAILURE: + WSREP_DEBUG("PS execute fail for CERT_FAILURE: thd: %ld err: %d", + thd->thread_id, thd->get_stmt_da()->sql_errno() ); + thd->wsrep_conflict_state = NO_CONFLICT; + break; + + case MUST_REPLAY: + (void)wsrep_replay_transaction(thd); + default: break; + } + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); +#endif /* WITH_WSREP */ if ((sql_command_flags[lex->sql_command] & CF_REEXECUTION_FRAGILE) && error && !thd->is_fatal_error && !thd->killed && diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc index bb3d5bb899a..f1f9ba9452f 100644 --- a/sql/sql_reload.cc +++ b/sql/sql_reload.cc @@ -253,7 +253,18 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options, } if (options & REFRESH_CHECKPOINT) disable_checkpoints(thd); - } +#ifdef WITH_WSREP + /* + We need to do it second time after wsrep appliers were blocked in + make_global_read_lock_block_commit(thd) above since they could have + modified the tables too. + */ + if (WSREP(thd) && + close_cached_tables(thd, tables, (options & REFRESH_FAST) ? + FALSE : TRUE, TRUE)) + result= 1; +#endif /* WITH_WSREP */ + } else { if (thd && thd->locked_tables_mode) diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index c7bd28259ae..eaed0660e46 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -2947,6 +2947,15 @@ int start_slave(THD* thd , Master_info* mi, bool net_report) err: unlock_slave_threads(mi); +#ifdef WITH_WSREP + if (WSREP(thd)) + thd_proc_info(thd, "exit stop_slave()"); + else + thd_proc_info(thd, 0); +#else /* WITH_WSREP */ + thd_proc_info(thd, 0); +#endif /* WITH_WSREP */ + if (slave_errno) { if (net_report) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 79c444ea442..25c005539af 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2931,11 +2931,39 @@ static bool show_status_array(THD *thd, const char *wild, *prefix_end++= '_'; len=name_buffer + sizeof(name_buffer) - prefix_end; +#ifdef WITH_WSREP + bool is_wsrep_var= FALSE; + /* + This is a workaround for lp:1306875 (PBX) to skip switching of wsrep + status variable name's first letter to uppercase. This is an optimization + for status variables defined under wsrep plugin. + TODO: remove once lp:1306875 has been addressed. + */ + if (*prefix && !my_strcasecmp(system_charset_info, prefix, "wsrep")) + { + is_wsrep_var= TRUE; + } +#endif /* WITH_WSREP */ + for (; variables->name; variables++) { bool wild_checked; strnmov(prefix_end, variables->name, len); name_buffer[sizeof(name_buffer)-1]=0; /* Safety */ + +#ifdef WITH_WSREP + /* + If the prefix is NULL, that means we are looking into the status variables + defined directly under mysqld.cc. Do not capitalize wsrep status variable + names until lp:1306875 has been fixed. + TODO: remove once lp:1306875 has been addressed. + */ + if (!(*prefix) && !strncasecmp(name_buffer, "wsrep", strlen("wsrep"))) + { + is_wsrep_var= TRUE; + } +#endif /* WITH_WSREP */ + if (ucase_names) my_caseup_str(system_charset_info, name_buffer); else @@ -2944,8 +2972,13 @@ static bool show_status_array(THD *thd, const char *wild, DBUG_ASSERT(name_buffer[0] >= 'a'); DBUG_ASSERT(name_buffer[0] <= 'z'); +#ifdef WITH_WSREP + // TODO: remove once lp:1306875 has been addressed. + if (status_var && (is_wsrep_var == FALSE)) +#else /* traditionally status variables have a first letter uppercased */ if (status_var) +#endif /* WITH_WSREP */ name_buffer[0]-= 'a' - 'A'; } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 80ac0978834..e632a65b636 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5264,6 +5264,61 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, int create_res; DBUG_ENTER("mysql_create_like_table"); +#ifdef WITH_WSREP + if (WSREP(thd) && !thd->wsrep_applier) + { + TABLE *tmp_table; + bool is_tmp_table= FALSE; + + for (tmp_table= thd->temporary_tables; tmp_table; tmp_table=tmp_table->next) + { + if (!strcmp(src_table->db, tmp_table->s->db.str) && + !strcmp(src_table->table_name, tmp_table->s->table_name.str)) + { + is_tmp_table= TRUE; + break; + } + } + if (create_info->options & HA_LEX_CREATE_TMP_TABLE) + { + /* CREATE TEMPORARY TABLE LIKE must be skipped from replication */ + WSREP_DEBUG("CREATE TEMPORARY TABLE LIKE... skipped replication\n %s", + thd->query()); + } + else if (!is_tmp_table) + { + /* this is straight CREATE TABLE LIKE... eith no tmp tables */ + WSREP_TO_ISOLATION_BEGIN(table->db, table->table_name, NULL); + } + else + { + /* here we have CREATE TABLE LIKE + the temporary table definition will be needed in slaves to + enable the create to succeed + */ + TABLE_LIST tbl; + bzero((void*) &tbl, sizeof(tbl)); + tbl.db= src_table->db; + tbl.table_name= tbl.alias= src_table->table_name; + tbl.table= tmp_table; + char buf[2048]; + String query(buf, sizeof(buf), system_charset_info); + query.length(0); // Have to zero it since constructor doesn't + + (void) store_create_info(thd, &tbl, &query, NULL, TRUE, FALSE); + WSREP_DEBUG("TMP TABLE: %s", query.ptr()); + + thd->wsrep_TOI_pre_query= query.ptr(); + thd->wsrep_TOI_pre_query_len= query.length(); + + WSREP_TO_ISOLATION_BEGIN(table->db, table->table_name, NULL); + + thd->wsrep_TOI_pre_query= NULL; + thd->wsrep_TOI_pre_query_len= 0; + } + } +#endif + /* We the open source table to get its description in HA_CREATE_INFO and Alter_info objects. This also acquires a shared metadata lock @@ -5526,6 +5581,13 @@ err: res= 1; } DBUG_RETURN(res); + +#ifdef WITH_WSREP + error: + thd->wsrep_TOI_pre_query= NULL; + DBUG_RETURN(TRUE); +#endif /* WITH_WSREP */ + } @@ -8057,6 +8119,10 @@ simple_rename_or_index_change(THD *thd, TABLE_LIST *table_list, : HA_EXTRA_FORCE_REOPEN; DBUG_ENTER("simple_rename_or_index_change"); +#ifdef WITH_WSREP + bool do_log_write(true); +#endif /* WITH_WSREP */ + if (keys_onoff != Alter_info::LEAVE_AS_IS) { if (wait_while_table_is_used(thd, table, extra_func)) @@ -8116,7 +8182,14 @@ simple_rename_or_index_change(THD *thd, TABLE_LIST *table_list, if (!error) { - error= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); +#ifdef WITH_WSREP + if (!WSREP(thd) || do_log_write) { +#endif /* WITH_WSREP */ + error= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); +#ifdef WITH_WSREP + } +#endif /* !WITH_WSREP */ + if (!error) my_ok(thd); } diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 70ac6265046..c3188305092 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -434,8 +434,14 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) binlogged, so they share the same danger, so trust_function_creators applies to them too. */ +#ifdef WITH_WSREP + if (!trust_function_creators && + (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) && + !(thd->security_ctx->master_access & SUPER_ACL)) +#else if (!trust_function_creators && mysql_bin_log.is_open() && !(thd->security_ctx->master_access & SUPER_ACL)) +#endif /* WITH_WSREP */ { my_error(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER, MYF(0)); DBUG_RETURN(TRUE); @@ -2437,3 +2443,55 @@ bool load_table_name_for_trigger(THD *thd, DBUG_RETURN(FALSE); } +#ifdef WITH_WSREP +int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len) +{ + LEX *lex= thd->lex; + String stmt_query; + + LEX_STRING definer_user; + LEX_STRING definer_host; + + if (!lex->definer) + { + if (!thd->slave_thread) + { + if (!(lex->definer= create_default_definer(thd, false))) + return 1; + } + } + + if (lex->definer) + { + /* SUID trigger. */ + + definer_user= lex->definer->user; + definer_host= lex->definer->host; + } + else + { + /* non-SUID trigger. */ + + definer_user.str= 0; + definer_user.length= 0; + + definer_host.str= 0; + definer_host.length= 0; + } + + stmt_query.append(STRING_WITH_LEN("CREATE ")); + + append_definer(thd, &stmt_query, &definer_user, &definer_host); + + LEX_STRING stmt_definition; + stmt_definition.str= (char*) thd->lex->stmt_definition_begin; + stmt_definition.length= thd->lex->stmt_definition_end + - thd->lex->stmt_definition_begin; + trim_whitespace(thd->charset(), & stmt_definition); + + stmt_query.append(stmt_definition.str, stmt_definition.length); + + return wsrep_to_buf_helper(thd, stmt_query.c_ptr(), stmt_query.length(), + buf, buf_len); +} +#endif /* WITH_WSREP */ diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc index e98679b1d51..8046405a4b4 100644 --- a/sql/sql_truncate.cc +++ b/sql/sql_truncate.cc @@ -24,6 +24,9 @@ #include "sql_acl.h" // DROP_ACL #include "sql_parse.h" // check_one_table_access() #include "sql_truncate.h" +#ifdef WITH_WSREP +#include "wsrep_mysqld.h" +#endif /* WITH_WSREP */ #include "sql_show.h" //append_identifier() @@ -411,6 +414,12 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref) { bool hton_can_recreate; +#ifdef WITH_WSREP + if (WSREP(thd) && wsrep_to_isolation_begin(thd, + table_ref->db, + table_ref->table_name, NULL)) + DBUG_RETURN(TRUE); +#endif /* WITH_WSREP */ if (lock_table(thd, table_ref, &hton_can_recreate)) DBUG_RETURN(TRUE); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index faf8e4c61d2..58d04674033 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -976,7 +976,11 @@ int mysql_update(THD *thd, */ if ((error < 0) || thd->transaction.stmt.modified_non_trans_table) { +#ifdef WITH_WSREP + if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) +#else if (mysql_bin_log.is_open()) +#endif { int errcode= 0; if (error < 0) @@ -2219,7 +2223,11 @@ void multi_update::abort_result_set() The query has to binlog because there's a modified non-transactional table either from the query's list or via a stored routine: bug#13270,23333 */ +#ifdef WITH_WSREP + if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) +#else if (mysql_bin_log.is_open()) +#endif { /* THD::killed status might not have been set ON at time of an error @@ -2488,7 +2496,11 @@ bool multi_update::send_eof() if (local_error == 0 || thd->transaction.stmt.modified_non_trans_table) { +#ifdef WITH_WSREP + if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) +#else if (mysql_bin_log.is_open()) +#endif { int errcode= 0; if (local_error == 0) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index a261d611aa6..a06d702f620 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7156,7 +7156,7 @@ alter: } view_tail {} - | ALTER definer_opt EVENT_SYM sp_name + | ALTER definer_opt remember_name EVENT_SYM sp_name { /* It is safe to use Lex->spname because @@ -7168,9 +7168,12 @@ alter: if (!(Lex->event_parse_data= Event_parse_data::new_instance(thd))) MYSQL_YYABORT; - Lex->event_parse_data->identifier= $4; + Lex->event_parse_data->identifier= $5; Lex->sql_command= SQLCOM_ALTER_EVENT; +#ifdef WITH_WSREP + Lex->stmt_definition_begin= $3; +#endif } ev_alter_on_schedule_completion opt_ev_rename_to @@ -7178,7 +7181,7 @@ alter: opt_ev_comment opt_ev_sql_stmt { - if (!($6 || $7 || $8 || $9 || $10)) + if (!($7 || $8 || $9 || $10 || $11)) { my_parse_error(ER(ER_SYNTAX_ERROR)); MYSQL_YYABORT; @@ -7188,6 +7191,9 @@ alter: can overwrite it */ Lex->sql_command= SQLCOM_ALTER_EVENT; +#ifdef WITH_WSREP + Lex->stmt_definition_end= (char*)YYLIP->get_cpp_ptr(); +#endif } | ALTER TABLESPACE alter_tablespace_info { diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 9495d16247d..1bf972d2c55 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -465,6 +465,26 @@ static bool binlog_format_check(sys_var *self, THD *thd, set_var *var) ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT)) return true; +#ifdef WITH_WSREP + /* MariaDB Galera does not support STATEMENT or MIXED binlog + format currently */ + if (WSREP(thd) && + (var->save_result.ulonglong_value == BINLOG_FORMAT_STMT || + var->save_result.ulonglong_value == BINLOG_FORMAT_MIXED)) + { + WSREP_DEBUG("MariaDB Galera does not support binlog format : %s", + var->save_result.ulonglong_value == BINLOG_FORMAT_STMT ? + "STATEMENT" : "MIXED"); + /* Push also warning, because error message is general */ + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + ER_UNKNOWN_ERROR, + "MariaDB Galera does not support binlog format: %s", + var->save_result.ulonglong_value == BINLOG_FORMAT_STMT ? + "STATEMENT" : "MIXED"); + return true; + } +#endif + return false; } @@ -3317,6 +3337,10 @@ static bool fix_autocommit(sys_var *self, THD *thd, enum_var_type type) if (trans_commit_stmt(thd) || trans_commit(thd)) { thd->variables.option_bits&= ~OPTION_AUTOCOMMIT; + thd->mdl_context.release_transactional_locks(); +#ifdef WITH_WSREP + WSREP_DEBUG("autocommit, MDL TRX lock released: %lu", thd->thread_id); +#endif /* WITH_WSREP */ return true; } /* @@ -4412,6 +4436,257 @@ static Sys_var_tz Sys_time_zone( SESSION_VAR(time_zone), NO_CMD_LINE, DEFAULT(&default_tz), NO_MUTEX_GUARD, IN_BINLOG); +#ifdef WITH_WSREP +#include "wsrep_var.h" +#include "wsrep_sst.h" +#include "wsrep_binlog.h" + +static Sys_var_charptr Sys_wsrep_provider( + "wsrep_provider", "Path to replication provider library", + PREALLOCATED GLOBAL_VAR(wsrep_provider), CMD_LINE(REQUIRED_ARG, OPT_WSREP_PROVIDER), + IN_FS_CHARSET, DEFAULT(WSREP_NONE), + NO_MUTEX_GUARD, NOT_IN_BINLOG, + ON_CHECK(wsrep_provider_check), ON_UPDATE(wsrep_provider_update)); + +static Sys_var_charptr Sys_wsrep_provider_options( + "wsrep_provider_options", "provider specific options", + PREALLOCATED GLOBAL_VAR(wsrep_provider_options), + CMD_LINE(REQUIRED_ARG, OPT_WSREP_PROVIDER_OPTIONS), + IN_FS_CHARSET, DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG, + ON_CHECK(wsrep_provider_options_check), + ON_UPDATE(wsrep_provider_options_update)); + +static Sys_var_charptr Sys_wsrep_data_home_dir( + "wsrep_data_home_dir", "home directory for wsrep provider", + READ_ONLY GLOBAL_VAR(wsrep_data_home_dir), CMD_LINE(REQUIRED_ARG), + IN_FS_CHARSET, DEFAULT(""), + NO_MUTEX_GUARD, NOT_IN_BINLOG); + +static Sys_var_charptr Sys_wsrep_cluster_name( + "wsrep_cluster_name", "Name for the cluster", + PREALLOCATED GLOBAL_VAR(wsrep_cluster_name), CMD_LINE(REQUIRED_ARG), + IN_FS_CHARSET, DEFAULT(WSREP_CLUSTER_NAME), + NO_MUTEX_GUARD, NOT_IN_BINLOG, + ON_CHECK(wsrep_cluster_name_check), + ON_UPDATE(wsrep_cluster_name_update)); + +static PolyLock_mutex PLock_wsrep_slave_threads(&LOCK_wsrep_slave_threads); +static Sys_var_charptr Sys_wsrep_cluster_address ( + "wsrep_cluster_address", "Address to initially connect to cluster", + PREALLOCATED GLOBAL_VAR(wsrep_cluster_address), + CMD_LINE(REQUIRED_ARG, OPT_WSREP_CLUSTER_ADDRESS), + IN_FS_CHARSET, DEFAULT(""), + &PLock_wsrep_slave_threads, NOT_IN_BINLOG, + ON_CHECK(wsrep_cluster_address_check), + ON_UPDATE(wsrep_cluster_address_update)); + +static Sys_var_charptr Sys_wsrep_node_name ( + "wsrep_node_name", "Node name", + PREALLOCATED GLOBAL_VAR(wsrep_node_name), CMD_LINE(REQUIRED_ARG), + IN_FS_CHARSET, DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG, + wsrep_node_name_check, wsrep_node_name_update); + +static Sys_var_charptr Sys_wsrep_node_address ( + "wsrep_node_address", "Node address", + PREALLOCATED GLOBAL_VAR(wsrep_node_address), CMD_LINE(REQUIRED_ARG), + IN_FS_CHARSET, DEFAULT(""), + NO_MUTEX_GUARD, NOT_IN_BINLOG, + ON_CHECK(wsrep_node_address_check), + ON_UPDATE(wsrep_node_address_update)); + +static Sys_var_charptr Sys_wsrep_node_incoming_address( + "wsrep_node_incoming_address", "Client connection address", + PREALLOCATED GLOBAL_VAR(wsrep_node_incoming_address),CMD_LINE(REQUIRED_ARG), + IN_FS_CHARSET, DEFAULT(WSREP_NODE_INCOMING_AUTO), + NO_MUTEX_GUARD, NOT_IN_BINLOG); + +static Sys_var_ulong Sys_wsrep_slave_threads( + "wsrep_slave_threads", "Number of slave appliers to launch", + GLOBAL_VAR(wsrep_slave_threads), CMD_LINE(REQUIRED_ARG), + VALID_RANGE(1, 512), DEFAULT(1), BLOCK_SIZE(1), + &PLock_wsrep_slave_threads, NOT_IN_BINLOG, + ON_CHECK(wsrep_slave_threads_check), + ON_UPDATE(wsrep_slave_threads_update)); + +static Sys_var_charptr Sys_wsrep_dbug_option( + "wsrep_dbug_option", "DBUG options to provider library", + GLOBAL_VAR(wsrep_dbug_option),CMD_LINE(REQUIRED_ARG), + IN_FS_CHARSET, DEFAULT(""), + NO_MUTEX_GUARD, NOT_IN_BINLOG); + +static Sys_var_mybool Sys_wsrep_debug( + "wsrep_debug", "To enable debug level logging", + GLOBAL_VAR(wsrep_debug), CMD_LINE(OPT_ARG), DEFAULT(FALSE)); + +static Sys_var_mybool Sys_wsrep_convert_LOCK_to_trx( + "wsrep_convert_LOCK_to_trx", "To convert locking sessions " + "into transactions", + GLOBAL_VAR(wsrep_convert_LOCK_to_trx), + CMD_LINE(OPT_ARG), DEFAULT(FALSE)); + +static Sys_var_ulong Sys_wsrep_retry_autocommit( + "wsrep_retry_autocommit", "Max number of times to retry " + "a failed autocommit statement", + SESSION_VAR(wsrep_retry_autocommit), CMD_LINE(REQUIRED_ARG), + VALID_RANGE(0, 10000), DEFAULT(1), BLOCK_SIZE(1)); + +static Sys_var_mybool Sys_wsrep_auto_increment_control( + "wsrep_auto_increment_control", "To automatically control the " + "assignment of autoincrement variables", + GLOBAL_VAR(wsrep_auto_increment_control), + CMD_LINE(OPT_ARG), DEFAULT(TRUE)); + +static Sys_var_mybool Sys_wsrep_drupal_282555_workaround( + "wsrep_drupal_282555_workaround", "To use a workaround for" + "bad autoincrement value", + GLOBAL_VAR(wsrep_drupal_282555_workaround), + CMD_LINE(OPT_ARG), DEFAULT(FALSE)); + +static Sys_var_charptr sys_wsrep_sst_method( + "wsrep_sst_method", "State snapshot transfer method", + GLOBAL_VAR(wsrep_sst_method),CMD_LINE(REQUIRED_ARG), + IN_FS_CHARSET, DEFAULT(WSREP_SST_DEFAULT), NO_MUTEX_GUARD, NOT_IN_BINLOG, + ON_CHECK(wsrep_sst_method_check), + ON_UPDATE(wsrep_sst_method_update)); + +static Sys_var_charptr Sys_wsrep_sst_receive_address( + "wsrep_sst_receive_address", "Address where node is waiting for " + "SST contact", + GLOBAL_VAR(wsrep_sst_receive_address),CMD_LINE(REQUIRED_ARG), + IN_FS_CHARSET, DEFAULT(WSREP_SST_ADDRESS_AUTO), NO_MUTEX_GUARD, + NOT_IN_BINLOG, + ON_CHECK(wsrep_sst_receive_address_check), + ON_UPDATE(wsrep_sst_receive_address_update)); + +static Sys_var_charptr Sys_wsrep_sst_auth( + "wsrep_sst_auth", "Authentication for SST connection", + PREALLOCATED GLOBAL_VAR(wsrep_sst_auth), CMD_LINE(REQUIRED_ARG, OPT_WSREP_SST_AUTH), + IN_FS_CHARSET, DEFAULT(NULL), NO_MUTEX_GUARD, + NOT_IN_BINLOG, + ON_CHECK(wsrep_sst_auth_check), + ON_UPDATE(wsrep_sst_auth_update)); + +static Sys_var_charptr Sys_wsrep_sst_donor( + "wsrep_sst_donor", "preferred donor node for the SST", + GLOBAL_VAR(wsrep_sst_donor),CMD_LINE(REQUIRED_ARG), + IN_FS_CHARSET, DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG, + ON_CHECK(wsrep_sst_donor_check), + ON_UPDATE(wsrep_sst_donor_update)); + +static Sys_var_mybool Sys_wsrep_sst_donor_rejects_queries( + "wsrep_sst_donor_rejects_queries", "Reject client queries " + "when donating state snapshot transfer", + GLOBAL_VAR(wsrep_sst_donor_rejects_queries), + CMD_LINE(OPT_ARG), DEFAULT(FALSE)); + +static Sys_var_mybool Sys_wsrep_on ( + "wsrep_on", "To enable wsrep replication ", + SESSION_VAR(wsrep_on), + CMD_LINE(OPT_ARG), DEFAULT(TRUE), + NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), + ON_UPDATE(wsrep_on_update)); + +static Sys_var_charptr Sys_wsrep_start_position ( + "wsrep_start_position", "global transaction position to start from ", + PREALLOCATED GLOBAL_VAR(wsrep_start_position), + CMD_LINE(REQUIRED_ARG, OPT_WSREP_START_POSITION), + IN_FS_CHARSET, DEFAULT(WSREP_START_POSITION_ZERO), + NO_MUTEX_GUARD, NOT_IN_BINLOG, + ON_CHECK(wsrep_start_position_check), + ON_UPDATE(wsrep_start_position_update)); + +static Sys_var_ulong Sys_wsrep_max_ws_size ( + "wsrep_max_ws_size", "Max write set size (bytes)", + GLOBAL_VAR(wsrep_max_ws_size), CMD_LINE(REQUIRED_ARG), + /* Upper limit is 65K short of 4G to avoid overlows on 32-bit systems */ + VALID_RANGE(1024, WSREP_MAX_WS_SIZE), DEFAULT(1073741824UL), BLOCK_SIZE(1)); + +static Sys_var_ulong Sys_wsrep_max_ws_rows ( + "wsrep_max_ws_rows", "Max number of rows in write set", + GLOBAL_VAR(wsrep_max_ws_rows), CMD_LINE(REQUIRED_ARG), + VALID_RANGE(1, 1048576), DEFAULT(131072), BLOCK_SIZE(1)); + +static Sys_var_charptr Sys_wsrep_notify_cmd( + "wsrep_notify_cmd", "", + GLOBAL_VAR(wsrep_notify_cmd),CMD_LINE(REQUIRED_ARG), + IN_FS_CHARSET, DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG); + +static Sys_var_mybool Sys_wsrep_certify_nonPK( + "wsrep_certify_nonPK", "Certify tables with no primary key", + GLOBAL_VAR(wsrep_certify_nonPK), + CMD_LINE(OPT_ARG), DEFAULT(TRUE)); + +static Sys_var_mybool Sys_wsrep_causal_reads( + "wsrep_causal_reads", "Enable \"strictly synchronous\" semantics for read operations", + SESSION_VAR(wsrep_causal_reads), + CMD_LINE(OPT_ARG), DEFAULT(FALSE)); + +static const char *wsrep_OSU_method_names[]= { "TOI", "RSU", NullS }; +static Sys_var_enum Sys_wsrep_OSU_method( + "wsrep_OSU_method", "Method for Online Schema Upgrade", + GLOBAL_VAR(wsrep_OSU_method_options), CMD_LINE(OPT_ARG), + wsrep_OSU_method_names, DEFAULT(WSREP_OSU_TOI), + NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), + ON_UPDATE(0)); + +static PolyLock_mutex PLock_wsrep_desync(&LOCK_wsrep_desync); +static Sys_var_mybool Sys_wsrep_desync ( + "wsrep_desync", "To desynchronize the node from the cluster", + GLOBAL_VAR(wsrep_desync), + CMD_LINE(OPT_ARG), DEFAULT(FALSE), + &PLock_wsrep_desync, NOT_IN_BINLOG, + ON_CHECK(wsrep_desync_check), + ON_UPDATE(wsrep_desync_update)); + +static Sys_var_enum Sys_wsrep_forced_binlog_format( + "wsrep_forced_binlog_format", "binlog format to take effect over user's choice", + GLOBAL_VAR(wsrep_forced_binlog_format), + CMD_LINE(REQUIRED_ARG, OPT_BINLOG_FORMAT), + wsrep_binlog_format_names, DEFAULT(BINLOG_FORMAT_UNSPEC), + NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), + ON_UPDATE(0)); + +static Sys_var_mybool Sys_wsrep_recover_datadir( + "wsrep_recover", "Recover database state after crash and exit", + READ_ONLY GLOBAL_VAR(wsrep_recovery), + CMD_LINE(OPT_ARG, OPT_WSREP_RECOVER), DEFAULT(FALSE)); + +static Sys_var_mybool Sys_wsrep_replicate_myisam( + "wsrep_replicate_myisam", "To enable myisam replication", + GLOBAL_VAR(wsrep_replicate_myisam), CMD_LINE(OPT_ARG), DEFAULT(FALSE)); + +static Sys_var_mybool Sys_wsrep_log_conflicts( + "wsrep_log_conflicts", "To log multi-master conflicts", + GLOBAL_VAR(wsrep_log_conflicts), CMD_LINE(OPT_ARG), DEFAULT(FALSE)); + +static Sys_var_ulong Sys_wsrep_mysql_replication_bundle( + "wsrep_mysql_replication_bundle", "mysql replication group commit ", + GLOBAL_VAR(wsrep_mysql_replication_bundle), CMD_LINE(REQUIRED_ARG), + VALID_RANGE(0, 1000), DEFAULT(0), BLOCK_SIZE(1)); + +static Sys_var_mybool Sys_wsrep_load_data_splitting( + "wsrep_load_data_splitting", "To commit LOAD DATA " + "transaction after every 10K rows inserted", + GLOBAL_VAR(wsrep_load_data_splitting), + CMD_LINE(OPT_ARG), DEFAULT(TRUE)); + +static Sys_var_mybool Sys_wsrep_slave_FK_checks( + "wsrep_slave_FK_checks", "Should slave thread do " + "foreign key constraint checks", + GLOBAL_VAR(wsrep_slave_FK_checks), + CMD_LINE(OPT_ARG), DEFAULT(TRUE)); + +static Sys_var_mybool Sys_wsrep_slave_UK_checks( + "wsrep_slave_UK_checks", "Should slave thread do " + "secondary index uniqueness checks", + GLOBAL_VAR(wsrep_slave_UK_checks), + CMD_LINE(OPT_ARG), DEFAULT(FALSE)); + +static Sys_var_mybool Sys_wsrep_restart_slave( + "wsrep_restart_slave", "Should MySQL slave be restarted automatically, when node joins back to cluster", + GLOBAL_VAR(wsrep_restart_slave), CMD_LINE(OPT_ARG), DEFAULT(FALSE)); +#endif /* WITH_WSREP */ + static bool fix_host_cache_size(sys_var *, THD *, enum_var_type) { hostname_cache_resize((uint) host_cache_size); diff --git a/sql/table.cc b/sql/table.cc index d720a16f6e5..25dd9786d94 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -40,6 +40,9 @@ #include "sql_statistics.h" #include "discover.h" #include "mdl.h" // MDL_wait_for_graph_visitor +#ifdef WITH_WSREP +#include "ha_partition.h" +#endif /* WITH_WSREP */ /* INFORMATION_SCHEMA name */ LEX_STRING INFORMATION_SCHEMA_NAME= {C_STRING_WITH_LEN("information_schema")}; diff --git a/sql/transaction.cc b/sql/transaction.cc index 933e39ae357..72a8c47cdd8 100644 --- a/sql/transaction.cc +++ b/sql/transaction.cc @@ -97,6 +97,9 @@ static bool xa_trans_force_rollback(THD *thd) by ha_rollback()/THD::transaction::cleanup(). */ thd->transaction.xid_state.rm_error= 0; +#ifdef WITH_WSREP + wsrep_register_hton(thd, TRUE); +#endif /* WITH_WSREP */ if (ha_rollback_trans(thd, true)) { my_error(ER_XAER_RMERR, MYF(0)); @@ -135,10 +138,16 @@ bool trans_begin(THD *thd, uint flags) (thd->variables.option_bits & OPTION_TABLE_LOCK)) { thd->variables.option_bits&= ~OPTION_TABLE_LOCK; +#ifdef WITH_WSREP + wsrep_register_hton(thd, TRUE); +#endif /* WITH_WSREP */ thd->server_status&= ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY); DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS")); res= MY_TEST(ha_commit_trans(thd, TRUE)); +#ifdef WITH_WSREP + wsrep_post_commit(thd, TRUE); +#endif /* WITH_WSREP */ } thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG); @@ -181,6 +190,12 @@ bool trans_begin(THD *thd, uint flags) thd->tx_read_only= false; } +#ifdef WITH_WSREP + thd->wsrep_PA_safe= true; + if (WSREP_CLIENT(thd) && wsrep_causal_wait(thd)) + DBUG_RETURN(TRUE); +#endif /* WITH_WSREP */ + thd->variables.option_bits|= OPTION_BEGIN; thd->server_status|= SERVER_STATUS_IN_TRANS; if (thd->tx_read_only) @@ -212,10 +227,16 @@ bool trans_commit(THD *thd) if (trans_check(thd)) DBUG_RETURN(TRUE); +#ifdef WITH_WSREP + wsrep_register_hton(thd, TRUE); +#endif /* WITH_WSREP */ thd->server_status&= ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY); DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS")); res= ha_commit_trans(thd, TRUE); +#ifdef WITH_WSREP + wsrep_post_commit(thd, TRUE); +#endif /* WITH_WSREP */ /* if res is non-zero, then ha_commit_trans has rolled back the transaction, so the hooks for rollback will be called. @@ -261,10 +282,16 @@ bool trans_commit_implicit(THD *thd) /* Safety if one did "drop table" on locked tables */ if (!thd->locked_tables_mode) thd->variables.option_bits&= ~OPTION_TABLE_LOCK; +#ifdef WITH_WSREP + wsrep_register_hton(thd, TRUE); +#endif /* WITH_WSREP */ thd->server_status&= ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY); DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS")); res= MY_TEST(ha_commit_trans(thd, TRUE)); +#ifdef WITH_WSREP + wsrep_post_commit(thd, TRUE); +#endif /* WITH_WSREP */ } thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG); @@ -297,9 +324,15 @@ bool trans_rollback(THD *thd) int res; DBUG_ENTER("trans_rollback"); +#ifdef WITH_WSREP + thd->wsrep_PA_safe= true; +#endif /* WITH_WSREP */ if (trans_check(thd)) DBUG_RETURN(TRUE); +#ifdef WITH_WSREP + wsrep_register_hton(thd, TRUE); +#endif /* WITH_WSREP */ thd->server_status&= ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY); DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS")); @@ -390,11 +423,17 @@ bool trans_commit_stmt(THD *thd) if (thd->transaction.stmt.ha_list) { +#ifdef WITH_WSREP + wsrep_register_hton(thd, FALSE); +#endif /* WITH_WSREP */ res= ha_commit_trans(thd, FALSE); if (! thd->in_active_multi_stmt_transaction()) { thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation; thd->tx_read_only= thd->variables.tx_read_only; +#ifdef WITH_WSREP + wsrep_post_commit(thd, FALSE); +#endif /* WITH_WSREP */ } } @@ -435,6 +474,9 @@ bool trans_rollback_stmt(THD *thd) if (thd->transaction.stmt.ha_list) { +#ifdef WITH_WSREP + wsrep_register_hton(thd, FALSE); +#endif /* WITH_WSREP */ ha_rollback_trans(thd, FALSE); if (! thd->in_active_multi_stmt_transaction()) { @@ -812,9 +854,15 @@ bool trans_xa_commit(THD *thd) } else if (xa_state == XA_IDLE && thd->lex->xa_opt == XA_ONE_PHASE) { +#ifdef WITH_WSREP + wsrep_register_hton(thd, TRUE); +#endif /* WITH_WSREP */ int r= ha_commit_trans(thd, TRUE); if ((res= MY_TEST(r))) my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0)); +#ifdef WITH_WSREP + wsrep_post_commit(thd, TRUE); +#endif /* WITH_WSREP */ } else if (xa_state == XA_PREPARED && thd->lex->xa_opt == XA_NONE) { @@ -833,6 +881,9 @@ bool trans_xa_commit(THD *thd) if (thd->mdl_context.acquire_lock(&mdl_request, thd->variables.lock_wait_timeout)) { +#ifdef WITH_WSREP + wsrep_register_hton(thd, TRUE); +#endif /* WITH_WSREP */ ha_rollback_trans(thd, TRUE); my_error(ER_XAER_RMERR, MYF(0)); } diff --git a/sql/tztime.cc b/sql/tztime.cc index d3b4fec6335..2a5a5d1681b 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -2708,6 +2708,12 @@ main(int argc, char **argv) free_defaults(default_argv); return 1; } + +#ifdef WITH_WSREP + // Replicate MyISAM DDL for this session, cf. lp:1161432 + printf("SET GLOBAL wsrep_replicate_myisam= ON;\n"); +#endif /* WITH_WSREP */ + if (argc == 1 && !opt_leap) { /* Argument is timezonedir */ @@ -2755,6 +2761,11 @@ main(int argc, char **argv) free_root(&tz_storage, MYF(0)); } +#ifdef WITH_WSREP + // Reset wsrep_replicate_myisam. lp:1161432 + printf("SET GLOBAL wsrep_replicate_myisam= OFF;\n"); +#endif /* WITH_WSREP */ + free_defaults(default_argv); my_end(0); return 0; diff --git a/sql/wsrep_applier.cc b/sql/wsrep_applier.cc new file mode 100644 index 00000000000..23687e98c32 --- /dev/null +++ b/sql/wsrep_applier.cc @@ -0,0 +1,387 @@ +/* Copyright (C) 2013 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + +#include "wsrep_priv.h" +#include "wsrep_binlog.h" // wsrep_dump_rbr_buf() + +#include "log_event.h" // EVENT_LEN_OFFSET, etc. +#include "wsrep_applier.h" + +/* + read the first event from (*buf). The size of the (*buf) is (*buf_len). + At the end (*buf) is shitfed to point to the following event or NULL and + (*buf_len) will be changed to account just being read bytes of the 1st event. +*/ + +static Log_event* wsrep_read_log_event( + char **arg_buf, size_t *arg_buf_len, + const Format_description_log_event *description_event) +{ + DBUG_ENTER("wsrep_read_log_event"); + char *head= (*arg_buf); + + uint data_len = uint4korr(head + EVENT_LEN_OFFSET); + char *buf= (*arg_buf); + const char *error= 0; + Log_event *res= 0; + + if (data_len > wsrep_max_ws_size) + { + error = "Event too big"; + goto err; + } + + res= Log_event::read_log_event(buf, data_len, &error, description_event, true); + +err: + if (!res) + { + DBUG_ASSERT(error != 0); + sql_print_error("Error in Log_event::read_log_event(): " + "'%s', data_len: %d, event_type: %d", + error,data_len,head[EVENT_TYPE_OFFSET]); + } + (*arg_buf)+= data_len; + (*arg_buf_len)-= data_len; + DBUG_RETURN(res); +} + +#include "transaction.h" // trans_commit(), trans_rollback() +#include "rpl_rli.h" // class Relay_log_info; +#include "sql_base.h" // close_temporary_table() + +static inline void +wsrep_set_apply_format(THD* thd, Format_description_log_event* ev) +{ + if (thd->wsrep_apply_format) + { + delete (Format_description_log_event*)thd->wsrep_apply_format; + } + thd->wsrep_apply_format= ev; +} + +static inline Format_description_log_event* +wsrep_get_apply_format(THD* thd) +{ + if (thd->wsrep_apply_format) + return (Format_description_log_event*) thd->wsrep_apply_format; + /* TODO: mariadb does not support rli->get_rli_description_event() + * => look for alternative way to remember last FDE in replication + */ + //return thd->wsrep_rli->get_rli_description_event(); + thd->wsrep_apply_format = new Format_description_log_event(4); + return (Format_description_log_event*) thd->wsrep_apply_format; +} + +static wsrep_cb_status_t wsrep_apply_events(THD* thd, + const void* events_buf, + size_t buf_len) +{ + char *buf= (char *)events_buf; + int rcode= 0; + int event= 1; + + DBUG_ENTER("wsrep_apply_events"); + + if (thd->killed == KILL_CONNECTION) + { + WSREP_INFO("applier has been aborted, skipping apply_rbr: %lld", + (long long) wsrep_thd_trx_seqno(thd)); + DBUG_RETURN(WSREP_CB_FAILURE); + } + + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + thd->wsrep_query_state= QUERY_EXEC; + if (thd->wsrep_conflict_state!= REPLAYING) + thd->wsrep_conflict_state= NO_CONFLICT; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + + if (!buf_len) WSREP_DEBUG("empty rbr buffer to apply: %lld", + (long long) wsrep_thd_trx_seqno(thd)); + + while(buf_len) + { + int exec_res; + Log_event* ev= wsrep_read_log_event(&buf, &buf_len, + wsrep_get_apply_format(thd)); + + if (!ev) + { + WSREP_ERROR("applier could not read binlog event, seqno: %lld, len: %zu", + (long long)wsrep_thd_trx_seqno(thd), buf_len); + rcode= 1; + goto error; + } + + switch (ev->get_type_code()) { + case FORMAT_DESCRIPTION_EVENT: + wsrep_set_apply_format(thd, (Format_description_log_event*)ev); + continue; +#ifdef GTID_SUPPORT + case GTID_LOG_EVENT: + { + Gtid_log_event* gev= (Gtid_log_event*)ev; + if (gev->get_gno() == 0) + { + /* Skip GTID log event to make binlog to generate LTID on commit */ + delete ev; + continue; + } + } +#endif /* GTID_SUPPORT */ + default: + break; + } + + thd->set_server_id(ev->server_id); // use the original server id for logging + thd->set_time(); // time the query + wsrep_xid_init(&thd->transaction.xid_state.xid, + &thd->wsrep_trx_meta.gtid.uuid, + thd->wsrep_trx_meta.gtid.seqno); + thd->lex->current_select= 0; + if (!ev->when) + { + my_hrtime_t hrtime= my_hrtime(); + ev->when= hrtime_to_my_time(hrtime); + ev->when_sec_part= hrtime_sec_part(hrtime); + } + + ev->thd = thd; + //exec_res = ev->apply_event(thd->wsrep_rli); + exec_res = ev->apply_event(thd->wsrep_rgi); + DBUG_PRINT("info", ("exec_event result: %d", exec_res)); + + if (exec_res) + { + WSREP_WARN("RBR event %d %s apply warning: %d, %lld", + event, ev->get_type_str(), exec_res, + (long long) wsrep_thd_trx_seqno(thd)); + rcode= exec_res; + /* stop processing for the first error */ + delete ev; + goto error; + } + event++; + + if (thd->wsrep_conflict_state!= NO_CONFLICT && + thd->wsrep_conflict_state!= REPLAYING) + WSREP_WARN("conflict state after RBR event applying: %d, %lld", + thd->wsrep_query_state, (long long)wsrep_thd_trx_seqno(thd)); + + if (thd->wsrep_conflict_state == MUST_ABORT) { + WSREP_WARN("RBR event apply failed, rolling back: %lld", + (long long) wsrep_thd_trx_seqno(thd)); + trans_rollback(thd); + thd->locked_tables_list.unlock_locked_tables(thd); + /* Release transactional metadata locks. */ + thd->mdl_context.release_transactional_locks(); + thd->wsrep_conflict_state= NO_CONFLICT; + DBUG_RETURN(WSREP_CB_FAILURE); + } + + delete ev; + } + + error: + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + thd->wsrep_query_state= QUERY_IDLE; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + + assert(thd->wsrep_exec_mode== REPL_RECV); + + if (thd->killed == KILL_CONNECTION) + WSREP_INFO("applier aborted: %lld", (long long)wsrep_thd_trx_seqno(thd)); + + if (rcode) DBUG_RETURN(WSREP_CB_FAILURE); + DBUG_RETURN(WSREP_CB_SUCCESS); +} + +wsrep_cb_status_t wsrep_apply_cb(void* const ctx, + const void* const buf, + size_t const buf_len, + uint32_t const flags, + const wsrep_trx_meta_t* meta) +{ + THD* const thd((THD*)ctx); + + thd->wsrep_trx_meta = *meta; + +#ifdef WSREP_PROC_INFO + snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, + "applying write set %lld: %p, %zu", + (long long)wsrep_thd_trx_seqno(thd), buf, buf_len); + thd_proc_info(thd, thd->wsrep_info); +#else + thd_proc_info(thd, "applying write set"); +#endif /* WSREP_PROC_INFO */ + + /* tune FK and UK checking policy */ + if (wsrep_slave_UK_checks == FALSE) + thd->variables.option_bits|= OPTION_RELAXED_UNIQUE_CHECKS; + else + thd->variables.option_bits&= ~OPTION_RELAXED_UNIQUE_CHECKS; + + if (wsrep_slave_FK_checks == FALSE) + thd->variables.option_bits|= OPTION_NO_FOREIGN_KEY_CHECKS; + else + thd->variables.option_bits&= ~OPTION_NO_FOREIGN_KEY_CHECKS; + + if (flags & WSREP_FLAG_ISOLATION) + { + thd->wsrep_apply_toi= true; + /* + Don't run in transaction mode with TOI actions. + */ + thd->variables.option_bits&= ~OPTION_BEGIN; + thd->server_status&= ~SERVER_STATUS_IN_TRANS; + } + wsrep_cb_status_t rcode(wsrep_apply_events(thd, buf, buf_len)); + +#ifdef WSREP_PROC_INFO + snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, + "applied write set %lld", (long long)wsrep_thd_trx_seqno(thd)); + thd_proc_info(thd, thd->wsrep_info); +#else + thd_proc_info(thd, "applied write set"); +#endif /* WSREP_PROC_INFO */ + + if (WSREP_CB_SUCCESS != rcode) + { + wsrep_dump_rbr_buf(thd, buf, buf_len); + } + + TABLE *tmp; + while ((tmp = thd->temporary_tables)) + { + WSREP_DEBUG("Applier %lu, has temporary tables: %s.%s", + thd->thread_id, + (tmp->s) ? tmp->s->db.str : "void", + (tmp->s) ? tmp->s->table_name.str : "void"); + close_temporary_table(thd, tmp, 1, 1); + } + + return rcode; +} + +static wsrep_cb_status_t wsrep_commit(THD* const thd, + wsrep_seqno_t const global_seqno) +{ +#ifdef WSREP_PROC_INFO + snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, + "committing %lld", (long long)wsrep_thd_trx_seqno(thd)); + thd_proc_info(thd, thd->wsrep_info); +#else + thd_proc_info(thd, "committing"); +#endif /* WSREP_PROC_INFO */ + + wsrep_cb_status_t const rcode(trans_commit(thd) ? + WSREP_CB_FAILURE : WSREP_CB_SUCCESS); + +#ifdef WSREP_PROC_INFO + snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, + "committed %lld", (long long)wsrep_thd_trx_seqno(thd)); + thd_proc_info(thd, thd->wsrep_info); +#else + thd_proc_info(thd, "committed"); +#endif /* WSREP_PROC_INFO */ + + if (WSREP_CB_SUCCESS == rcode) + { + thd->wsrep_rgi->cleanup_context(thd, false); +#ifdef GTID_SUPPORT + thd->variables.gtid_next.set_automatic(); +#endif /* GTID_SUPPORT */ + // TODO: mark snapshot with global_seqno. + } + + return rcode; +} + +static wsrep_cb_status_t wsrep_rollback(THD* const thd, + wsrep_seqno_t const global_seqno) +{ +#ifdef WSREP_PROC_INFO + snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, + "rolling back %lld", (long long)wsrep_thd_trx_seqno(thd)); + thd_proc_info(thd, thd->wsrep_info); +#else + thd_proc_info(thd, "rolling back"); +#endif /* WSREP_PROC_INFO */ + + wsrep_cb_status_t const rcode(trans_rollback(thd) ? + WSREP_CB_FAILURE : WSREP_CB_SUCCESS); + +#ifdef WSREP_PROC_INFO + snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, + "rolled back %lld", (long long)wsrep_thd_trx_seqno(thd)); + thd_proc_info(thd, thd->wsrep_info); +#else + thd_proc_info(thd, "rolled back"); +#endif /* WSREP_PROC_INFO */ + + return rcode; +} + +wsrep_cb_status_t wsrep_commit_cb(void* const ctx, + uint32_t const flags, + const wsrep_trx_meta_t* meta, + wsrep_bool_t* const exit, + bool const commit) +{ + THD* const thd((THD*)ctx); + + assert(meta->gtid.seqno == wsrep_thd_trx_seqno(thd)); + + wsrep_cb_status_t rcode; + + if (commit) + rcode = wsrep_commit(thd, meta->gtid.seqno); + else + rcode = wsrep_rollback(thd, meta->gtid.seqno); + + wsrep_set_apply_format(thd, NULL); + thd->mdl_context.release_transactional_locks(); + free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC)); + thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation; + + if (wsrep_slave_count_change < 0 && commit && WSREP_CB_SUCCESS == rcode) + { + mysql_mutex_lock(&LOCK_wsrep_slave_threads); + if (wsrep_slave_count_change < 0) + { + wsrep_slave_count_change++; + *exit = true; + } + mysql_mutex_unlock(&LOCK_wsrep_slave_threads); + } + + if (*exit == false && thd->wsrep_applier) + { + /* From trans_begin() */ + thd->variables.option_bits|= OPTION_BEGIN; + thd->server_status|= SERVER_STATUS_IN_TRANS; + thd->wsrep_apply_toi= false; + } + + return rcode; +} + + +wsrep_cb_status_t wsrep_unordered_cb(void* const ctx, + const void* const data, + size_t const size) +{ + return WSREP_CB_SUCCESS; +} diff --git a/sql/wsrep_applier.h b/sql/wsrep_applier.h new file mode 100644 index 00000000000..816970db67c --- /dev/null +++ b/sql/wsrep_applier.h @@ -0,0 +1,38 @@ +/* Copyright 2013 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef WSREP_APPLIER_H +#define WSREP_APPLIER_H + +#include + +/* wsrep callback prototypes */ + +wsrep_cb_status_t wsrep_apply_cb(void *ctx, + const void* buf, size_t buf_len, + uint32_t flags, + const wsrep_trx_meta_t* meta); + +wsrep_cb_status_t wsrep_commit_cb(void *ctx, + uint32_t flags, + const wsrep_trx_meta_t* meta, + wsrep_bool_t* exit, + bool commit); + +wsrep_cb_status_t wsrep_unordered_cb(void* ctx, + const void* data, + size_t size); + +#endif /* WSREP_APPLIER_H */ diff --git a/sql/wsrep_binlog.cc b/sql/wsrep_binlog.cc new file mode 100644 index 00000000000..5cb910248a2 --- /dev/null +++ b/sql/wsrep_binlog.cc @@ -0,0 +1,408 @@ +/* Copyright (C) 2013 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + +#include "wsrep_binlog.h" +#include "wsrep_priv.h" + +/* + Write the contents of a cache to a memory buffer. + + This function quite the same as MYSQL_BIN_LOG::write_cache(), + with the exception that here we write in buffer instead of log file. + */ +int wsrep_write_cache_buf(IO_CACHE *cache, uchar **buf, size_t *buf_len) +{ + *buf= NULL; + *buf_len= 0; + + my_off_t const saved_pos(my_b_tell(cache)); + + if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0)) + { + WSREP_ERROR("failed to initialize io-cache"); + return ER_ERROR_ON_WRITE; + } + + uint length = my_b_bytes_in_cache(cache); + if (unlikely(0 == length)) length = my_b_fill(cache); + + size_t total_length = 0; + + if (likely(length > 0)) do + { + total_length += length; + /* + Bail out if buffer grows too large. + A temporary fix to avoid allocating indefinitely large buffer, + not a real limit on a writeset size which includes other things + like header and keys. + */ + if (total_length > wsrep_max_ws_size) + { + WSREP_WARN("transaction size limit (%lu) exceeded: %zu", + wsrep_max_ws_size, total_length); + goto error; + } + uchar* tmp = (uchar *)my_realloc(*buf, total_length, + MYF(MY_ALLOW_ZERO_PTR)); + if (!tmp) + { + WSREP_ERROR("could not (re)allocate buffer: %zu + %u", + *buf_len, length); + goto error; + } + *buf = tmp; + + memcpy(*buf + *buf_len, cache->read_pos, length); + *buf_len = total_length; + cache->read_pos = cache->read_end; + } while ((cache->file >= 0) && (length = my_b_fill(cache))); + + if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0)) + { + WSREP_WARN("failed to initialize io-cache"); + goto cleanup; + } + + return 0; + +error: + if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0)) + { + WSREP_WARN("failed to initialize io-cache"); + } +cleanup: + my_free(*buf); + *buf= NULL; + *buf_len= 0; + return ER_ERROR_ON_WRITE; +} + +#define STACK_SIZE 4096 /* 4K - for buffer preallocated on the stack: + * many transactions would fit in there + * so there is no need to reach for the heap */ + +/* Returns minimum multiple of HEAP_PAGE_SIZE that is >= length */ +static inline size_t +heap_size(size_t length) +{ + return (length + HEAP_PAGE_SIZE - 1)/HEAP_PAGE_SIZE*HEAP_PAGE_SIZE; +} + +/* append data to writeset */ +static inline wsrep_status_t +wsrep_append_data(wsrep_t* const wsrep, + wsrep_ws_handle_t* const ws, + const void* const data, + size_t const len) +{ + struct wsrep_buf const buff = { data, len }; + wsrep_status_t const rc(wsrep->append_data(wsrep, ws, &buff, 1, + WSREP_DATA_ORDERED, true)); + if (rc != WSREP_OK) + { + WSREP_WARN("append_data() returned %d", rc); + } + + return rc; +} + +/* + Write the contents of a cache to wsrep provider. + + This function quite the same as MYSQL_BIN_LOG::write_cache(), + with the exception that here we write in buffer instead of log file. + + This version reads all of cache into single buffer and then appends to a + writeset at once. + */ +static int wsrep_write_cache_once(wsrep_t* const wsrep, + THD* const thd, + IO_CACHE* const cache, + size_t* const len) +{ + my_off_t const saved_pos(my_b_tell(cache)); + + if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0)) + { + WSREP_ERROR("failed to initialize io-cache"); + return ER_ERROR_ON_WRITE; + } + + int err(WSREP_OK); + + size_t total_length(0); + uchar stack_buf[STACK_SIZE]; /* to avoid dynamic allocations for few data*/ + uchar* heap_buf(NULL); + uchar* buf(stack_buf); + size_t allocated(sizeof(stack_buf)); + size_t used(0); + + uint length(my_b_bytes_in_cache(cache)); + if (unlikely(0 == length)) length = my_b_fill(cache); + + if (likely(length > 0)) do + { + total_length += length; + /* + Bail out if buffer grows too large. + A temporary fix to avoid allocating indefinitely large buffer, + not a real limit on a writeset size which includes other things + like header and keys. + */ + if (unlikely(total_length > wsrep_max_ws_size)) + { + WSREP_WARN("transaction size limit (%lu) exceeded: %zu", + wsrep_max_ws_size, total_length); + err = WSREP_TRX_SIZE_EXCEEDED; + goto cleanup; + } + + if (total_length > allocated) + { + size_t const new_size(heap_size(total_length)); + uchar* tmp = (uchar *)my_realloc(heap_buf, new_size, + MYF(MY_ALLOW_ZERO_PTR)); + if (!tmp) + { + WSREP_ERROR("could not (re)allocate buffer: %zu + %u", + allocated, length); + err = WSREP_TRX_SIZE_EXCEEDED; + goto cleanup; + } + + heap_buf = tmp; + buf = heap_buf; + allocated = new_size; + + if (used <= STACK_SIZE && used > 0) // there's data in stack_buf + { + DBUG_ASSERT(buf == stack_buf); + memcpy(heap_buf, stack_buf, used); + } + } + + memcpy(buf + used, cache->read_pos, length); + used = total_length; + cache->read_pos = cache->read_end; + } while ((cache->file >= 0) && (length = my_b_fill(cache))); + + if (used > 0) + err = wsrep_append_data(wsrep, &thd->wsrep_ws_handle, buf, used); + + if (WSREP_OK == err) *len = total_length; + +cleanup: + if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0)) + { + WSREP_ERROR("failed to reinitialize io-cache"); + } + + if (unlikely(WSREP_OK != err)) wsrep_dump_rbr_buf(thd, buf, used); + + my_free(heap_buf); + return err; +} + +/* + Write the contents of a cache to wsrep provider. + + This function quite the same as MYSQL_BIN_LOG::write_cache(), + with the exception that here we write in buffer instead of log file. + + This version uses incremental data appending as it reads it from cache. + */ +static int wsrep_write_cache_inc(wsrep_t* const wsrep, + THD* const thd, + IO_CACHE* const cache, + size_t* const len) +{ + my_off_t const saved_pos(my_b_tell(cache)); + + if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0)) + { + WSREP_ERROR("failed to initialize io-cache"); + return WSREP_TRX_ERROR; + } + + int err(WSREP_OK); + + size_t total_length(0); + + uint length(my_b_bytes_in_cache(cache)); + if (unlikely(0 == length)) length = my_b_fill(cache); + + if (likely(length > 0)) do + { + total_length += length; + /* bail out if buffer grows too large + not a real limit on a writeset size which includes other things + like header and keys. + */ + if (unlikely(total_length > wsrep_max_ws_size)) + { + WSREP_WARN("transaction size limit (%lu) exceeded: %zu", + wsrep_max_ws_size, total_length); + err = WSREP_TRX_SIZE_EXCEEDED; + goto cleanup; + } + + if(WSREP_OK != (err=wsrep_append_data(wsrep, &thd->wsrep_ws_handle, + cache->read_pos, length))) + goto cleanup; + + cache->read_pos = cache->read_end; + } while ((cache->file >= 0) && (length = my_b_fill(cache))); + + if (WSREP_OK == err) *len = total_length; + +cleanup: + if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0)) + { + WSREP_ERROR("failed to reinitialize io-cache"); + } + + return err; +} + +/* + Write the contents of a cache to wsrep provider. + + This function quite the same as MYSQL_BIN_LOG::write_cache(), + with the exception that here we write in buffer instead of log file. + */ +int wsrep_write_cache(wsrep_t* const wsrep, + THD* const thd, + IO_CACHE* const cache, + size_t* const len) +{ + if (wsrep_incremental_data_collection) { + return wsrep_write_cache_inc(wsrep, thd, cache, len); + } + else { + return wsrep_write_cache_once(wsrep, thd, cache, len); + } +} + +void wsrep_dump_rbr_buf(THD *thd, const void* rbr_buf, size_t buf_len) +{ + char filename[PATH_MAX]= {0}; + int len= snprintf(filename, PATH_MAX, "%s/GRA_%ld_%lld.log", + wsrep_data_home_dir, thd->thread_id, + (long long)wsrep_thd_trx_seqno(thd)); + if (len >= PATH_MAX) + { + WSREP_ERROR("RBR dump path too long: %d, skipping dump.", len); + return; + } + + FILE *of= fopen(filename, "wb"); + if (of) + { + fwrite (rbr_buf, buf_len, 1, of); + fclose(of); + } + else + { + WSREP_ERROR("Failed to open file '%s': %d (%s)", + filename, errno, strerror(errno)); + } +} +extern handlerton *binlog_hton; + +/* + wsrep exploits binlog's caches even if binlogging itself is not + activated. In such case connection close needs calling + actual binlog's method. + Todo: split binlog hton from its caches to use ones by wsrep + without referring to binlog's stuff. +*/ +int wsrep_binlog_close_connection(THD* thd) +{ + DBUG_ENTER("wsrep_binlog_close_connection"); + if (thd_get_ha_data(thd, binlog_hton) != NULL) + binlog_hton->close_connection (binlog_hton, thd); + DBUG_RETURN(0); +} + +int wsrep_binlog_savepoint_set(THD *thd, void *sv) +{ + if (!wsrep_emulate_bin_log) return 0; + int rcode = binlog_hton->savepoint_set(binlog_hton, thd, sv); + return rcode; +} + +int wsrep_binlog_savepoint_rollback(THD *thd, void *sv) +{ + if (!wsrep_emulate_bin_log) return 0; + int rcode = binlog_hton->savepoint_rollback(binlog_hton, thd, sv); + return rcode; +} + +void wsrep_dump_rbr_direct(THD* thd, IO_CACHE* cache) +{ + char filename[PATH_MAX]= {0}; + int len= snprintf(filename, PATH_MAX, "%s/GRA_%ld_%lld.log", + wsrep_data_home_dir, thd->thread_id, + (long long)wsrep_thd_trx_seqno(thd)); + size_t bytes_in_cache = 0; + // check path + if (len >= PATH_MAX) + { + WSREP_ERROR("RBR dump path too long: %d, skipping dump.", len); + return ; + } + // init cache + my_off_t const saved_pos(my_b_tell(cache)); + if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0)) + { + WSREP_ERROR("failed to initialize io-cache"); + return ; + } + // open file + FILE* of = fopen(filename, "wb"); + if (!of) + { + WSREP_ERROR("Failed to open file '%s': %d (%s)", + filename, errno, strerror(errno)); + goto cleanup; + } + // ready to write + bytes_in_cache= my_b_bytes_in_cache(cache); + if (unlikely(bytes_in_cache == 0)) bytes_in_cache = my_b_fill(cache); + if (likely(bytes_in_cache > 0)) do + { + if (my_fwrite(of, cache->read_pos, bytes_in_cache, + MYF(MY_WME | MY_NABP)) == (size_t) -1) + { + WSREP_ERROR("Failed to write file '%s'", filename); + goto cleanup; + } + cache->read_pos= cache->read_end; + } while ((cache->file >= 0) && (bytes_in_cache= my_b_fill(cache))); + if(cache->error == -1) + { + WSREP_ERROR("RBR inconsistent"); + goto cleanup; + } +cleanup: + // init back + if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0)) + { + WSREP_ERROR("failed to reinitialize io-cache"); + } + // close file + if (of) fclose(of); +} diff --git a/sql/wsrep_binlog.h b/sql/wsrep_binlog.h new file mode 100644 index 00000000000..a3d8ec6ec2c --- /dev/null +++ b/sql/wsrep_binlog.h @@ -0,0 +1,59 @@ +/* Copyright (C) 2013 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + +#ifndef WSREP_BINLOG_H +#define WSREP_BINLOG_H + +#include "sql_class.h" // THD, IO_CACHE + +#define HEAP_PAGE_SIZE 65536 /* 64K */ +#define WSREP_MAX_WS_SIZE (0xFFFFFFFFUL - HEAP_PAGE_SIZE) + +/* + Write the contents of a cache to a memory buffer. + + This function quite the same as MYSQL_BIN_LOG::write_cache(), + with the exception that here we write in buffer instead of log file. + */ +int wsrep_write_cache_buf(IO_CACHE *cache, uchar **buf, size_t *buf_len); + +/* + Write the contents of a cache to wsrep provider. + + This function quite the same as MYSQL_BIN_LOG::write_cache(), + with the exception that here we write in buffer instead of log file. + + @param len total amount of data written + @return wsrep error status + */ +int wsrep_write_cache (wsrep_t* wsrep, + THD* thd, + IO_CACHE* cache, + size_t* len); + +/* Dump replication buffer to disk */ +void wsrep_dump_rbr_buf(THD *thd, const void* rbr_buf, size_t buf_len); + +/* Dump replication buffer to disk without intermediate buffer */ +void wsrep_dump_rbr_direct(THD* thd, IO_CACHE* cache); + +int wsrep_binlog_close_connection(THD* thd); +int wsrep_binlog_savepoint_set(THD *thd, void *sv); +int wsrep_binlog_savepoint_rollback(THD *thd, void *sv); + +/* Dump replication buffer to disk without intermediate buffer */ +void wsrep_dump_rbr_direct(THD* thd, IO_CACHE* cache); + +#endif /* WSREP_BINLOG_H */ diff --git a/sql/wsrep_check_opts.cc b/sql/wsrep_check_opts.cc new file mode 100644 index 00000000000..5ec18c79978 --- /dev/null +++ b/sql/wsrep_check_opts.cc @@ -0,0 +1,379 @@ +/* Copyright 2011 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +//#include +#include +//#include +//#include + +#include "wsrep_mysqld.h" + +#include +#include +#include +#include + +/* This file is about checking for correctness of mysql configuration options */ + +struct opt +{ + const char* const name; + const char* value; +}; + +/* A list of options to check. + * At first we assume default values and then see if they are changed on CLI or + * in my.cnf */ +static struct opt opts[] = +{ + { "wsrep_slave_threads", "1" }, // mysqld.cc + { "bind_address", "0.0.0.0" }, // mysqld.cc + { "wsrep_sst_method", "rsync" }, // mysqld.cc + { "wsrep_sst_receive_address","AUTO"}, // mysqld.cc + { "binlog_format", "ROW" }, // mysqld.cc + { "wsrep_provider", "none" }, // mysqld.cc + { "query_cache_type", "0" }, // mysqld.cc + { "query_cache_size", "0" }, // mysqld.cc + { "locked_in_memory", "0" }, // mysqld.cc + { "wsrep_cluster_address", "0" }, // mysqld.cc + { "locks_unsafe_for_binlog", "0" }, // ha_innodb.cc + { "autoinc_lock_mode", "1" }, // ha_innodb.cc + { 0, 0 } +}; + +enum +{ + WSREP_SLAVE_THREADS, + BIND_ADDRESS, + WSREP_SST_METHOD, + WSREP_SST_RECEIVE_ADDRESS, + BINLOG_FORMAT, + WSREP_PROVIDER, + QUERY_CACHE_TYPE, + QUERY_CACHE_SIZE, + LOCKED_IN_MEMORY, + WSREP_CLUSTER_ADDRESS, + LOCKS_UNSAFE_FOR_BINLOG, + AUTOINC_LOCK_MODE +}; + + +/* A class to make a copy of argv[] vector */ +struct argv_copy +{ + int const argc_; + char** argv_; + + argv_copy (int const argc, const char* const argv[]) : + argc_ (argc), + argv_ (reinterpret_cast(calloc(argc_, sizeof(char*)))) + { + if (argv_) + { + for (int i = 0; i < argc_; ++i) + { + argv_[i] = strdup(argv[i]); + + if (!argv_[i]) + { + argv_free (); // free whatever bee allocated + return; + } + } + } + } + + ~argv_copy () { argv_free (); } + +private: + argv_copy (const argv_copy&); + argv_copy& operator= (const argv_copy&); + + void argv_free() + { + if (argv_) + { + for (int i = 0; (i < argc_) && argv_[i] ; ++i) free (argv_[i]); + free (argv_); + argv_ = 0; + } + } +}; + +/* a short corresponding to '--' byte sequence */ +static short const long_opt_prefix ('-' + ('-' << 8)); + +/* Normalizes long options to have '_' instead of '-' */ +static int +normalize_opts (argv_copy& a) +{ + if (a.argv_) + { + for (int i = 0; i < a.argc_; ++i) + { + char* ptr = a.argv_[i]; + if (long_opt_prefix == *(short*)ptr) // long option + { + ptr += 2; + const char* end = strchr(ptr, '='); + + if (!end) end = ptr + strlen(ptr); + + for (; ptr != end; ++ptr) if ('-' == *ptr) *ptr = '_'; + } + } + + return 0; + } + + return EINVAL; +} + +/* Find required options in the argument list and change their values */ +static int +find_opts (argv_copy& a, struct opt* const opts) +{ + for (int i = 0; i < a.argc_; ++i) + { + char* ptr = a.argv_[i] + 2; // we're interested only in long options + + struct opt* opt = opts; + for (; 0 != opt->name; ++opt) + { + if (!strstr(ptr, opt->name)) continue; // try next option + + /* 1. try to find value after the '=' */ + opt->value = strchr(ptr, '=') + 1; + + /* 2. if no '=', try next element in the argument vector */ + if (reinterpret_cast(1) == opt->value) + { + /* also check that the next element is not an option itself */ + if (i + 1 < a.argc_ && *(a.argv_[i + 1]) != '-') + { + ++i; + opt->value = a.argv_[i]; + } + else opt->value = ""; // no value supplied (like boolean opt) + } + + break; // option found, break inner loop + } + } + + return 0; +} + +/* Parses string for an integer. Returns 0 on success. */ +int get_long_long (const struct opt& opt, long long* const val, int const base) +{ + const char* const str = opt.value; + + if ('\0' != *str) + { + char* endptr; + + *val = strtoll (str, &endptr, base); + + if ('k' == *endptr || 'K' == *endptr) + { + *val *= 1024L; + endptr++; + } + else if ('m' == *endptr || 'M' == *endptr) + { + *val *= 1024L * 1024L; + endptr++; + } + else if ('g' == *endptr || 'G' == *endptr) + { + *val *= 1024L * 1024L * 1024L; + endptr++; + } + + if ('\0' == *endptr) return 0; // the whole string was a valid integer + } + + WSREP_ERROR ("Bad value for *%s: '%s'. Should be integer.", + opt.name, opt.value); + + return EINVAL; +} + +/* This is flimzy coz hell knows how mysql interprets boolean strings... + * and, no, I'm not going to become versed in how mysql handles options - + * I'd rather sing. + + Aha, http://dev.mysql.com/doc/refman/5.1/en/dynamic-system-variables.html: + Variables that have a type of “boolean†can be set to 0, 1, ON or OFF. (If you + set them on the command line or in an option file, use the numeric values.) + + So it is '0' for FALSE, '1' or empty string for TRUE + + */ +int get_bool (const struct opt& opt, bool* const val) +{ + const char* str = opt.value; + + while (isspace(*str)) ++str; // skip initial whitespaces + + ssize_t str_len = strlen(str); + switch (str_len) + { + case 0: + *val = true; + return 0; + case 1: + if ('0' == *str || '1' == *str) + { + *val = ('1' == *str); + return 0; + } + } + + WSREP_ERROR ("Bad value for *%s: '%s'. Should be '0', '1' or empty string.", + opt.name, opt.value); + + return EINVAL; +} + +static int +check_opts (int const argc, const char* const argv[], struct opt opts[]) +{ + /* First, make a copy of argv to be able to manipulate it */ + argv_copy a(argc, argv); + + if (!a.argv_) + { + WSREP_ERROR ("Could not copy argv vector: not enough memory."); + return ENOMEM; + } + + int err = normalize_opts (a); + if (err) + { + WSREP_ERROR ("Failed to normalize options."); + return err; + } + + err = find_opts (a, opts); + if (err) + { + WSREP_ERROR ("Failed to parse options."); + return err; + } + + /* At this point we have updated default values in our option list to + what has been specified on the command line / my.cnf */ + + long long slave_threads; + err = get_long_long (opts[WSREP_SLAVE_THREADS], &slave_threads, 10); + if (err) return err; + + int rcode = 0; + + if (slave_threads > 1) + /* Need to check AUTOINC_LOCK_MODE and LOCKS_UNSAFE_FOR_BINLOG */ + { + long long autoinc_lock_mode; + err = get_long_long (opts[AUTOINC_LOCK_MODE], &autoinc_lock_mode, 10); + if (err) return err; + + bool locks_unsafe_for_binlog; + err = get_bool (opts[LOCKS_UNSAFE_FOR_BINLOG],&locks_unsafe_for_binlog); + if (err) return err; + + if (autoinc_lock_mode != 2) + { + WSREP_ERROR ("Parallel applying (wsrep_slave_threads > 1) requires" + " innodb_autoinc_lock_mode = 2."); + rcode = EINVAL; + } + } + + bool locked_in_memory; + err = get_bool (opts[LOCKED_IN_MEMORY], &locked_in_memory); + if (err) { WSREP_ERROR("get_bool error: %s", strerror(err)); return err; } + if (locked_in_memory) + { + WSREP_ERROR ("Memory locking is not supported (locked_in_memory=%s)", + locked_in_memory ? "ON" : "OFF"); + rcode = EINVAL; + } + + if (!strcasecmp(opts[WSREP_SST_METHOD].value,"mysqldump")) + { + if (!strcasecmp(opts[BIND_ADDRESS].value, "127.0.0.1") || + !strcasecmp(opts[BIND_ADDRESS].value, "localhost")) + { + WSREP_ERROR ("wsrep_sst_method is set to 'mysqldump' yet " + "mysqld bind_address is set to '%s', which makes it " + "impossible to receive state transfer from another " + "node, since mysqld won't accept such connections. " + "If you wish to use mysqldump state transfer method, " + "set bind_address to allow mysql client connections " + "from other cluster members (e.g. 0.0.0.0).", + opts[BIND_ADDRESS].value); + rcode = EINVAL; + } + } + else + { + // non-mysqldump SST requires wsrep_cluster_address on startup + if (strlen(opts[WSREP_CLUSTER_ADDRESS].value) == 0) + { + WSREP_ERROR ("%s SST method requires wsrep_cluster_address to be " + "configured on startup.",opts[WSREP_SST_METHOD].value); + rcode = EINVAL; + } + } + + if (strcasecmp(opts[WSREP_SST_RECEIVE_ADDRESS].value, "AUTO")) + { + if (!strncasecmp(opts[WSREP_SST_RECEIVE_ADDRESS].value, + "127.0.0.1", strlen("127.0.0.1")) || + !strncasecmp(opts[WSREP_SST_RECEIVE_ADDRESS].value, + "localhost", strlen("localhost"))) + { + WSREP_WARN ("wsrep_sst_receive_address is set to '%s' which " + "makes it impossible for another host to reach this " + "one. Please set it to the address which this node " + "can be connected at by other cluster members.", + opts[WSREP_SST_RECEIVE_ADDRESS].value); +// rcode = EINVAL; + } + } + + if (strcasecmp(opts[WSREP_PROVIDER].value, "none")) + { + if (strcasecmp(opts[BINLOG_FORMAT].value, "ROW")) + { + WSREP_ERROR ("Only binlog_format = 'ROW' is currently supported. " + "Configured value: '%s'. Please adjust your " + "configuration.", opts[BINLOG_FORMAT].value); + + rcode = EINVAL; + } + } + + return rcode; +} + +int +wsrep_check_opts (int const argc, char* const* const argv) +{ + return check_opts (argc, argv, opts); +} + diff --git a/sql/wsrep_hton.cc b/sql/wsrep_hton.cc new file mode 100644 index 00000000000..48577a9b5a1 --- /dev/null +++ b/sql/wsrep_hton.cc @@ -0,0 +1,577 @@ +/* Copyright 2008 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include +#include "sql_base.h" +#include "rpl_filter.h" +#include +#include "wsrep_mysqld.h" +#include "wsrep_binlog.h" +#include +#include + +extern ulonglong thd_to_trx_id(THD *thd); + +extern "C" int thd_binlog_format(const MYSQL_THD thd); +// todo: share interface with ha_innodb.c + +enum wsrep_trx_status wsrep_run_wsrep_commit(THD *thd, handlerton *hton, + bool all); + +/* + Cleanup after local transaction commit/rollback, replay or TOI. +*/ +void wsrep_cleanup_transaction(THD *thd) +{ + if (wsrep_emulate_bin_log) thd_binlog_trx_reset(thd); + thd->wsrep_ws_handle.trx_id= WSREP_UNDEFINED_TRX_ID; + thd->wsrep_trx_meta.gtid= WSREP_GTID_UNDEFINED; + thd->wsrep_trx_meta.depends_on= WSREP_SEQNO_UNDEFINED; + thd->wsrep_exec_mode= LOCAL_STATE; + return; +} + +/* + wsrep hton +*/ +handlerton *wsrep_hton; + + +/* + Registers wsrep hton at commit time if transaction has registered htons + for supported engine types. + + Hton should not be registered for TOTAL_ORDER operations. + + Registration is needed for both LOCAL_MODE and REPL_RECV transactions to run + commit in 2pc so that wsrep position gets properly recorded in storage + engines. + + Note that all hton calls should immediately return for threads that are + in REPL_RECV mode as their states are controlled by wsrep appliers or + replaying code. Only threads in LOCAL_MODE should run wsrep callbacks + from hton methods. +*/ +void wsrep_register_hton(THD* thd, bool all) +{ + if (thd->wsrep_exec_mode != TOTAL_ORDER && !thd->wsrep_apply_toi) + { + THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt; + for (Ha_trx_info *i= trans->ha_list; WSREP(thd) && i; i = i->next()) + { + if ((i->ht()->db_type == DB_TYPE_INNODB) || + (i->ht()->db_type == DB_TYPE_TOKUDB)) + { + trans_register_ha(thd, all, wsrep_hton); + + /* follow innodb read/write settting + * but, as an exception: CTAS with empty result set will not be + * replicated unless we declare wsrep hton as read/write here + */ + if (i->is_trx_read_write() || + (thd->lex->sql_command == SQLCOM_CREATE_TABLE && + thd->wsrep_exec_mode == LOCAL_STATE)) + { + thd->ha_data[wsrep_hton->slot].ha_info[all].set_trx_read_write(); + } + break; + } + } + } +} + +/* + Calls wsrep->post_commit() for locally executed transactions that have + got seqno from provider (must commit) and don't require replaying. + */ +void wsrep_post_commit(THD* thd, bool all) +{ + if (thd->wsrep_exec_mode == LOCAL_COMMIT) + { + DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno != WSREP_SEQNO_UNDEFINED); + if (wsrep->post_commit(wsrep, &thd->wsrep_ws_handle)) + { + DBUG_PRINT("wsrep", ("set committed fail")); + WSREP_WARN("set committed fail: %llu %d", + (long long)thd->real_id, thd->get_stmt_da()->status()); + } + wsrep_cleanup_transaction(thd); + } +} + +/* + wsrep exploits binlog's caches even if binlogging itself is not + activated. In such case connection close needs calling + actual binlog's method. + Todo: split binlog hton from its caches to use ones by wsrep + without referring to binlog's stuff. +*/ +static int +wsrep_close_connection(handlerton* hton, THD* thd) +{ + DBUG_ENTER("wsrep_close_connection"); + + if (thd->wsrep_exec_mode == REPL_RECV) + { + DBUG_RETURN(0); + } + DBUG_RETURN(wsrep_binlog_close_connection (thd)); +} + +/* + prepare/wsrep_run_wsrep_commit can fail in two ways + - certification test or an equivalent. As a result, + the current transaction just rolls back + Error codes: + WSREP_TRX_CERT_FAIL, WSREP_TRX_SIZE_EXCEEDED, WSREP_TRX_ERROR + - a post-certification failure makes this server unable to + commit its own WS and therefore the server must abort +*/ +static int wsrep_prepare(handlerton *hton, THD *thd, bool all) +{ + DBUG_ENTER("wsrep_prepare"); + + if (thd->wsrep_exec_mode == REPL_RECV) + { + DBUG_RETURN(0); + } + + DBUG_ASSERT(thd->ha_data[wsrep_hton->slot].ha_info[all].is_trx_read_write()); + DBUG_ASSERT(thd->wsrep_exec_mode == LOCAL_STATE); + DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno == WSREP_SEQNO_UNDEFINED); + + if ((all || + !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) && + (thd->variables.wsrep_on && !wsrep_trans_cache_is_empty(thd))) + { + DBUG_RETURN (wsrep_run_wsrep_commit(thd, hton, all)); + } + DBUG_RETURN(0); +} + +static int wsrep_savepoint_set(handlerton *hton, THD *thd, void *sv) +{ + DBUG_ENTER("wsrep_savepoint_set"); + + if (thd->wsrep_exec_mode == REPL_RECV) + { + DBUG_RETURN(0); + } + + if (!wsrep_emulate_bin_log) DBUG_RETURN(0); + int rcode = wsrep_binlog_savepoint_set(thd, sv); + DBUG_RETURN(rcode); +} + +static int wsrep_savepoint_rollback(handlerton *hton, THD *thd, void *sv) +{ + DBUG_ENTER("wsrep_savepoint_rollback"); + + if (thd->wsrep_exec_mode == REPL_RECV) + { + DBUG_RETURN(0); + } + + if (!wsrep_emulate_bin_log) DBUG_RETURN(0); + int rcode = wsrep_binlog_savepoint_rollback(thd, sv); + DBUG_RETURN(rcode); +} + +static int wsrep_rollback(handlerton *hton, THD *thd, bool all) +{ + DBUG_ENTER("wsrep_rollback"); + + if (thd->wsrep_exec_mode == REPL_RECV) + { + DBUG_RETURN(0); + } + + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + switch (thd->wsrep_exec_mode) + { + case TOTAL_ORDER: + case REPL_RECV: + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + WSREP_DEBUG("Avoiding wsrep rollback for failed DDL: %s", thd->query()); + DBUG_RETURN(0); + default: break; + } + + if ((all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) && + (thd->variables.wsrep_on && thd->wsrep_conflict_state != MUST_REPLAY)) + { + if (wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle)) + { + DBUG_PRINT("wsrep", ("setting rollback fail")); + WSREP_ERROR("settting rollback fail: thd: %llu SQL: %s", + (long long)thd->real_id, thd->query()); + } + wsrep_cleanup_transaction(thd); + } + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + DBUG_RETURN(0); +} + +int wsrep_commit(handlerton *hton, THD *thd, bool all) +{ + DBUG_ENTER("wsrep_commit"); + + if (thd->wsrep_exec_mode == REPL_RECV) + { + DBUG_RETURN(0); + } + + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + if ((all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) && + (thd->variables.wsrep_on && thd->wsrep_conflict_state != MUST_REPLAY)) + { + if (thd->wsrep_exec_mode == LOCAL_COMMIT) + { + DBUG_ASSERT(thd->ha_data[wsrep_hton->slot].ha_info[all].is_trx_read_write()); + /* + Call to wsrep->post_commit() (moved to wsrep_post_commit()) must + be done only after commit has done for all involved htons. + */ + DBUG_PRINT("wsrep", ("commit")); + } + else + { + /* + Transaction didn't go through wsrep->pre_commit() so just roll back + possible changes to clean state. + */ + if (WSREP_PROVIDER_EXISTS) { + if (wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle)) + { + DBUG_PRINT("wsrep", ("setting rollback fail")); + WSREP_ERROR("settting rollback fail: thd: %llu SQL: %s", + (long long)thd->real_id, thd->query()); + } + } + wsrep_cleanup_transaction(thd); + } + } + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + DBUG_RETURN(0); +} + + +extern Rpl_filter* binlog_filter; +extern my_bool opt_log_slave_updates; + +enum wsrep_trx_status +wsrep_run_wsrep_commit(THD *thd, handlerton *hton, bool all) +{ + int rcode= -1; + size_t data_len= 0; + IO_CACHE *cache; + int replay_round= 0; + + if (thd->get_stmt_da()->is_error()) { + WSREP_ERROR("commit issue, error: %d %s", + thd->get_stmt_da()->sql_errno(), thd->get_stmt_da()->message()); + } + + DBUG_ENTER("wsrep_run_wsrep_commit"); + + if (thd->slave_thread && !opt_log_slave_updates) DBUG_RETURN(WSREP_TRX_OK); + + if (thd->wsrep_exec_mode == REPL_RECV) { + + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + if (thd->wsrep_conflict_state == MUST_ABORT) { + if (wsrep_debug) + WSREP_INFO("WSREP: must abort for BF"); + DBUG_PRINT("wsrep", ("BF apply commit fail")); + thd->wsrep_conflict_state = NO_CONFLICT; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + // + // TODO: test all calls of the rollback. + // rollback must happen automagically innobase_rollback(hton, thd, 1); + // + DBUG_RETURN(WSREP_TRX_ERROR); + } + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } + + if (thd->wsrep_exec_mode != LOCAL_STATE) DBUG_RETURN(WSREP_TRX_OK); + + if (thd->wsrep_consistency_check == CONSISTENCY_CHECK_RUNNING) { + WSREP_DEBUG("commit for consistency check: %s", thd->query()); + DBUG_RETURN(WSREP_TRX_OK); + } + + DBUG_PRINT("wsrep", ("replicating commit")); + + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + if (thd->wsrep_conflict_state == MUST_ABORT) { + DBUG_PRINT("wsrep", ("replicate commit fail")); + thd->wsrep_conflict_state = ABORTED; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + if (wsrep_debug) { + WSREP_INFO("innobase_commit, abort %s", + (thd->query()) ? thd->query() : "void"); + } + DBUG_RETURN(WSREP_TRX_CERT_FAIL); + } + + mysql_mutex_lock(&LOCK_wsrep_replaying); + + while (wsrep_replaying > 0 && + thd->wsrep_conflict_state == NO_CONFLICT && + thd->killed == NOT_KILLED && + !shutdown_in_progress) + { + + mysql_mutex_unlock(&LOCK_wsrep_replaying); + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + + mysql_mutex_lock(&thd->mysys_var->mutex); + thd_proc_info(thd, "wsrep waiting on replaying"); + thd->mysys_var->current_mutex= &LOCK_wsrep_replaying; + thd->mysys_var->current_cond= &COND_wsrep_replaying; + mysql_mutex_unlock(&thd->mysys_var->mutex); + + mysql_mutex_lock(&LOCK_wsrep_replaying); + // Using timedwait is a hack to avoid deadlock in case if BF victim + // misses the signal. + struct timespec wtime = {0, 1000000}; + mysql_cond_timedwait(&COND_wsrep_replaying, &LOCK_wsrep_replaying, + &wtime); + + if (replay_round++ % 100000 == 0) + WSREP_DEBUG("commit waiting for replaying: replayers %d, thd: (%lu) " + "conflict: %d (round: %d)", + wsrep_replaying, thd->thread_id, + thd->wsrep_conflict_state, replay_round); + + mysql_mutex_unlock(&LOCK_wsrep_replaying); + + mysql_mutex_lock(&thd->mysys_var->mutex); + thd->mysys_var->current_mutex= 0; + thd->mysys_var->current_cond= 0; + mysql_mutex_unlock(&thd->mysys_var->mutex); + + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + mysql_mutex_lock(&LOCK_wsrep_replaying); + } + mysql_mutex_unlock(&LOCK_wsrep_replaying); + + if (thd->wsrep_conflict_state == MUST_ABORT) { + DBUG_PRINT("wsrep", ("replicate commit fail")); + thd->wsrep_conflict_state = ABORTED; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + WSREP_DEBUG("innobase_commit abort after replaying wait %s", + (thd->query()) ? thd->query() : "void"); + DBUG_RETURN(WSREP_TRX_CERT_FAIL); + } + + thd->wsrep_query_state = QUERY_COMMITTING; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + + cache = get_trans_log(thd); + rcode = 0; + if (cache) { + thd->binlog_flush_pending_rows_event(true); + rcode = wsrep_write_cache(wsrep, thd, cache, &data_len); + if (WSREP_OK != rcode) { + WSREP_ERROR("rbr write fail, data_len: %zu, %d", data_len, rcode); + DBUG_RETURN(WSREP_TRX_SIZE_EXCEEDED); + } + } + + if (data_len == 0) + { + if (thd->get_stmt_da()->is_ok() && + thd->get_stmt_da()->affected_rows() > 0 && + !binlog_filter->is_on()) + { + WSREP_DEBUG("empty rbr buffer, query: %s, " + "affected rows: %llu, " + "changed tables: %d, " + "sql_log_bin: %d, " + "wsrep status (%d %d %d)", + thd->query(), thd->get_stmt_da()->affected_rows(), + stmt_has_updated_trans_table(thd), thd->variables.sql_log_bin, + thd->wsrep_exec_mode, thd->wsrep_query_state, + thd->wsrep_conflict_state); + } + else + { + WSREP_DEBUG("empty rbr buffer, query: %s", thd->query()); + } + thd->wsrep_query_state= QUERY_EXEC; + DBUG_RETURN(WSREP_TRX_OK); + } + + if (WSREP_UNDEFINED_TRX_ID == thd->wsrep_ws_handle.trx_id) + { + WSREP_WARN("SQL statement was ineffective, THD: %lu, buf: %zu\n" + "QUERY: %s\n" + " => Skipping replication", + thd->thread_id, data_len, thd->query()); + rcode = WSREP_TRX_FAIL; + } + else if (!rcode) + { + if (WSREP_OK == rcode) + rcode = wsrep->pre_commit(wsrep, + (wsrep_conn_id_t)thd->thread_id, + &thd->wsrep_ws_handle, + WSREP_FLAG_COMMIT | + ((thd->wsrep_PA_safe) ? + 0ULL : WSREP_FLAG_PA_UNSAFE), + &thd->wsrep_trx_meta); + + if (rcode == WSREP_TRX_MISSING) { + WSREP_WARN("Transaction missing in provider, thd: %ld, SQL: %s", + thd->thread_id, thd->query()); + rcode = WSREP_TRX_FAIL; + } else if (rcode == WSREP_BF_ABORT) { + WSREP_DEBUG("thd %lu seqno %lld BF aborted by provider, will replay", + thd->thread_id, (long long)thd->wsrep_trx_meta.gtid.seqno); + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + thd->wsrep_conflict_state = MUST_REPLAY; + DBUG_ASSERT(wsrep_thd_trx_seqno(thd) > 0); + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + mysql_mutex_lock(&LOCK_wsrep_replaying); + wsrep_replaying++; + WSREP_DEBUG("replaying increased: %d, thd: %lu", + wsrep_replaying, thd->thread_id); + mysql_mutex_unlock(&LOCK_wsrep_replaying); + } + } else { + WSREP_ERROR("I/O error reading from thd's binlog iocache: " + "errno=%d, io cache code=%d", my_errno, cache->error); + DBUG_ASSERT(0); // failure like this can not normally happen + DBUG_RETURN(WSREP_TRX_ERROR); + } + + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + switch(rcode) { + case 0: + /* + About MUST_ABORT: We assume that even if thd conflict state was set + to MUST_ABORT, underlying transaction was not rolled back or marked + as deadlock victim in QUERY_COMMITTING state. Conflict state is + set to NO_CONFLICT and commit proceeds as usual. + */ + if (thd->wsrep_conflict_state == MUST_ABORT) + thd->wsrep_conflict_state= NO_CONFLICT; + + if (thd->wsrep_conflict_state != NO_CONFLICT) + { + WSREP_WARN("thd %lu seqno %lld: conflict state %d after post commit", + thd->thread_id, + (long long)thd->wsrep_trx_meta.gtid.seqno, + thd->wsrep_conflict_state); + } + thd->wsrep_exec_mode= LOCAL_COMMIT; + DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno != WSREP_SEQNO_UNDEFINED); + /* Override XID iff it was generated by mysql */ + if (thd->transaction.xid_state.xid.get_my_xid()) + { + wsrep_xid_init(&thd->transaction.xid_state.xid, + &thd->wsrep_trx_meta.gtid.uuid, + thd->wsrep_trx_meta.gtid.seqno); + } + DBUG_PRINT("wsrep", ("replicating commit success")); + break; + case WSREP_BF_ABORT: + DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno != WSREP_SEQNO_UNDEFINED); + case WSREP_TRX_FAIL: + WSREP_DEBUG("commit failed for reason: %d", rcode); + DBUG_PRINT("wsrep", ("replicating commit fail")); + + thd->wsrep_query_state= QUERY_EXEC; + + if (thd->wsrep_conflict_state == MUST_ABORT) { + thd->wsrep_conflict_state= ABORTED; + } + else + { + WSREP_DEBUG("conflict state: %d", thd->wsrep_conflict_state); + if (thd->wsrep_conflict_state == NO_CONFLICT) + { + thd->wsrep_conflict_state = CERT_FAILURE; + WSREP_LOG_CONFLICT(NULL, thd, FALSE); + } + } + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + + DBUG_RETURN(WSREP_TRX_CERT_FAIL); + + case WSREP_SIZE_EXCEEDED: + WSREP_ERROR("transaction size exceeded"); + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + DBUG_RETURN(WSREP_TRX_SIZE_EXCEEDED); + case WSREP_CONN_FAIL: + WSREP_ERROR("connection failure"); + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + DBUG_RETURN(WSREP_TRX_ERROR); + default: + WSREP_ERROR("unknown connection failure"); + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + DBUG_RETURN(WSREP_TRX_ERROR); + } + + thd->wsrep_query_state= QUERY_EXEC; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + + DBUG_RETURN(WSREP_TRX_OK); +} + + +static int wsrep_hton_init(void *p) +{ + wsrep_hton= (handlerton *)p; + //wsrep_hton->state=opt_bin_log ? SHOW_OPTION_YES : SHOW_OPTION_NO; + wsrep_hton->state= SHOW_OPTION_YES; + wsrep_hton->db_type=DB_TYPE_WSREP; + wsrep_hton->savepoint_offset= sizeof(my_off_t); + wsrep_hton->close_connection= wsrep_close_connection; + wsrep_hton->savepoint_set= wsrep_savepoint_set; + wsrep_hton->savepoint_rollback= wsrep_savepoint_rollback; + wsrep_hton->commit= wsrep_commit; + wsrep_hton->rollback= wsrep_rollback; + wsrep_hton->prepare= wsrep_prepare; + wsrep_hton->flags= HTON_NOT_USER_SELECTABLE | HTON_HIDDEN; // todo: fix flags + wsrep_hton->slot= 0; + return 0; +} + + +struct st_mysql_storage_engine wsrep_storage_engine= +{ MYSQL_HANDLERTON_INTERFACE_VERSION }; + + +mysql_declare_plugin(wsrep) +{ + MYSQL_STORAGE_ENGINE_PLUGIN, + &wsrep_storage_engine, + "wsrep", + "Codership Oy", + "A pseudo storage engine to represent transactions in multi-master " + "synchornous replication", + PLUGIN_LICENSE_GPL, + wsrep_hton_init, /* Plugin Init */ + NULL, /* Plugin Deinit */ + 0x0100 /* 1.0 */, + NULL, /* status variables */ + NULL, /* system variables */ + NULL, /* config options */ + 0, /* flags */ +} +mysql_declare_plugin_end; diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc new file mode 100644 index 00000000000..a9344b0a946 --- /dev/null +++ b/sql/wsrep_mysqld.cc @@ -0,0 +1,1562 @@ +/* Copyright 2008-2013 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include +#include +#include +#include "wsrep_priv.h" +#include "wsrep_thd.h" +#include "wsrep_sst.h" +#include "wsrep_utils.h" +#include "wsrep_var.h" +#include "wsrep_binlog.h" +#include "wsrep_applier.h" +#include +#include +#include "log_event.h" +#include + +wsrep_t *wsrep = NULL; +my_bool wsrep_emulate_bin_log = FALSE; // activating parts of binlog interface +#ifdef GTID_SUPPORT +/* Sidno in global_sid_map corresponding to group uuid */ +rpl_sidno wsrep_sidno= -1; +#endif /* GTID_SUPPORT */ +my_bool wsrep_preordered_opt= FALSE; + +/* + * Begin configuration options and their default values + */ + +const char* wsrep_data_home_dir = NULL; +const char* wsrep_dbug_option = ""; + +long wsrep_slave_threads = 1; // # of slave action appliers wanted +int wsrep_slave_count_change = 0; // # of appliers to stop or start +my_bool wsrep_debug = 0; // enable debug level logging +my_bool wsrep_convert_LOCK_to_trx = 1; // convert locking sessions to trx +ulong wsrep_retry_autocommit = 5; // retry aborted autocommit trx +my_bool wsrep_auto_increment_control = 1; // control auto increment variables +my_bool wsrep_drupal_282555_workaround = 1; // retry autoinc insert after dupkey +my_bool wsrep_incremental_data_collection = 0; // incremental data collection +ulong wsrep_max_ws_size = 1073741824UL;//max ws (RBR buffer) size +ulong wsrep_max_ws_rows = 65536; // max number of rows in ws +int wsrep_to_isolation = 0; // # of active TO isolation threads +my_bool wsrep_certify_nonPK = 1; // certify, even when no primary key +long wsrep_max_protocol_version = 3; // maximum protocol version to use +ulong wsrep_forced_binlog_format = BINLOG_FORMAT_UNSPEC; +my_bool wsrep_recovery = 0; // recovery +my_bool wsrep_replicate_myisam = 0; // enable myisam replication +my_bool wsrep_log_conflicts = 0; +ulong wsrep_mysql_replication_bundle = 0; +my_bool wsrep_desync = 0; // desynchronize the node from the + // cluster +my_bool wsrep_load_data_splitting = 1; // commit load data every 10K intervals +my_bool wsrep_restart_slave = 0; // should mysql slave thread be + // restarted, if node joins back +my_bool wsrep_restart_slave_activated = 0; // node has dropped, and slave + // restart will be needed +my_bool wsrep_slave_UK_checks = 0; // slave thread does UK checks +my_bool wsrep_slave_FK_checks = 0; // slave thread does FK checks +/* + * End configuration options + */ + +/* + * Other wsrep global variables. + */ +my_bool wsrep_inited = 0; // initialized ? + +static const wsrep_uuid_t cluster_uuid = WSREP_UUID_UNDEFINED; +static char cluster_uuid_str[40]= { 0, }; +static const char* cluster_status_str[WSREP_VIEW_MAX] = +{ + "Primary", + "non-Primary", + "Disconnected" +}; + +static char provider_name[256]= { 0, }; +static char provider_version[256]= { 0, }; +static char provider_vendor[256]= { 0, }; + +/* + * wsrep status variables + */ +my_bool wsrep_connected = FALSE; +my_bool wsrep_ready = FALSE; // node can accept queries +const char* wsrep_cluster_state_uuid = cluster_uuid_str; +long long wsrep_cluster_conf_id = WSREP_SEQNO_UNDEFINED; +const char* wsrep_cluster_status = cluster_status_str[WSREP_VIEW_DISCONNECTED]; +long wsrep_cluster_size = 0; +long wsrep_local_index = -1; +long long wsrep_local_bf_aborts = 0; +const char* wsrep_provider_name = provider_name; +const char* wsrep_provider_version = provider_version; +const char* wsrep_provider_vendor = provider_vendor; +/* End wsrep status variables */ + +wsrep_uuid_t local_uuid = WSREP_UUID_UNDEFINED; +wsrep_seqno_t local_seqno = WSREP_SEQNO_UNDEFINED; +wsp::node_status local_status; +long wsrep_protocol_version = 3; + +// Boolean denoting if server is in initial startup phase. This is needed +// to make sure that main thread waiting in wsrep_sst_wait() is signaled +// if there was no state gap on receiving first view event. +static my_bool wsrep_startup = TRUE; + + +static void wsrep_log_cb(wsrep_log_level_t level, const char *msg) { + switch (level) { + case WSREP_LOG_INFO: + sql_print_information("WSREP: %s", msg); + break; + case WSREP_LOG_WARN: + sql_print_warning("WSREP: %s", msg); + break; + case WSREP_LOG_ERROR: + case WSREP_LOG_FATAL: + sql_print_error("WSREP: %s", msg); + break; + case WSREP_LOG_DEBUG: + sql_print_information ("[Debug] WSREP: %s", msg); + default: + break; + } +} + +static void wsrep_log_states (wsrep_log_level_t const level, + const wsrep_uuid_t* const group_uuid, + wsrep_seqno_t const group_seqno, + const wsrep_uuid_t* const node_uuid, + wsrep_seqno_t const node_seqno) +{ + char uuid_str[37]; + char msg[256]; + + wsrep_uuid_print (group_uuid, uuid_str, sizeof(uuid_str)); + snprintf (msg, 255, "WSREP: Group state: %s:%lld", + uuid_str, (long long)group_seqno); + wsrep_log_cb (level, msg); + + wsrep_uuid_print (node_uuid, uuid_str, sizeof(uuid_str)); + snprintf (msg, 255, "WSREP: Local state: %s:%lld", + uuid_str, (long long)node_seqno); + wsrep_log_cb (level, msg); +} + +static my_bool set_SE_checkpoint(THD* unused, plugin_ref plugin, void* arg) +{ + XID* xid= reinterpret_cast(arg); + handlerton* hton= plugin_data(plugin, handlerton *); + if (hton->db_type == DB_TYPE_INNODB) + { + const wsrep_uuid_t* uuid(wsrep_xid_uuid(xid)); + char uuid_str[40] = {0, }; + wsrep_uuid_print(uuid, uuid_str, sizeof(uuid_str)); + WSREP_DEBUG("Set WSREPXid for InnoDB: %s:%lld", + uuid_str, (long long)wsrep_xid_seqno(xid)); + hton->wsrep_set_checkpoint(hton, xid); + } + return FALSE; +} + +void wsrep_set_SE_checkpoint(XID* xid) +{ + plugin_foreach(NULL, set_SE_checkpoint, MYSQL_STORAGE_ENGINE_PLUGIN, xid); +} + +static my_bool get_SE_checkpoint(THD* unused, plugin_ref plugin, void* arg) +{ + XID* xid= reinterpret_cast(arg); + handlerton* hton= plugin_data(plugin, handlerton *); + if (hton->db_type == DB_TYPE_INNODB) + { + hton->wsrep_get_checkpoint(hton, xid); + const wsrep_uuid_t* uuid(wsrep_xid_uuid(xid)); + char uuid_str[40] = {0, }; + wsrep_uuid_print(uuid, uuid_str, sizeof(uuid_str)); + WSREP_DEBUG("Read WSREPXid from InnoDB: %s:%lld", + uuid_str, (long long)wsrep_xid_seqno(xid)); + + } + return FALSE; +} + +void wsrep_get_SE_checkpoint(XID* xid) +{ + plugin_foreach(NULL, get_SE_checkpoint, MYSQL_STORAGE_ENGINE_PLUGIN, xid); +} + +#ifdef GTID_SUPPORT +void wsrep_init_sidno(const wsrep_uuid_t& uuid) +{ + /* generate new Sid map entry from inverted uuid */ + rpl_sid sid; + wsrep_uuid_t ltid_uuid; + for (size_t i= 0; i < sizeof(ltid_uuid.data); ++i) + { + ltid_uuid.data[i] = ~local_uuid.data[i]; + } + sid.copy_from(ltid_uuid.data); + global_sid_lock->wrlock(); + wsrep_sidno= global_sid_map->add_sid(sid); + WSREP_INFO("inited wsrep sidno %d", wsrep_sidno); + global_sid_lock->unlock(); +} +#endif /* GTID_SUPPORT */ + +static wsrep_cb_status_t +wsrep_view_handler_cb (void* app_ctx, + void* recv_ctx, + const wsrep_view_info_t* view, + const char* state, + size_t state_len, + void** sst_req, + size_t* sst_req_len) +{ + *sst_req = NULL; + *sst_req_len = 0; + + wsrep_member_status_t new_status= local_status.get(); + + if (memcmp(&cluster_uuid, &view->state_id.uuid, sizeof(wsrep_uuid_t))) + { + memcpy((wsrep_uuid_t*)&cluster_uuid, &view->state_id.uuid, + sizeof(cluster_uuid)); + + wsrep_uuid_print (&cluster_uuid, cluster_uuid_str, + sizeof(cluster_uuid_str)); + } + + wsrep_cluster_conf_id= view->view; + wsrep_cluster_status= cluster_status_str[view->status]; + wsrep_cluster_size= view->memb_num; + wsrep_local_index= view->my_idx; + + WSREP_INFO("New cluster view: global state: %s:%lld, view# %lld: %s, " + "number of nodes: %ld, my index: %ld, protocol version %d", + wsrep_cluster_state_uuid, (long long)view->state_id.seqno, + (long long)wsrep_cluster_conf_id, wsrep_cluster_status, + wsrep_cluster_size, wsrep_local_index, view->proto_ver); + + /* Proceed further only if view is PRIMARY */ + if (WSREP_VIEW_PRIMARY != view->status) { + wsrep_ready_set(FALSE); + new_status= WSREP_MEMBER_UNDEFINED; + /* Always record local_uuid and local_seqno in non-prim since this + * may lead to re-initializing provider and start position is + * determined according to these variables */ + // WRONG! local_uuid should be the last primary configuration uuid we were + // a member of. local_seqno should be updated in commit calls. + // local_uuid= cluster_uuid; + // local_seqno= view->first - 1; + goto out; + } + + switch (view->proto_ver) + { + case 0: + case 1: + case 2: + case 3: + // version change + if (view->proto_ver != wsrep_protocol_version) + { + my_bool wsrep_ready_saved= wsrep_ready; + wsrep_ready_set(FALSE); + WSREP_INFO("closing client connections for " + "protocol change %ld -> %d", + wsrep_protocol_version, view->proto_ver); + wsrep_close_client_connections(TRUE); + wsrep_protocol_version= view->proto_ver; + wsrep_ready_set(wsrep_ready_saved); + } + break; + default: + WSREP_ERROR("Unsupported application protocol version: %d", + view->proto_ver); + unireg_abort(1); + } + + if (view->state_gap) + { + WSREP_WARN("Gap in state sequence. Need state transfer."); + + /* After that wsrep will call wsrep_sst_prepare. */ + /* keep ready flag 0 until we receive the snapshot */ + wsrep_ready_set(FALSE); + + /* Close client connections to ensure that they don't interfere + * with SST */ + WSREP_DEBUG("[debug]: closing client connections for PRIM"); + wsrep_close_client_connections(TRUE); + + ssize_t const req_len= wsrep_sst_prepare (sst_req); + + if (req_len < 0) + { + WSREP_ERROR("SST preparation failed: %zd (%s)", -req_len, + strerror(-req_len)); + new_status= WSREP_MEMBER_UNDEFINED; + } + else + { + assert(sst_req != NULL); + *sst_req_len= req_len; + new_status= WSREP_MEMBER_JOINER; + } + } + else + { + /* + * NOTE: Initialize wsrep_group_uuid here only if it wasn't initialized + * before - OR - it was reinitilized on startup (lp:992840) + */ + if (wsrep_startup) + { + if (wsrep_before_SE()) + { + wsrep_SE_init_grab(); + // Signal mysqld init thread to continue + wsrep_sst_complete (&cluster_uuid, view->state_id.seqno, false); + // and wait for SE initialization + wsrep_SE_init_wait(); + } + else + { + local_uuid= cluster_uuid; + local_seqno= view->state_id.seqno; + } + /* Init storage engine XIDs from first view */ + XID xid; + wsrep_xid_init(&xid, &local_uuid, local_seqno); + wsrep_set_SE_checkpoint(&xid); + new_status= WSREP_MEMBER_JOINED; +#ifdef GTID_SUPPORT + wsrep_init_sidno(local_uuid); +#endif /* GTID_SUPPORT */ + } + + // just some sanity check + if (memcmp (&local_uuid, &cluster_uuid, sizeof (wsrep_uuid_t))) + { + WSREP_ERROR("Undetected state gap. Can't continue."); + wsrep_log_states(WSREP_LOG_FATAL, &cluster_uuid, view->state_id.seqno, + &local_uuid, -1); + unireg_abort(1); + } + } + + if (wsrep_auto_increment_control) + { + global_system_variables.auto_increment_offset= view->my_idx + 1; + global_system_variables.auto_increment_increment= view->memb_num; + } + + { /* capabilities may be updated on new configuration */ + uint64_t const caps(wsrep->capabilities (wsrep)); + + my_bool const idc((caps & WSREP_CAP_INCREMENTAL_WRITESET) != 0); + if (TRUE == wsrep_incremental_data_collection && FALSE == idc) + { + WSREP_WARN("Unsupported protocol downgrade: " + "incremental data collection disabled. Expect abort."); + } + wsrep_incremental_data_collection = idc; + } + +out: + if (view->status == WSREP_VIEW_PRIMARY) wsrep_startup= FALSE; + local_status.set(new_status, view); + + return WSREP_CB_SUCCESS; +} + +void wsrep_ready_set (my_bool x) +{ + WSREP_DEBUG("Setting wsrep_ready to %d", x); + if (mysql_mutex_lock (&LOCK_wsrep_ready)) abort(); + if (wsrep_ready != x) + { + wsrep_ready= x; + mysql_cond_signal (&COND_wsrep_ready); + } + mysql_mutex_unlock (&LOCK_wsrep_ready); +} + +// Wait until wsrep has reached ready state +void wsrep_ready_wait () +{ + if (mysql_mutex_lock (&LOCK_wsrep_ready)) abort(); + while (!wsrep_ready) + { + WSREP_INFO("Waiting to reach ready state"); + mysql_cond_wait (&COND_wsrep_ready, &LOCK_wsrep_ready); + } + WSREP_INFO("ready state reached"); + mysql_mutex_unlock (&LOCK_wsrep_ready); +} + +static void wsrep_synced_cb(void* app_ctx) +{ + WSREP_INFO("Synchronized with group, ready for connections"); + bool signal_main= false; + if (mysql_mutex_lock (&LOCK_wsrep_ready)) abort(); + if (!wsrep_ready) + { + wsrep_ready= TRUE; + mysql_cond_signal (&COND_wsrep_ready); + signal_main= true; + + } + local_status.set(WSREP_MEMBER_SYNCED); + mysql_mutex_unlock (&LOCK_wsrep_ready); + + if (signal_main) + { + wsrep_SE_init_grab(); + // Signal mysqld init thread to continue + wsrep_sst_complete (&local_uuid, local_seqno, false); + // and wait for SE initialization + wsrep_SE_init_wait(); + } + if (wsrep_restart_slave_activated) + { + int rcode; + WSREP_INFO("MySQL slave restart"); + wsrep_restart_slave_activated= FALSE; + + mysql_mutex_lock(&LOCK_active_mi); + if ((rcode = start_slave_threads(1 /* need mutex */, + 0 /* no wait for start*/, + active_mi, + master_info_file, + relay_log_info_file, + SLAVE_SQL))) + { + WSREP_WARN("Failed to create slave threads: %d", rcode); + } + mysql_mutex_unlock(&LOCK_active_mi); + + } +} + +static void wsrep_init_position() +{ + /* read XIDs from storage engines */ + XID xid; + memset(&xid, 0, sizeof(xid)); + xid.formatID= -1; + wsrep_get_SE_checkpoint(&xid); + + if (xid.formatID == -1) + { + WSREP_INFO("Read nil XID from storage engines, skipping position init"); + return; + } + else if (!wsrep_is_wsrep_xid(&xid)) + { + WSREP_WARN("Read non-wsrep XID from storage engines, skipping position init"); + return; + } + + const wsrep_uuid_t* uuid= wsrep_xid_uuid(&xid); + const wsrep_seqno_t seqno= wsrep_xid_seqno(&xid); + + char uuid_str[40] = {0, }; + wsrep_uuid_print(uuid, uuid_str, sizeof(uuid_str)); + WSREP_INFO("Initial position: %s:%lld", uuid_str, (long long)seqno); + + + if (!memcmp(&local_uuid, &WSREP_UUID_UNDEFINED, sizeof(local_uuid)) && + local_seqno == WSREP_SEQNO_UNDEFINED) + { + // Initial state + local_uuid= *uuid; + local_seqno= seqno; + } + else if (memcmp(&local_uuid, uuid, sizeof(local_uuid)) || + local_seqno != seqno) + { + WSREP_WARN("Initial position was provided by configuration or SST, " + "avoiding override"); + } +} + +extern char* my_bind_addr_str; + +int wsrep_init() +{ + int rcode= -1; + DBUG_ASSERT(wsrep_inited == 0); + + wsrep_ready_set(FALSE); + assert(wsrep_provider); + + wsrep_init_position(); + + if ((rcode= wsrep_load(wsrep_provider, &wsrep, wsrep_log_cb)) != WSREP_OK) + { + if (strcasecmp(wsrep_provider, WSREP_NONE)) + { + WSREP_ERROR("wsrep_load(%s) failed: %s (%d). Reverting to no provider.", + wsrep_provider, strerror(rcode), rcode); + strcpy((char*)wsrep_provider, WSREP_NONE); // damn it's a dirty hack + (void) wsrep_init(); + return rcode; + } + else /* this is for recursive call above */ + { + WSREP_ERROR("Could not revert to no provider: %s (%d). Need to abort.", + strerror(rcode), rcode); + unireg_abort(1); + } + } + + if (!WSREP_PROVIDER_EXISTS) + { + // enable normal operation in case no provider is specified + wsrep_ready_set(TRUE); + wsrep_inited= 1; + global_system_variables.wsrep_on = 0; + wsrep_init_args args; + args.logger_cb = wsrep_log_cb; + args.options = (wsrep_provider_options) ? + wsrep_provider_options : ""; + rcode = wsrep->init(wsrep, &args); + if (rcode) + { + DBUG_PRINT("wsrep",("wsrep::init() failed: %d", rcode)); + WSREP_ERROR("wsrep::init() failed: %d, must shutdown", rcode); + wsrep->free(wsrep); + free(wsrep); + wsrep = NULL; + } + return rcode; + } + else + { + global_system_variables.wsrep_on = 1; + strncpy(provider_name, + wsrep->provider_name, sizeof(provider_name) - 1); + strncpy(provider_version, + wsrep->provider_version, sizeof(provider_version) - 1); + strncpy(provider_vendor, + wsrep->provider_vendor, sizeof(provider_vendor) - 1); + } + + if (!wsrep_data_home_dir || strlen(wsrep_data_home_dir) == 0) + wsrep_data_home_dir = mysql_real_data_home; + + char node_addr[512]= { 0, }; + size_t const node_addr_max= sizeof(node_addr) - 1; + if (!wsrep_node_address || !strcmp(wsrep_node_address, "")) + { + size_t const ret= wsrep_guess_ip(node_addr, node_addr_max); + if (!(ret > 0 && ret < node_addr_max)) + { + WSREP_WARN("Failed to guess base node address. Set it explicitly via " + "wsrep_node_address."); + node_addr[0]= '\0'; + } + } + else + { + strncpy(node_addr, wsrep_node_address, node_addr_max); + } + + char inc_addr[512]= { 0, }; + size_t const inc_addr_max= sizeof (inc_addr); + if ((!wsrep_node_incoming_address || + !strcmp (wsrep_node_incoming_address, WSREP_NODE_INCOMING_AUTO))) + { + unsigned int my_bind_ip= INADDR_ANY; // default if not set + if (my_bind_addr_str && strlen(my_bind_addr_str)) + { + my_bind_ip= wsrep_check_ip(my_bind_addr_str); + } + + if (INADDR_ANY != my_bind_ip) + { + if (INADDR_NONE != my_bind_ip && INADDR_LOOPBACK != my_bind_ip) + { + snprintf(inc_addr, inc_addr_max, "%s:%u", + my_bind_addr_str, (int)mysqld_port); + } // else leave inc_addr an empty string - mysqld is not listening for + // client connections on network interfaces. + } + else // mysqld binds to 0.0.0.0, take IP from wsrep_node_address if possible + { + size_t const node_addr_len= strlen(node_addr); + if (node_addr_len > 0) + { + const char* const colon= strrchr(node_addr, ':'); + if (strchr(node_addr, ':') == colon) // 1 or 0 ':' + { + size_t const ip_len= colon ? colon - node_addr : node_addr_len; + if (ip_len + 7 /* :55555\0 */ < inc_addr_max) + { + memcpy (inc_addr, node_addr, ip_len); + snprintf(inc_addr + ip_len, inc_addr_max - ip_len, ":%u", + (int)mysqld_port); + } + else + { + WSREP_WARN("Guessing address for incoming client connections: " + "address too long."); + inc_addr[0]= '\0'; + } + } + else + { + WSREP_WARN("Guessing address for incoming client connections: " + "too many colons :) ."); + inc_addr[0]= '\0'; + } + } + + if (!strlen(inc_addr)) + { + WSREP_WARN("Guessing address for incoming client connections failed. " + "Try setting wsrep_node_incoming_address explicitly."); + } + } + } + else if (!strchr(wsrep_node_incoming_address, ':')) // no port included + { + if ((int)inc_addr_max <= + snprintf(inc_addr, inc_addr_max, "%s:%u", + wsrep_node_incoming_address,(int)mysqld_port)) + { + WSREP_WARN("Guessing address for incoming client connections: " + "address too long."); + inc_addr[0]= '\0'; + } + } + else + { + size_t const need = strlen (wsrep_node_incoming_address); + if (need >= inc_addr_max) { + WSREP_WARN("wsrep_node_incoming_address too long: %zu", need); + inc_addr[0]= '\0'; + } + else { + memcpy (inc_addr, wsrep_node_incoming_address, need); + } + } + + struct wsrep_init_args wsrep_args; + + struct wsrep_gtid const state_id = { local_uuid, local_seqno }; + + wsrep_args.data_dir = wsrep_data_home_dir; + wsrep_args.node_name = (wsrep_node_name) ? wsrep_node_name : ""; + wsrep_args.node_address = node_addr; + wsrep_args.node_incoming = inc_addr; + wsrep_args.options = (wsrep_provider_options) ? + wsrep_provider_options : ""; + wsrep_args.proto_ver = wsrep_max_protocol_version; + + wsrep_args.state_id = &state_id; + + wsrep_args.logger_cb = wsrep_log_cb; + wsrep_args.view_handler_cb = wsrep_view_handler_cb; + wsrep_args.apply_cb = wsrep_apply_cb; + wsrep_args.commit_cb = wsrep_commit_cb; + wsrep_args.unordered_cb = wsrep_unordered_cb; + wsrep_args.sst_donate_cb = wsrep_sst_donate_cb; + wsrep_args.synced_cb = wsrep_synced_cb; + + rcode = wsrep->init(wsrep, &wsrep_args); + + if (rcode) + { + DBUG_PRINT("wsrep",("wsrep::init() failed: %d", rcode)); + WSREP_ERROR("wsrep::init() failed: %d, must shutdown", rcode); + wsrep->free(wsrep); + free(wsrep); + wsrep = NULL; + } else { + wsrep_inited= 1; + } + + return rcode; +} + +extern int wsrep_on(void *); + +void wsrep_init_startup (bool first) +{ + if (wsrep_init()) unireg_abort(1); + + wsrep_thr_lock_init(wsrep_thd_is_BF, wsrep_abort_thd, + wsrep_debug, wsrep_convert_LOCK_to_trx, wsrep_on); + + /* Skip replication start if no cluster address */ + if (!wsrep_cluster_address || strlen(wsrep_cluster_address) == 0) return; + + if (first) wsrep_sst_grab(); // do it so we can wait for SST below + + if (!wsrep_start_replication()) unireg_abort(1); + + wsrep_create_rollbacker(); + wsrep_create_appliers(1); + + if (first && !wsrep_sst_wait()) unireg_abort(1);// wait until SST is completed +} + + +void wsrep_deinit(bool free_options) +{ + DBUG_ASSERT(wsrep_inited == 1); + wsrep_unload(wsrep); + wsrep= 0; + provider_name[0]= '\0'; + provider_version[0]= '\0'; + provider_vendor[0]= '\0'; + wsrep_inited= 0; + + if (free_options) + { + wsrep_sst_auth_free(); + } +} + +void wsrep_recover() +{ + if (!memcmp(&local_uuid, &WSREP_UUID_UNDEFINED, sizeof(wsrep_uuid_t)) && + local_seqno == -2) + { + char uuid_str[40]; + wsrep_uuid_print(&local_uuid, uuid_str, sizeof(uuid_str)); + WSREP_INFO("Position %s:%lld given at startup, skipping position recovery", + uuid_str, (long long)local_seqno); + return; + } + XID xid; + memset(&xid, 0, sizeof(xid)); + xid.formatID= -1; + wsrep_get_SE_checkpoint(&xid); + char uuid_str[40]; + wsrep_uuid_print(wsrep_xid_uuid(&xid), uuid_str, sizeof(uuid_str)); + WSREP_INFO("Recovered position: %s:%lld", uuid_str, + (long long)wsrep_xid_seqno(&xid)); +} + + +void wsrep_stop_replication(THD *thd) +{ + WSREP_INFO("Stop replication"); + if (!wsrep) + { + WSREP_INFO("Provider was not loaded, in stop replication"); + return; + } + + /* disconnect from group first to get wsrep_ready == FALSE */ + WSREP_DEBUG("Provider disconnect"); + wsrep->disconnect(wsrep); + + wsrep_connected= FALSE; + + wsrep_close_client_connections(TRUE); + + /* wait until appliers have stopped */ + wsrep_wait_appliers_close(thd); + + return; +} + +/* This one is set to true when --wsrep-new-cluster is found in the command + * line arguments */ +static my_bool wsrep_new_cluster= FALSE; +#define WSREP_NEW_CLUSTER "--wsrep-new-cluster" +/* Finds and hides --wsrep-new-cluster from the arguments list + * by moving it to the end of the list and decrementing argument count */ +void wsrep_filter_new_cluster (int* argc, char* argv[]) +{ + int i; + for (i= *argc - 1; i > 0; i--) + { + /* make a copy of the argument to convert possible underscores to hyphens. + * the copy need not to be longer than WSREP_NEW_CLUSTER option */ + char arg[sizeof(WSREP_NEW_CLUSTER) + 2]= { 0, }; + strncpy(arg, argv[i], sizeof(arg) - 1); + char* underscore; + while (NULL != (underscore= strchr(arg, '_'))) *underscore= '-'; + + if (!strcmp(arg, WSREP_NEW_CLUSTER)) + { + wsrep_new_cluster= TRUE; + *argc -= 1; + /* preserve the order of remaining arguments AND + * preserve the original argument pointers - just in case */ + char* wnc= argv[i]; + memmove(&argv[i], &argv[i + 1], (*argc - i)*sizeof(argv[i])); + argv[*argc]= wnc; /* this will be invisible to the rest of the program */ + } + } +} + +bool wsrep_start_replication() +{ + wsrep_status_t rcode; + + /* + if provider is trivial, don't even try to connect, + but resume local node operation + */ + if (!WSREP_PROVIDER_EXISTS) + { + // enable normal operation in case no provider is specified + wsrep_ready_set(TRUE); + return true; + } + + if (!wsrep_cluster_address || strlen(wsrep_cluster_address)== 0) + { + // if provider is non-trivial, but no address is specified, wait for address + wsrep_ready_set(FALSE); + return true; + } + + bool const bootstrap(TRUE == wsrep_new_cluster); + wsrep_new_cluster= FALSE; + + WSREP_INFO("Start replication"); + + if ((rcode = wsrep->connect(wsrep, + wsrep_cluster_name, + wsrep_cluster_address, + wsrep_sst_donor, + bootstrap))) + { + if (-ESOCKTNOSUPPORT == rcode) + { + DBUG_PRINT("wsrep",("unrecognized cluster address: '%s', rcode: %d", + wsrep_cluster_address, rcode)); + WSREP_ERROR("unrecognized cluster address: '%s', rcode: %d", + wsrep_cluster_address, rcode); + } + else + { + DBUG_PRINT("wsrep",("wsrep->connect() failed: %d", rcode)); + WSREP_ERROR("wsrep::connect() failed: %d", rcode); + } + + return false; + } + else + { + wsrep_connected= TRUE; + + char* opts= wsrep->options_get(wsrep); + if (opts) + { + wsrep_provider_options_init(opts); + free(opts); + } + else + { + WSREP_WARN("Failed to get wsrep options"); + } + } + + return true; +} + +bool +wsrep_causal_wait (THD* thd) +{ + if (thd->variables.wsrep_causal_reads && thd->variables.wsrep_on && + !thd->in_active_multi_stmt_transaction() && + thd->wsrep_conflict_state != REPLAYING) + { + // This allows autocommit SELECTs and a first SELECT after SET AUTOCOMMIT=0 + // TODO: modify to check if thd has locked any rows. + wsrep_gtid_t gtid; + wsrep_status_t ret= wsrep->causal_read (wsrep, >id); + + if (unlikely(WSREP_OK != ret)) + { + const char* msg; + int err; + + // Possibly relevant error codes: + // ER_CHECKREAD, ER_ERROR_ON_READ, ER_INVALID_DEFAULT, ER_EMPTY_QUERY, + // ER_FUNCTION_NOT_DEFINED, ER_NOT_ALLOWED_COMMAND, ER_NOT_SUPPORTED_YET, + // ER_FEATURE_DISABLED, ER_QUERY_INTERRUPTED + + switch (ret) + { + case WSREP_NOT_IMPLEMENTED: + msg= "consistent reads by wsrep backend. " + "Please unset wsrep_causal_reads variable."; + err= ER_NOT_SUPPORTED_YET; + break; + default: + msg= "Causal wait failed."; + err= ER_LOCK_WAIT_TIMEOUT; // NOTE: the above msg won't be displayed + // with ER_LOCK_WAIT_TIMEOUT + } + + my_error(err, MYF(0), msg); + + return true; + } + } + + return false; +} + +/* + * Helpers to deal with TOI key arrays + */ +typedef struct wsrep_key_arr +{ + wsrep_key_t* keys; + size_t keys_len; +} wsrep_key_arr_t; + + +static void wsrep_keys_free(wsrep_key_arr_t* key_arr) +{ + for (size_t i= 0; i < key_arr->keys_len; ++i) + { + my_free((void*)key_arr->keys[i].key_parts); + } + my_free(key_arr->keys); + key_arr->keys= 0; + key_arr->keys_len= 0; +} + + +/*! + * @param db Database string + * @param table Table string + * @param key Array of wsrep_key_t + * @param key_len In: number of elements in key array, Out: number of + * elements populated + * + * @return true if preparation was successful, otherwise false. + */ + +static bool wsrep_prepare_key_for_isolation(const char* db, + const char* table, + wsrep_buf_t* key, + size_t* key_len) +{ + if (*key_len < 2) return false; + + switch (wsrep_protocol_version) + { + case 0: + *key_len= 0; + break; + case 1: + case 2: + case 3: + { + *key_len= 0; + if (db) + { + // sql_print_information("%s.%s", db, table); + if (db) + { + key[*key_len].ptr= db; + key[*key_len].len= strlen(db); + ++(*key_len); + if (table) + { + key[*key_len].ptr= table; + key[*key_len].len= strlen(table); + ++(*key_len); + } + } + } + break; + } + default: + return false; + } + + return true; +} + +/* Prepare key list from db/table and table_list */ +static bool wsrep_prepare_keys_for_isolation(THD* thd, + const char* db, + const char* table, + const TABLE_LIST* table_list, + wsrep_key_arr_t* ka) +{ + ka->keys= 0; + ka->keys_len= 0; + + extern TABLE* find_temporary_table(THD*, const TABLE_LIST*); + + if (db || table) + { + TABLE_LIST tmp_table; + MDL_request mdl_request; + + memset(&tmp_table, 0, sizeof(tmp_table)); + tmp_table.table_name= (char*)table; + tmp_table.db= (char*)db; + tmp_table.mdl_request.init(MDL_key::GLOBAL, (db) ? db : "", + (table) ? table : "", + MDL_INTENTION_EXCLUSIVE, MDL_STATEMENT); + + if (!table || !find_temporary_table(thd, &tmp_table)) + { + if (!(ka->keys= (wsrep_key_t*)my_malloc(sizeof(wsrep_key_t), MYF(0)))) + { + WSREP_ERROR("Can't allocate memory for key_array"); + goto err; + } + ka->keys_len= 1; + if (!(ka->keys[0].key_parts= (wsrep_buf_t*) + my_malloc(sizeof(wsrep_buf_t)*2, MYF(0)))) + { + WSREP_ERROR("Can't allocate memory for key_parts"); + goto err; + } + ka->keys[0].key_parts_num= 2; + if (!wsrep_prepare_key_for_isolation( + db, table, + (wsrep_buf_t*)ka->keys[0].key_parts, + &ka->keys[0].key_parts_num)) + { + WSREP_ERROR("Preparing keys for isolation failed"); + goto err; + } + } + } + + for (const TABLE_LIST* table= table_list; table; table= table->next_global) + { + if (!find_temporary_table(thd, table)) + { + wsrep_key_t* tmp; + tmp= (wsrep_key_t*)my_realloc( + ka->keys, (ka->keys_len + 1) * sizeof(wsrep_key_t), + MYF(MY_ALLOW_ZERO_PTR)); + + if (!tmp) + { + WSREP_ERROR("Can't allocate memory for key_array"); + goto err; + } + ka->keys= tmp; + if (!(ka->keys[ka->keys_len].key_parts= (wsrep_buf_t*) + my_malloc(sizeof(wsrep_buf_t)*2, MYF(0)))) + { + WSREP_ERROR("Can't allocate memory for key_parts"); + goto err; + } + ka->keys[ka->keys_len].key_parts_num= 2; + ++ka->keys_len; + if (!wsrep_prepare_key_for_isolation( + table->db, table->table_name, + (wsrep_buf_t*)ka->keys[ka->keys_len - 1].key_parts, + &ka->keys[ka->keys_len - 1].key_parts_num)) + { + WSREP_ERROR("Preparing keys for isolation failed"); + goto err; + } + } + } + return true; +err: + wsrep_keys_free(ka); + return false; +} + + +bool wsrep_prepare_key_for_innodb(const uchar* cache_key, + size_t cache_key_len, + const uchar* row_id, + size_t row_id_len, + wsrep_buf_t* key, + size_t* key_len) +{ + if (*key_len < 3) return false; + + *key_len= 0; + switch (wsrep_protocol_version) + { + case 0: + { + key[0].ptr = cache_key; + key[0].len = cache_key_len; + + *key_len = 1; + break; + } + case 1: + case 2: + case 3: + { + key[0].ptr = cache_key; + key[0].len = strlen( (char*)cache_key ); + + key[1].ptr = cache_key + strlen( (char*)cache_key ) + 1; + key[1].len = strlen( (char*)(key[1].ptr) ); + + *key_len = 2; + break; + } + default: + return false; + } + + key[*key_len].ptr = row_id; + key[*key_len].len = row_id_len; + ++(*key_len); + + return true; +} + + +/* + * Construct Query_log_Event from thd query and serialize it + * into buffer. + * + * Return 0 in case of success, 1 in case of error. + */ +int wsrep_to_buf_helper( + THD* thd, const char *query, uint query_len, uchar** buf, size_t* buf_len) +{ + IO_CACHE tmp_io_cache; + if (open_cached_file(&tmp_io_cache, mysql_tmpdir, TEMP_PREFIX, + 65536, MYF(MY_WME))) + return 1; + int ret(0); + +#ifdef GTID_SUPPORT + if (thd->variables.gtid_next.type == GTID_GROUP) + { + Gtid_log_event gtid_ev(thd, FALSE, &thd->variables.gtid_next); + if (!gtid_ev.is_valid()) ret= 0; + if (!ret && gtid_ev.write(&tmp_io_cache)) ret= 1; + } +#endif /* GTID_SUPPORT */ + + /* if there is prepare query, add event for it */ + if (!ret && thd->wsrep_TOI_pre_query) + { + Query_log_event ev(thd, thd->wsrep_TOI_pre_query, + thd->wsrep_TOI_pre_query_len, + FALSE, FALSE, FALSE, 0); + if (ev.write(&tmp_io_cache)) ret= 1; + } + + /* continue to append the actual query */ + Query_log_event ev(thd, query, query_len, FALSE, FALSE, FALSE, 0); + if (!ret && ev.write(&tmp_io_cache)) ret= 1; + if (!ret && wsrep_write_cache_buf(&tmp_io_cache, buf, buf_len)) ret= 1; + close_cached_file(&tmp_io_cache); + return ret; +} + +#include "sql_show.h" +static int +create_view_query(THD *thd, uchar** buf, size_t* buf_len) +{ + LEX *lex= thd->lex; + SELECT_LEX *select_lex= &lex->select_lex; + TABLE_LIST *first_table= select_lex->table_list.first; + TABLE_LIST *views = first_table; + + String buff; + const LEX_STRING command[3]= + {{ C_STRING_WITH_LEN("CREATE ") }, + { C_STRING_WITH_LEN("ALTER ") }, + { C_STRING_WITH_LEN("CREATE OR REPLACE ") }}; + + buff.append(command[thd->lex->create_view_mode].str, + command[thd->lex->create_view_mode].length); + + if (!lex->definer) + { + /* + DEFINER-clause is missing; we have to create default definer in + persistent arena to be PS/SP friendly. + If this is an ALTER VIEW then the current user should be set as + the definer. + */ + + if (!(lex->definer= create_default_definer(thd, false))) + { + WSREP_WARN("view default definer issue"); + } + } + + views->algorithm = lex->create_view_algorithm; + views->definer.user = lex->definer->user; + views->definer.host = lex->definer->host; + views->view_suid = lex->create_view_suid; + views->with_check = lex->create_view_check; + + view_store_options(thd, views, &buff); + buff.append(STRING_WITH_LEN("VIEW ")); + /* Test if user supplied a db (ie: we did not use thd->db) */ + if (views->db && views->db[0] && + (thd->db == NULL || strcmp(views->db, thd->db))) + { + append_identifier(thd, &buff, views->db, + views->db_length); + buff.append('.'); + } + append_identifier(thd, &buff, views->table_name, + views->table_name_length); + if (lex->view_list.elements) + { + List_iterator_fast names(lex->view_list); + LEX_STRING *name; + int i; + + for (i= 0; (name= names++); i++) + { + buff.append(i ? ", " : "("); + append_identifier(thd, &buff, name->str, name->length); + } + buff.append(')'); + } + buff.append(STRING_WITH_LEN(" AS ")); + //buff.append(views->source.str, views->source.length); + buff.append(thd->lex->create_view_select.str, + thd->lex->create_view_select.length); + //int errcode= query_error_code(thd, TRUE); + //if (thd->binlog_query(THD::STMT_QUERY_TYPE, + // buff.ptr(), buff.length(), FALSE, FALSE, FALSE, errcod + return wsrep_to_buf_helper(thd, buff.ptr(), buff.length(), buf, buf_len); +} + +static int wsrep_TOI_begin(THD *thd, char *db_, char *table_, + const TABLE_LIST* table_list) +{ + wsrep_status_t ret(WSREP_WARNING); + uchar* buf(0); + size_t buf_len(0); + int buf_err; + + WSREP_DEBUG("TO BEGIN: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd), + thd->wsrep_exec_mode, thd->query() ); + switch (thd->lex->sql_command) + { + case SQLCOM_CREATE_VIEW: + buf_err= create_view_query(thd, &buf, &buf_len); + break; + case SQLCOM_CREATE_PROCEDURE: + case SQLCOM_CREATE_SPFUNCTION: + buf_err= wsrep_create_sp(thd, &buf, &buf_len); + break; + case SQLCOM_CREATE_TRIGGER: + buf_err= wsrep_create_trigger_query(thd, &buf, &buf_len); + break; + case SQLCOM_CREATE_EVENT: + buf_err= wsrep_create_event_query(thd, &buf, &buf_len); + break; + case SQLCOM_ALTER_EVENT: + buf_err= wsrep_alter_event_query(thd, &buf, &buf_len); + break; + default: + buf_err= wsrep_to_buf_helper(thd, thd->query(), thd->query_length(), &buf, + &buf_len); + break; + } + + wsrep_key_arr_t key_arr= {0, 0}; + struct wsrep_buf buff = { buf, buf_len }; + if (!buf_err && + wsrep_prepare_keys_for_isolation(thd, db_, table_, table_list, &key_arr)&& + WSREP_OK == (ret = wsrep->to_execute_start(wsrep, thd->thread_id, + key_arr.keys, key_arr.keys_len, + &buff, 1, + &thd->wsrep_trx_meta))) + { + thd->wsrep_exec_mode= TOTAL_ORDER; + wsrep_to_isolation++; + if (buf) my_free(buf); + wsrep_keys_free(&key_arr); + WSREP_DEBUG("TO BEGIN: %lld, %d",(long long)wsrep_thd_trx_seqno(thd), + thd->wsrep_exec_mode); + } + else { + /* jump to error handler in mysql_execute_command() */ + WSREP_WARN("TO isolation failed for: %d, sql: %s. Check wsrep " + "connection state and retry the query.", + ret, (thd->query()) ? thd->query() : "void"); + my_error(ER_LOCK_DEADLOCK, MYF(0), "WSREP replication failed. Check " + "your wsrep connection state and retry the query."); + if (buf) my_free(buf); + wsrep_keys_free(&key_arr); + return -1; + } + return 0; +} + +static void wsrep_TOI_end(THD *thd) { + wsrep_status_t ret; + wsrep_to_isolation--; + + WSREP_DEBUG("TO END: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd), + thd->wsrep_exec_mode, (thd->query()) ? thd->query() : "void"); + + XID xid; + wsrep_xid_init(&xid, &thd->wsrep_trx_meta.gtid.uuid, + thd->wsrep_trx_meta.gtid.seqno); + wsrep_set_SE_checkpoint(&xid); + WSREP_DEBUG("TO END: %lld, update seqno", + (long long)wsrep_thd_trx_seqno(thd)); + + if (WSREP_OK == (ret = wsrep->to_execute_end(wsrep, thd->thread_id))) { + WSREP_DEBUG("TO END: %lld", (long long)wsrep_thd_trx_seqno(thd)); + } + else { + WSREP_WARN("TO isolation end failed for: %d, sql: %s", + ret, (thd->query()) ? thd->query() : "void"); + } +} + +static int wsrep_RSU_begin(THD *thd, char *db_, char *table_) +{ + wsrep_status_t ret(WSREP_WARNING); + WSREP_DEBUG("RSU BEGIN: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd), + thd->wsrep_exec_mode, thd->query() ); + + ret = wsrep->desync(wsrep); + if (ret != WSREP_OK) + { + WSREP_WARN("RSU desync failed %d for %s", ret, thd->query()); + my_error(ER_LOCK_DEADLOCK, MYF(0)); + return(ret); + } + mysql_mutex_lock(&LOCK_wsrep_replaying); + wsrep_replaying++; + mysql_mutex_unlock(&LOCK_wsrep_replaying); + + if (wsrep_wait_committing_connections_close(5000)) + { + /* no can do, bail out from DDL */ + WSREP_WARN("RSU failed due to pending transactions, %s", thd->query()); + mysql_mutex_lock(&LOCK_wsrep_replaying); + wsrep_replaying--; + mysql_mutex_unlock(&LOCK_wsrep_replaying); + + ret = wsrep->resync(wsrep); + if (ret != WSREP_OK) + { + WSREP_WARN("resync failed %d for %s", ret, thd->query()); + } + my_error(ER_LOCK_DEADLOCK, MYF(0)); + return(1); + } + + wsrep_seqno_t seqno = wsrep->pause(wsrep); + if (seqno == WSREP_SEQNO_UNDEFINED) + { + WSREP_WARN("pause failed %lld for %s", (long long)seqno, thd->query()); + return(1); + } + WSREP_DEBUG("paused at %lld", (long long)seqno); + thd->variables.wsrep_on = 0; + return 0; +} + +static void wsrep_RSU_end(THD *thd) +{ + wsrep_status_t ret(WSREP_WARNING); + WSREP_DEBUG("RSU END: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd), + thd->wsrep_exec_mode, thd->query() ); + + + mysql_mutex_lock(&LOCK_wsrep_replaying); + wsrep_replaying--; + mysql_mutex_unlock(&LOCK_wsrep_replaying); + + ret = wsrep->resume(wsrep); + if (ret != WSREP_OK) + { + WSREP_WARN("resume failed %d for %s", ret, thd->query()); + } + ret = wsrep->resync(wsrep); + if (ret != WSREP_OK) + { + WSREP_WARN("resync failed %d for %s", ret, thd->query()); + return; + } + thd->variables.wsrep_on = 1; +} + +int wsrep_to_isolation_begin(THD *thd, char *db_, char *table_, + const TABLE_LIST* table_list) +{ + + /* + No isolation for applier or replaying threads. + */ + if (thd->wsrep_exec_mode == REPL_RECV) return 0; + + int ret= 0; + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + + if (thd->wsrep_conflict_state == MUST_ABORT) + { + WSREP_INFO("thread: %lu, %s has been aborted due to multi-master conflict", + thd->thread_id, thd->query()); + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + return WSREP_TRX_FAIL; + } + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + + DBUG_ASSERT(thd->wsrep_exec_mode == LOCAL_STATE); + DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno == WSREP_SEQNO_UNDEFINED); + + if (thd->global_read_lock.can_acquire_protection()) + { + WSREP_DEBUG("Aborting TOI: Global Read-Lock (FTWRL) in place: %s %lu", + thd->query(), thd->thread_id); + return -1; + } + + if (wsrep_debug && thd->mdl_context.has_locks()) + { + WSREP_DEBUG("thread holds MDL locks at TI begin: %s %lu", + thd->query(), thd->thread_id); + } + + /* + It makes sense to set auto_increment_* to defaults in TOI operations. + Must be done before wsrep_TOI_begin() since Query_log_event encapsulating + TOI statement and auto inc variables for wsrep replication is constructed + there. Variables are reset back in THD::reset_for_next_command() before + processing of next command. + */ + if (wsrep_auto_increment_control) + { + thd->variables.auto_increment_offset = 1; + thd->variables.auto_increment_increment = 1; + } + + if (thd->variables.wsrep_on && thd->wsrep_exec_mode==LOCAL_STATE) + { + switch (wsrep_OSU_method_options) { + case WSREP_OSU_TOI: ret = wsrep_TOI_begin(thd, db_, table_, + table_list); break; + case WSREP_OSU_RSU: ret = wsrep_RSU_begin(thd, db_, table_); break; + } + if (!ret) + { + thd->wsrep_exec_mode= TOTAL_ORDER; + } + } + return ret; +} + +void wsrep_to_isolation_end(THD *thd) +{ + if (thd->wsrep_exec_mode == TOTAL_ORDER) + { + switch(wsrep_OSU_method_options) + { + case WSREP_OSU_TOI: wsrep_TOI_end(thd); break; + case WSREP_OSU_RSU: wsrep_RSU_end(thd); break; + } + wsrep_cleanup_transaction(thd); + } +} + +#define WSREP_MDL_LOG(severity, msg, req, gra) \ + WSREP_##severity( \ + "%s\n" \ + "request: (%lu \tseqno %lld \twsrep (%d, %d, %d) cmd %d %d \t%s)\n" \ + "granted: (%lu \tseqno %lld \twsrep (%d, %d, %d) cmd %d %d \t%s)", \ + msg, \ + req->thread_id, (long long)wsrep_thd_trx_seqno(req), \ + req->wsrep_exec_mode, req->wsrep_query_state, req->wsrep_conflict_state, \ + req->get_command(), req->lex->sql_command, req->query(), \ + gra->thread_id, (long long)wsrep_thd_trx_seqno(gra), \ + gra->wsrep_exec_mode, gra->wsrep_query_state, gra->wsrep_conflict_state, \ + gra->get_command(), gra->lex->sql_command, gra->query()); + +bool +wsrep_grant_mdl_exception(MDL_context *requestor_ctx, + MDL_ticket *ticket +) { + if (!WSREP_ON) return FALSE; + + THD *request_thd = requestor_ctx->wsrep_get_thd(); + THD *granted_thd = ticket->get_ctx()->wsrep_get_thd(); + bool ret = FALSE; + + mysql_mutex_lock(&request_thd->LOCK_wsrep_thd); + if (request_thd->wsrep_exec_mode == TOTAL_ORDER || + request_thd->wsrep_exec_mode == REPL_RECV) + { + mysql_mutex_unlock(&request_thd->LOCK_wsrep_thd); + WSREP_MDL_LOG(DEBUG, "MDL conflict ", request_thd, granted_thd); + ticket->wsrep_report(wsrep_debug); + + mysql_mutex_lock(&granted_thd->LOCK_wsrep_thd); + if (granted_thd->wsrep_exec_mode == TOTAL_ORDER || + granted_thd->wsrep_exec_mode == REPL_RECV) + { + WSREP_MDL_LOG(INFO, "MDL BF-BF conflict", request_thd, granted_thd); + ticket->wsrep_report(true); + mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd); + ret = TRUE; + } + else if (granted_thd->lex->sql_command == SQLCOM_FLUSH) + { + WSREP_DEBUG("mdl granted over FLUSH BF"); + ticket->wsrep_report(wsrep_debug); + mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd); + ret = TRUE; + } + else if (request_thd->lex->sql_command == SQLCOM_DROP_TABLE) + { + WSREP_DEBUG("DROP caused BF abort"); + ticket->wsrep_report(wsrep_debug); + mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd); + wsrep_abort_thd((void*)request_thd, (void*)granted_thd, 1); + ret = FALSE; + } + else if (granted_thd->wsrep_query_state == QUERY_COMMITTING) + { + WSREP_DEBUG("mdl granted, but commiting thd abort scheduled"); + ticket->wsrep_report(wsrep_debug); + mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd); + wsrep_abort_thd((void*)request_thd, (void*)granted_thd, 1); + ret = FALSE; + } + else + { + WSREP_MDL_LOG(DEBUG, "MDL conflict-> BF abort", request_thd, granted_thd); + ticket->wsrep_report(wsrep_debug); + mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd); + wsrep_abort_thd((void*)request_thd, (void*)granted_thd, 1); + ret = FALSE; + } + } + else + { + mysql_mutex_unlock(&request_thd->LOCK_wsrep_thd); + } + return ret; +} diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h new file mode 100644 index 00000000000..796f1aac0f1 --- /dev/null +++ b/sql/wsrep_mysqld.h @@ -0,0 +1,320 @@ +/* Copyright 2008-2013 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef WSREP_MYSQLD_H +#define WSREP_MYSQLD_H + +#include "mysqld.h" +typedef struct st_mysql_show_var SHOW_VAR; +#include +//#include "rpl_gtid.h" +#include "../wsrep/wsrep_api.h" + +#define WSREP_UNDEFINED_TRX_ID ULONGLONG_MAX + +class set_var; +class THD; + +enum wsrep_exec_mode { + LOCAL_STATE, + REPL_RECV, + TOTAL_ORDER, + LOCAL_COMMIT +}; + +enum wsrep_query_state { + QUERY_IDLE, + QUERY_EXEC, + QUERY_COMMITTING, + QUERY_EXITING, + QUERY_ROLLINGBACK, +}; + +enum wsrep_conflict_state { + NO_CONFLICT, + MUST_ABORT, + ABORTING, + ABORTED, + MUST_REPLAY, + REPLAYING, + RETRY_AUTOCOMMIT, + CERT_FAILURE, +}; + +enum wsrep_consistency_check_mode { + NO_CONSISTENCY_CHECK, + CONSISTENCY_CHECK_DECLARED, + CONSISTENCY_CHECK_RUNNING, +}; + + +// Global wsrep parameters +extern wsrep_t* wsrep; + +// MySQL wsrep options +extern const char* wsrep_provider; +extern const char* wsrep_provider_options; +extern const char* wsrep_cluster_name; +extern const char* wsrep_cluster_address; +extern const char* wsrep_node_name; +extern const char* wsrep_node_address; +extern const char* wsrep_node_incoming_address; +extern const char* wsrep_data_home_dir; +extern const char* wsrep_dbug_option; +extern long wsrep_slave_threads; +extern int wsrep_slave_count_change; +extern MYSQL_PLUGIN_IMPORT my_bool wsrep_debug; +extern my_bool wsrep_convert_LOCK_to_trx; +extern ulong wsrep_retry_autocommit; +extern my_bool wsrep_auto_increment_control; +extern my_bool wsrep_drupal_282555_workaround; +extern my_bool wsrep_incremental_data_collection; +extern const char* wsrep_start_position; +extern ulong wsrep_max_ws_size; +extern ulong wsrep_max_ws_rows; +extern const char* wsrep_notify_cmd; +extern my_bool wsrep_certify_nonPK; +extern long wsrep_max_protocol_version; +extern long wsrep_protocol_version; +extern ulong wsrep_forced_binlog_format; +extern ulong wsrep_OSU_method_options; +extern my_bool wsrep_desync; +extern my_bool wsrep_recovery; +extern my_bool wsrep_replicate_myisam; +extern my_bool wsrep_log_conflicts; +extern ulong wsrep_mysql_replication_bundle; +extern my_bool wsrep_load_data_splitting; +extern my_bool wsrep_restart_slave; +extern my_bool wsrep_restart_slave_activated; +extern my_bool wsrep_slave_FK_checks; +extern my_bool wsrep_slave_UK_checks; + +enum enum_wsrep_OSU_method { WSREP_OSU_TOI, WSREP_OSU_RSU }; + +// MySQL status variables +extern my_bool wsrep_connected; +extern my_bool wsrep_ready; +extern const char* wsrep_cluster_state_uuid; +extern long long wsrep_cluster_conf_id; +extern const char* wsrep_cluster_status; +extern long wsrep_cluster_size; +extern long wsrep_local_index; +extern long long wsrep_local_bf_aborts; +extern const char* wsrep_provider_name; +extern const char* wsrep_provider_version; +extern const char* wsrep_provider_vendor; + +int wsrep_show_status(THD *thd, SHOW_VAR *var, char *buff); +void wsrep_free_status(THD *thd); + +/* Filters out --wsrep-new-cluster oprtion from argv[] + * should be called in the very beginning of main() */ +void wsrep_filter_new_cluster (int* argc, char* argv[]); + +int wsrep_init(); +void wsrep_deinit(bool free_options); +void wsrep_recover(); +bool wsrep_before_SE(); // initialize wsrep before storage + // engines (true) or after (false) +/* wsrep initialization sequence at startup + * @param before wsrep_before_SE() value */ +void wsrep_init_startup(bool before); + +// Other wsrep global variables +extern my_bool wsrep_inited; // whether wsrep is initialized ? + +extern "C" enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd); +extern "C" enum wsrep_conflict_state wsrep_thd_conflict_state(THD *thd); +extern "C" enum wsrep_query_state wsrep_thd_query_state(THD *thd); +extern "C" const char * wsrep_thd_exec_mode_str(THD *thd); +extern "C" const char * wsrep_thd_conflict_state_str(THD *thd); +extern "C" const char * wsrep_thd_query_state_str(THD *thd); +extern "C" wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd); + +extern "C" void wsrep_thd_set_exec_mode(THD *thd, enum wsrep_exec_mode mode); +extern "C" void wsrep_thd_set_query_state( + THD *thd, enum wsrep_query_state state); +extern "C" void wsrep_thd_set_conflict_state( + THD *thd, enum wsrep_conflict_state state); + +extern "C" void wsrep_thd_set_trx_to_replay(THD *thd, uint64 trx_id); + +extern "C" void wsrep_thd_LOCK(THD *thd); +extern "C" void wsrep_thd_UNLOCK(THD *thd); +extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd); +extern "C" time_t wsrep_thd_query_start(THD *thd); +extern "C" my_thread_id wsrep_thd_thread_id(THD *thd); +extern "C" int64_t wsrep_thd_trx_seqno(THD *thd); +extern "C" query_id_t wsrep_thd_query_id(THD *thd); +extern "C" char * wsrep_thd_query(THD *thd); +extern "C" query_id_t wsrep_thd_wsrep_last_query_id(THD *thd); +extern "C" void wsrep_thd_set_wsrep_last_query_id(THD *thd, query_id_t id); +extern "C" void wsrep_thd_awake(THD *thd, my_bool signal); +extern "C" int wsrep_thd_retry_counter(THD *thd); + + +extern void wsrep_close_client_connections(my_bool wait_to_end); +extern int wsrep_wait_committing_connections_close(int wait_time); +extern void wsrep_close_applier(THD *thd); +extern void wsrep_wait_appliers_close(THD *thd); +extern void wsrep_close_applier_threads(int count); +extern void wsrep_kill_mysql(THD *thd); + +/* new defines */ +extern void wsrep_stop_replication(THD *thd); +extern bool wsrep_start_replication(); +extern bool wsrep_causal_wait(THD* thd); +extern int wsrep_check_opts (int argc, char* const* argv); +extern void wsrep_prepend_PATH (const char* path); + +/* Other global variables */ +extern wsrep_seqno_t wsrep_locked_seqno; + +#define WSREP_ON \ + (global_system_variables.wsrep_on) + +#define WSREP(thd) \ + (WSREP_ON && (thd && thd->variables.wsrep_on)) + +#define WSREP_CLIENT(thd) \ + (WSREP(thd) && thd->wsrep_client_thread) + +#define WSREP_EMULATE_BINLOG(thd) \ + (WSREP(thd) && wsrep_emulate_bin_log) + +// MySQL logging functions don't seem to understand long long length modifer. +// This is a workaround. It also prefixes all messages with "WSREP" +#define WSREP_LOG(fun, ...) \ + { \ + char msg[1024] = {'\0'}; \ + snprintf(msg, sizeof(msg) - 1, ## __VA_ARGS__); \ + fun("WSREP: %s", msg); \ + } + +#define WSREP_DEBUG(...) \ + if (wsrep_debug) WSREP_LOG(sql_print_information, ##__VA_ARGS__) +#define WSREP_INFO(...) WSREP_LOG(sql_print_information, ##__VA_ARGS__) +#define WSREP_WARN(...) WSREP_LOG(sql_print_warning, ##__VA_ARGS__) +#define WSREP_ERROR(...) WSREP_LOG(sql_print_error, ##__VA_ARGS__) + +#define WSREP_LOG_CONFLICT_THD(thd, role) \ + WSREP_LOG(sql_print_information, \ + "%s: \n " \ + " THD: %lu, mode: %s, state: %s, conflict: %s, seqno: %lld\n " \ + " SQL: %s", \ + role, wsrep_thd_thread_id(thd), wsrep_thd_exec_mode_str(thd), \ + wsrep_thd_query_state_str(thd), \ + wsrep_thd_conflict_state_str(thd), (long long)wsrep_thd_trx_seqno(thd), \ + wsrep_thd_query(thd) \ + ); + +#define WSREP_LOG_CONFLICT(bf_thd, victim_thd, bf_abort) \ + if (wsrep_debug || wsrep_log_conflicts) \ + { \ + WSREP_LOG(sql_print_information, "cluster conflict due to %s for threads:",\ + (bf_abort) ? "high priority abort" : "certification failure" \ + ); \ + if (bf_thd != NULL) WSREP_LOG_CONFLICT_THD(bf_thd, "Winning thread"); \ + if (victim_thd) WSREP_LOG_CONFLICT_THD(victim_thd, "Victim thread"); \ + } + +#define WSREP_PROVIDER_EXISTS \ + (wsrep_provider && strncasecmp(wsrep_provider, WSREP_NONE, FN_REFLEN)) + +extern void wsrep_ready_wait(); + +enum wsrep_trx_status { + WSREP_TRX_OK, + WSREP_TRX_CERT_FAIL, /* certification failure, must abort */ + WSREP_TRX_SIZE_EXCEEDED, /* trx size exceeded */ + WSREP_TRX_ERROR, /* native mysql error */ +}; + +extern enum wsrep_trx_status +wsrep_run_wsrep_commit(THD *thd, handlerton *hton, bool all); +class Ha_trx_info; +struct THD_TRANS; +void wsrep_register_hton(THD* thd, bool all); +void wsrep_post_commit(THD* thd, bool all); +void wsrep_brute_force_killer(THD *thd); +int wsrep_hire_brute_force_killer(THD *thd, uint64_t trx_id); + +extern "C" bool wsrep_consistency_check(void *thd_ptr); + +/* this is visible for client build so that innodb plugin gets this */ +typedef struct wsrep_aborting_thd { + struct wsrep_aborting_thd *next; + THD *aborting_thd; +} *wsrep_aborting_thd_t; + +extern mysql_mutex_t LOCK_wsrep_ready; +extern mysql_cond_t COND_wsrep_ready; +extern mysql_mutex_t LOCK_wsrep_sst; +extern mysql_cond_t COND_wsrep_sst; +extern mysql_mutex_t LOCK_wsrep_sst_init; +extern mysql_cond_t COND_wsrep_sst_init; +extern mysql_mutex_t LOCK_wsrep_rollback; +extern mysql_cond_t COND_wsrep_rollback; +extern int wsrep_replaying; +extern mysql_mutex_t LOCK_wsrep_replaying; +extern mysql_cond_t COND_wsrep_replaying; +extern mysql_mutex_t LOCK_wsrep_slave_threads; +extern mysql_mutex_t LOCK_wsrep_desync; +extern wsrep_aborting_thd_t wsrep_aborting_thd; +extern my_bool wsrep_emulate_bin_log; +extern int wsrep_to_isolation; +#ifdef GTID_SUPPORT +extern rpl_sidno wsrep_sidno; +#endif /* GTID_SUPPORT */ +extern my_bool wsrep_preordered_opt; + +#ifdef HAVE_PSI_INTERFACE +extern PSI_mutex_key key_LOCK_wsrep_ready; +extern PSI_mutex_key key_COND_wsrep_ready; +extern PSI_mutex_key key_LOCK_wsrep_sst; +extern PSI_cond_key key_COND_wsrep_sst; +extern PSI_mutex_key key_LOCK_wsrep_sst_init; +extern PSI_cond_key key_COND_wsrep_sst_init; +extern PSI_mutex_key key_LOCK_wsrep_sst_thread; +extern PSI_cond_key key_COND_wsrep_sst_thread; +extern PSI_mutex_key key_LOCK_wsrep_rollback; +extern PSI_cond_key key_COND_wsrep_rollback; +extern PSI_mutex_key key_LOCK_wsrep_replaying; +extern PSI_cond_key key_COND_wsrep_replaying; +extern PSI_mutex_key key_LOCK_wsrep_slave_threads; +extern PSI_mutex_key key_LOCK_wsrep_desync; +#endif /* HAVE_PSI_INTERFACE */ +struct TABLE_LIST; +int wsrep_to_isolation_begin(THD *thd, char *db_, char *table_, + const TABLE_LIST* table_list); +void wsrep_to_isolation_end(THD *thd); +void wsrep_cleanup_transaction(THD *thd); +int wsrep_to_buf_helper( + THD* thd, const char *query, uint query_len, uchar** buf, size_t* buf_len); +int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len); +int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len); +int wsrep_create_event_query(THD *thd, uchar** buf, size_t* buf_len); +int wsrep_alter_event_query(THD *thd, uchar** buf, size_t* buf_len); + +struct xid_t; +void wsrep_get_SE_checkpoint(xid_t*); +void wsrep_set_SE_checkpoint(xid_t*); +void wsrep_init_sidno(const wsrep_uuid_t&); +void wsrep_xid_init(xid_t*, const wsrep_uuid_t*, wsrep_seqno_t); +const wsrep_uuid_t* wsrep_xid_uuid(const xid_t*); +wsrep_seqno_t wsrep_xid_seqno(const xid_t*); +extern "C" int wsrep_is_wsrep_xid(const void* xid); + +#endif /* WSREP_MYSQLD_H */ diff --git a/sql/wsrep_notify.cc b/sql/wsrep_notify.cc new file mode 100644 index 00000000000..6eefb961b62 --- /dev/null +++ b/sql/wsrep_notify.cc @@ -0,0 +1,111 @@ +/* Copyright 2010 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include +#include "wsrep_priv.h" +#include "wsrep_utils.h" + +const char* wsrep_notify_cmd=""; + +static const char* _status_str(wsrep_member_status_t status) +{ + switch (status) + { + case WSREP_MEMBER_UNDEFINED: return "Undefined"; + case WSREP_MEMBER_JOINER: return "Joiner"; + case WSREP_MEMBER_DONOR: return "Donor"; + case WSREP_MEMBER_JOINED: return "Joined"; + case WSREP_MEMBER_SYNCED: return "Synced"; + default: return "Error(?)"; + } +} + +void wsrep_notify_status (wsrep_member_status_t status, + const wsrep_view_info_t* view) +{ + if (!wsrep_notify_cmd || 0 == strlen(wsrep_notify_cmd)) + { + WSREP_INFO("wsrep_notify_cmd is not defined, skipping notification."); + return; + } + + char cmd_buf[1 << 16]; // this can be long + long cmd_len = sizeof(cmd_buf) - 1; + char* cmd_ptr = cmd_buf; + long cmd_off = 0; + + cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off, "%s", + wsrep_notify_cmd); + + if (status >= WSREP_MEMBER_UNDEFINED && status < WSREP_MEMBER_ERROR) + { + cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off, " --status %s", + _status_str(status)); + } + else + { + /* here we preserve provider error codes */ + cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off, + " --status 'Error(%d)'", status); + } + + if (0 != view) + { + char uuid_str[40]; + + wsrep_uuid_print (&view->state_id.uuid, uuid_str, sizeof(uuid_str)); + cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off, + " --uuid %s", uuid_str); + + cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off, + " --primary %s", view->view >= 0 ? "yes" : "no"); + + cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off, + " --index %d", view->my_idx); + + if (view->memb_num) + { + cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off, " --members"); + + for (int i = 0; i < view->memb_num; i++) + { + wsrep_uuid_print (&view->members[i].id, uuid_str, sizeof(uuid_str)); + cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off, + "%c%s/%s/%s", i > 0 ? ',' : ' ', + uuid_str, view->members[i].name, + view->members[i].incoming); + } + } + } + + if (cmd_off == cmd_len) + { + WSREP_ERROR("Notification buffer too short (%ld). Aborting notification.", + cmd_len); + return; + } + + wsp::process p(cmd_ptr, "r"); + + p.wait(); + int err = p.error(); + + if (err) + { + WSREP_ERROR("Notification command failed: %d (%s): \"%s\"", + err, strerror(err), cmd_ptr); + } +} + diff --git a/sql/wsrep_priv.h b/sql/wsrep_priv.h new file mode 100644 index 00000000000..5c66587d757 --- /dev/null +++ b/sql/wsrep_priv.h @@ -0,0 +1,53 @@ +/* Copyright 2010 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//! @file declares symbols private to wsrep integration layer + +#ifndef WSREP_PRIV_H +#define WSREP_PRIV_H + +#include "wsrep_mysqld.h" +#include "../wsrep/wsrep_api.h" + +#include +#include +#include + +void wsrep_ready_set (my_bool x); + +ssize_t wsrep_sst_prepare (void** msg); +wsrep_cb_status wsrep_sst_donate_cb (void* app_ctx, + void* recv_ctx, + const void* msg, size_t msg_len, + const wsrep_gtid_t* current_id, + const char* state, size_t state_len, + bool bypass); +extern unsigned int wsrep_check_ip (const char* addr); +extern size_t wsrep_guess_ip (char* buf, size_t buf_len); +extern size_t wsrep_guess_address(char* buf, size_t buf_len); + +extern wsrep_uuid_t local_uuid; +extern wsrep_seqno_t local_seqno; + +// a helper function +extern void wsrep_sst_received(wsrep_t*, const wsrep_uuid_t*, wsrep_seqno_t, + const void*, size_t); +/*! SST thread signals init thread about sst completion */ +extern void wsrep_sst_complete(const wsrep_uuid_t*, wsrep_seqno_t, bool); + +void wsrep_notify_status (wsrep_member_status_t new_status, + const wsrep_view_info_t* view = 0); +#endif /* WSREP_PRIV_H */ diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc new file mode 100644 index 00000000000..c122d88f7cc --- /dev/null +++ b/sql/wsrep_sst.cc @@ -0,0 +1,1127 @@ +/* Copyright 2008-2012 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "wsrep_sst.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wsrep_priv.h" +#include "wsrep_utils.h" +#include +#include + +extern const char wsrep_defaults_file[]; + +const char* wsrep_sst_method = WSREP_SST_DEFAULT; +const char* wsrep_sst_receive_address = WSREP_SST_ADDRESS_AUTO; +const char* wsrep_sst_donor = ""; + char* wsrep_sst_auth = NULL; + +// container for real auth string +static const char* sst_auth_real = NULL; +my_bool wsrep_sst_donor_rejects_queries = FALSE; + +bool wsrep_sst_method_check (sys_var *self, THD* thd, set_var* var) +{ + if ((! var->save_result.string_value.str) || + (var->save_result.string_value.length == 0 )) + { + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, + var->save_result.string_value.str ? + var->save_result.string_value.str : "NULL"); + return 1; + } + + return 0; +} + +bool wsrep_sst_method_update (sys_var *self, THD* thd, enum_var_type type) +{ + return 0; +} + +// TODO: Improve address verification. +static bool sst_receive_address_check (const char* str) +{ + if (!strncasecmp(str, "127.0.0.1", strlen("127.0.0.1")) || + !strncasecmp(str, "localhost", strlen("localhost"))) + { + return 1; + } + + return 0; +} + +bool wsrep_sst_receive_address_check (sys_var *self, THD* thd, set_var* var) +{ + char addr_buf[FN_REFLEN]; + + if ((! var->save_result.string_value.str) || + (var->save_result.string_value.length > (FN_REFLEN - 1))) // safety + { + goto err; + } + + memcpy(addr_buf, var->save_result.string_value.str, + var->save_result.string_value.length); + addr_buf[var->save_result.string_value.length]= 0; + + if (sst_receive_address_check(addr_buf)) + { + goto err; + } + + return 0; + +err: + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, + var->save_result.string_value.str ? + var->save_result.string_value.str : "NULL"); + return 1; +} + +bool wsrep_sst_receive_address_update (sys_var *self, THD* thd, + enum_var_type type) +{ + return 0; +} + +bool wsrep_sst_auth_check (sys_var *self, THD* thd, set_var* var) +{ + return 0; +} + +static bool sst_auth_real_set (const char* value) +{ + const char* v= NULL; + + if (value) + { + v= my_strdup(value, MYF(0)); + } + else // its NULL + { + wsrep_sst_auth_free(); + return 0; + } + + if (v) + { + // set sst_auth_real + if (sst_auth_real) { my_free((void *) sst_auth_real); } + sst_auth_real = v; + + // mask wsrep_sst_auth + if (strlen(sst_auth_real)) + { + if (wsrep_sst_auth) { my_free((void*) wsrep_sst_auth); } + wsrep_sst_auth= my_strdup(WSREP_SST_AUTH_MASK, MYF(0)); + } + return 0; + } + return 1; +} + +void wsrep_sst_auth_free() +{ + if (wsrep_sst_auth) { my_free((void *) wsrep_sst_auth); } + if (sst_auth_real) { my_free((void *) sst_auth_real); } + wsrep_sst_auth= NULL; + sst_auth_real= NULL; +} + +bool wsrep_sst_auth_update (sys_var *self, THD* thd, enum_var_type type) +{ + return sst_auth_real_set (wsrep_sst_auth); +} + +void wsrep_sst_auth_init (const char* value) +{ + if (wsrep_sst_auth == value) wsrep_sst_auth = NULL; + if (value) sst_auth_real_set (value); +} + +bool wsrep_sst_donor_check (sys_var *self, THD* thd, set_var* var) +{ + return 0; +} + +bool wsrep_sst_donor_update (sys_var *self, THD* thd, enum_var_type type) +{ + return 0; +} + +static wsrep_uuid_t cluster_uuid = WSREP_UUID_UNDEFINED; + +bool wsrep_before_SE() +{ + return (wsrep_provider != NULL + && strcmp (wsrep_provider, WSREP_NONE) + && strcmp (wsrep_sst_method, WSREP_SST_SKIP) + && strcmp (wsrep_sst_method, WSREP_SST_MYSQLDUMP)); +} + +static bool sst_complete = false; +static bool sst_needed = false; + +void wsrep_sst_grab () +{ + WSREP_INFO("wsrep_sst_grab()"); + if (mysql_mutex_lock (&LOCK_wsrep_sst)) abort(); + sst_complete = false; + mysql_mutex_unlock (&LOCK_wsrep_sst); +} + +// Wait for end of SST +bool wsrep_sst_wait () +{ + if (mysql_mutex_lock (&LOCK_wsrep_sst)) abort(); + while (!sst_complete) + { + WSREP_INFO("Waiting for SST to complete."); + mysql_cond_wait (&COND_wsrep_sst, &LOCK_wsrep_sst); + } + + if (local_seqno >= 0) + { + WSREP_INFO("SST complete, seqno: %lld", (long long) local_seqno); + } + else + { + WSREP_ERROR("SST failed: %d (%s)", + int(-local_seqno), strerror(-local_seqno)); + } + + mysql_mutex_unlock (&LOCK_wsrep_sst); + + return (local_seqno >= 0); +} + +// Signal end of SST +void wsrep_sst_complete (const wsrep_uuid_t* sst_uuid, + wsrep_seqno_t sst_seqno, + bool needed) +{ + if (mysql_mutex_lock (&LOCK_wsrep_sst)) abort(); + if (!sst_complete) + { + sst_complete = true; + sst_needed = needed; + local_uuid = *sst_uuid; + local_seqno = sst_seqno; + mysql_cond_signal (&COND_wsrep_sst); + } + else + { + /* This can happen when called from wsrep_synced_cb(). + At the moment there is no way to check there + if main thread is still waiting for signal, + so wsrep_sst_complete() is called from there + each time wsrep_ready changes from FALSE -> TRUE. + */ + WSREP_DEBUG("Nobody is waiting for SST."); + } + mysql_mutex_unlock (&LOCK_wsrep_sst); +} + +void wsrep_sst_received (wsrep_t* const wsrep, + const wsrep_uuid_t* const uuid, + wsrep_seqno_t const seqno, + const void* const state, + size_t const state_len) +{ + int const rcode(seqno < 0 ? seqno : 0); + wsrep_gtid_t const state_id = { + *uuid, (rcode ? WSREP_SEQNO_UNDEFINED : seqno) + }; +#ifdef GTID_SUPPORT + wsrep_init_sidno(state_id.uuid); +#endif /* GTID_SUPPORT */ + wsrep->sst_received(wsrep, &state_id, state, state_len, rcode); +} + +// Let applier threads to continue +void wsrep_sst_continue () +{ + if (sst_needed) + { + WSREP_INFO("Signalling provider to continue."); + wsrep_sst_received (wsrep, &local_uuid, local_seqno, NULL, 0); + } +} + +struct sst_thread_arg +{ + const char* cmd; + int err; + char* ret_str; + mysql_mutex_t lock; + mysql_cond_t cond; + + sst_thread_arg (const char* c) : cmd(c), err(-1), ret_str(0) + { + mysql_mutex_init(key_LOCK_wsrep_sst_thread, &lock, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_wsrep_sst_thread, &cond, NULL); + } + + ~sst_thread_arg() + { + mysql_cond_destroy (&cond); + mysql_mutex_unlock (&lock); + mysql_mutex_destroy (&lock); + } +}; + +static int sst_scan_uuid_seqno (const char* str, + wsrep_uuid_t* uuid, wsrep_seqno_t* seqno) +{ + int offt = wsrep_uuid_scan (str, strlen(str), uuid); + if (offt > 0 && strlen(str) > (unsigned int)offt && ':' == str[offt]) + { + *seqno = strtoll (str + offt + 1, NULL, 10); + if (*seqno != LLONG_MAX || errno != ERANGE) + { + return 0; + } + } + + WSREP_ERROR("Failed to parse uuid:seqno pair: '%s'", str); + return EINVAL; +} + +// get rid of trailing \n +static char* my_fgets (char* buf, size_t buf_len, FILE* stream) +{ + char* ret= fgets (buf, buf_len, stream); + + if (ret) + { + size_t len = strlen(ret); + if (len > 0 && ret[len - 1] == '\n') ret[len - 1] = '\0'; + } + + return ret; +} + +/* + Generate opt_binlog_opt_val for sst_donate_other(), sst_prepare_other(). + + Returns zero on success, negative error code otherwise. + + String containing binlog name is stored in param ret if binlog is enabled + and GTID mode is on, otherwise empty string. Returned string should be + freed with my_free(). + */ +static int generate_binlog_opt_val(char** ret) +{ + DBUG_ASSERT(ret); + *ret= NULL; + if (opt_bin_log) + { + assert(opt_bin_logname); + *ret= strcmp(opt_bin_logname, "0") ? + my_strdup(opt_bin_logname, MYF(0)) : my_strdup("", MYF(0)); + } + else + { + *ret= my_strdup("", MYF(0)); + } + if (!*ret) return -ENOMEM; + return 0; +} + +static void* sst_joiner_thread (void* a) +{ + sst_thread_arg* arg= (sst_thread_arg*) a; + int err= 1; + + { + const char magic[] = "ready"; + const size_t magic_len = sizeof(magic) - 1; + const size_t out_len = 512; + char out[out_len]; + + WSREP_INFO("Running: '%s'", arg->cmd); + + wsp::process proc (arg->cmd, "r"); + + if (proc.pipe() && !proc.error()) + { + const char* tmp= my_fgets (out, out_len, proc.pipe()); + + if (!tmp || strlen(tmp) < (magic_len + 2) || + strncasecmp (tmp, magic, magic_len)) + { + WSREP_ERROR("Failed to read '%s ' from: %s\n\tRead: '%s'", + magic, arg->cmd, tmp); + proc.wait(); + if (proc.error()) err = proc.error(); + } + else + { + err = 0; + } + } + else + { + err = proc.error(); + WSREP_ERROR("Failed to execute: %s : %d (%s)", + arg->cmd, err, strerror(err)); + } + + // signal sst_prepare thread with ret code, + // it will go on sending SST request + mysql_mutex_lock (&arg->lock); + if (!err) + { + arg->ret_str = strdup (out + magic_len + 1); + if (!arg->ret_str) err = ENOMEM; + } + arg->err = -err; + mysql_cond_signal (&arg->cond); + mysql_mutex_unlock (&arg->lock); //! @note arg is unusable after that. + + if (err) return NULL; /* lp:808417 - return immediately, don't signal + * initializer thread to ensure single thread of + * shutdown. */ + + wsrep_uuid_t ret_uuid = WSREP_UUID_UNDEFINED; + wsrep_seqno_t ret_seqno = WSREP_SEQNO_UNDEFINED; + + // in case of successfull receiver start, wait for SST completion/end + char* tmp = my_fgets (out, out_len, proc.pipe()); + + proc.wait(); + err= EINVAL; + + if (!tmp) + { + WSREP_ERROR("Failed to read uuid:seqno from joiner script."); + if (proc.error()) err = proc.error(); + } + else + { + err= sst_scan_uuid_seqno (out, &ret_uuid, &ret_seqno); + } + + if (err) + { + ret_uuid= WSREP_UUID_UNDEFINED; + ret_seqno= -err; + } + + // Tell initializer thread that SST is complete + wsrep_sst_complete (&ret_uuid, ret_seqno, true); + } + + return NULL; +} + +static ssize_t sst_prepare_other (const char* method, + const char* addr_in, + const char** addr_out) +{ + ssize_t cmd_len= 1024; + char cmd_str[cmd_len]; + const char* sst_dir= mysql_real_data_home; + const char* binlog_opt= ""; + char* binlog_opt_val= NULL; + + int ret; + if ((ret= generate_binlog_opt_val(&binlog_opt_val))) + { + WSREP_ERROR("sst_prepare_other(): generate_binlog_opt_val() failed: %d", + ret); + return ret; + } + if (strlen(binlog_opt_val)) binlog_opt= WSREP_SST_OPT_BINLOG; + + + ret= snprintf (cmd_str, cmd_len, + "wsrep_sst_%s " + WSREP_SST_OPT_ROLE" 'joiner' " + WSREP_SST_OPT_ADDR" '%s' " + WSREP_SST_OPT_AUTH" '%s' " + WSREP_SST_OPT_DATA" '%s' " + WSREP_SST_OPT_CONF" '%s' " + WSREP_SST_OPT_PARENT" '%d'" + " %s '%s' ", + method, addr_in, (sst_auth_real) ? sst_auth_real : "", + sst_dir, wsrep_defaults_file, (int)getpid(), + binlog_opt, binlog_opt_val); + my_free(binlog_opt_val); + + if (ret < 0 || ret >= cmd_len) + { + WSREP_ERROR("sst_prepare_other(): snprintf() failed: %d", ret); + return (ret < 0 ? ret : -EMSGSIZE); + } + + pthread_t tmp; + sst_thread_arg arg(cmd_str); + mysql_mutex_lock (&arg.lock); + ret = pthread_create (&tmp, NULL, sst_joiner_thread, &arg); + if (ret) + { + WSREP_ERROR("sst_prepare_other(): pthread_create() failed: %d (%s)", + ret, strerror(ret)); + return ret; + } + mysql_cond_wait (&arg.cond, &arg.lock); + + *addr_out= arg.ret_str; + + if (!arg.err) + ret = strlen(*addr_out); + else + { + assert (arg.err < 0); + ret = arg.err; + } + + pthread_detach (tmp); + + return ret; +} + +extern uint mysqld_port; + +/*! Just tells donor where to send mysqldump */ +static ssize_t sst_prepare_mysqldump (const char* addr_in, + const char** addr_out) +{ + ssize_t ret = strlen (addr_in); + + if (!strrchr(addr_in, ':')) + { + ssize_t s = ret + 7; + char* tmp = (char*) malloc (s); + + if (tmp) + { + ret= snprintf (tmp, s, "%s:%u", addr_in, mysqld_port); + + if (ret > 0 && ret < s) + { + *addr_out= tmp; + return ret; + } + if (ret > 0) /* buffer too short */ ret = -EMSGSIZE; + free (tmp); + } + else { + ret= -ENOMEM; + } + + WSREP_ERROR ("Could not prepare state transfer request: " + "adding default port failed: %zd.", ret); + } + else { + *addr_out= addr_in; + } + + return ret; +} + +static bool SE_initialized = false; + +ssize_t wsrep_sst_prepare (void** msg) +{ + const ssize_t ip_max= 256; + char ip_buf[ip_max]; + const char* addr_in= NULL; + const char* addr_out= NULL; + + if (!strcmp(wsrep_sst_method, WSREP_SST_SKIP)) + { + ssize_t ret = strlen(WSREP_STATE_TRANSFER_TRIVIAL) + 1; + *msg = strdup(WSREP_STATE_TRANSFER_TRIVIAL); + if (!msg) + { + WSREP_ERROR("Could not allocate %zd bytes for state request", ret); + unireg_abort(1); + } + return ret; + } + + // Figure out SST address. Common for all SST methods + if (wsrep_sst_receive_address && + strcmp (wsrep_sst_receive_address, WSREP_SST_ADDRESS_AUTO)) + { + addr_in= wsrep_sst_receive_address; + } + else if (wsrep_node_address && strlen(wsrep_node_address)) + { + const char* const colon= strchr (wsrep_node_address, ':'); + if (colon) + { + ptrdiff_t const len= colon - wsrep_node_address; + strncpy (ip_buf, wsrep_node_address, len); + ip_buf[len]= '\0'; + addr_in= ip_buf; + } + else + { + addr_in= wsrep_node_address; + } + } + else + { + ssize_t ret= wsrep_guess_ip (ip_buf, ip_max); + + if (ret && ret < ip_max) + { + addr_in= ip_buf; + } + else + { + WSREP_ERROR("Could not prepare state transfer request: " + "failed to guess address to accept state transfer at. " + "wsrep_sst_receive_address must be set manually."); + unireg_abort(1); + } + } + + ssize_t addr_len= -ENOSYS; + if (!strcmp(wsrep_sst_method, WSREP_SST_MYSQLDUMP)) + { + addr_len= sst_prepare_mysqldump (addr_in, &addr_out); + if (addr_len < 0) unireg_abort(1); + } + else + { + /*! A heuristic workaround until we learn how to stop and start engines */ + if (SE_initialized) + { + // we already did SST at initializaiton, now engines are running + // sql_print_information() is here because the message is too long + // for WSREP_INFO. + sql_print_information ("WSREP: " + "You have configured '%s' state snapshot transfer method " + "which cannot be performed on a running server. " + "Wsrep provider won't be able to fall back to it " + "if other means of state transfer are unavailable. " + "In that case you will need to restart the server.", + wsrep_sst_method); + *msg = 0; + return 0; + } + + addr_len = sst_prepare_other (wsrep_sst_method, addr_in, &addr_out); + if (addr_len < 0) + { + WSREP_ERROR("Failed to prepare for '%s' SST. Unrecoverable.", + wsrep_sst_method); + unireg_abort(1); + } + } + + size_t const method_len(strlen(wsrep_sst_method)); + size_t const msg_len (method_len + addr_len + 2 /* + auth_len + 1*/); + + *msg = malloc (msg_len); + if (NULL != *msg) { + char* const method_ptr(reinterpret_cast(*msg)); + strcpy (method_ptr, wsrep_sst_method); + char* const addr_ptr(method_ptr + method_len + 1); + strcpy (addr_ptr, addr_out); + + WSREP_INFO ("Prepared SST request: %s|%s", method_ptr, addr_ptr); + } + else { + WSREP_ERROR("Failed to allocate SST request of size %zu. Can't continue.", + msg_len); + unireg_abort(1); + } + + if (addr_out != addr_in) /* malloc'ed */ free ((char*)addr_out); + + return msg_len; +} + +// helper method for donors +static int sst_run_shell (const char* cmd_str, int max_tries) +{ + int ret = 0; + + for (int tries=1; tries <= max_tries; tries++) + { + wsp::process proc (cmd_str, "r"); + + if (NULL != proc.pipe()) + { + proc.wait(); + } + + if ((ret = proc.error())) + { + WSREP_ERROR("Try %d/%d: '%s' failed: %d (%s)", + tries, max_tries, proc.cmd(), ret, strerror(ret)); + sleep (1); + } + else + { + WSREP_DEBUG("SST script successfully completed."); + break; + } + } + + return -ret; +} + +static void sst_reject_queries(my_bool close_conn) +{ + wsrep_ready_set (FALSE); // this will be resotred when donor becomes synced + WSREP_INFO("Rejecting client queries for the duration of SST."); + if (TRUE == close_conn) wsrep_close_client_connections(FALSE); +} + +static int sst_mysqldump_check_addr (const char* user, const char* pswd, + const char* host, const char* port) +{ + return 0; +} + +static int sst_donate_mysqldump (const char* addr, + const wsrep_uuid_t* uuid, + const char* uuid_str, + wsrep_seqno_t seqno, + bool bypass) +{ + size_t host_len; + const char* port = strchr (addr, ':'); + + if (port) + { + port += 1; + host_len = port - addr; + } + else + { + port = ""; + host_len = strlen (addr) + 1; + } + + char host[host_len]; + + strncpy (host, addr, host_len - 1); + host[host_len - 1] = '\0'; + + const char* auth = sst_auth_real; + const char* pswd = (auth) ? strchr (auth, ':') : NULL; + size_t user_len; + + if (pswd) + { + pswd += 1; + user_len = pswd - auth; + } + else + { + pswd = ""; + user_len = (auth) ? strlen (auth) + 1 : 1; + } + + char user[user_len]; + + strncpy (user, (auth) ? auth : "", user_len - 1); + user[user_len - 1] = '\0'; + + int ret = sst_mysqldump_check_addr (user, pswd, host, port); + if (!ret) + { + size_t cmd_len= 1024; + char cmd_str[cmd_len]; + + if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(TRUE); + + snprintf (cmd_str, cmd_len, + "wsrep_sst_mysqldump " + WSREP_SST_OPT_USER" '%s' " + WSREP_SST_OPT_PSWD" '%s' " + WSREP_SST_OPT_HOST" '%s' " + WSREP_SST_OPT_PORT" '%s' " + WSREP_SST_OPT_LPORT" '%u' " + WSREP_SST_OPT_SOCKET" '%s' " + WSREP_SST_OPT_CONF" '%s' " + WSREP_SST_OPT_GTID" '%s:%lld'" + "%s", + user, pswd, host, port, mysqld_port, mysqld_unix_port, + wsrep_defaults_file, uuid_str, + (long long)seqno, bypass ? " "WSREP_SST_OPT_BYPASS : ""); + + WSREP_DEBUG("Running: '%s'", cmd_str); + + ret= sst_run_shell (cmd_str, 3); + } + + wsrep_gtid_t const state_id = { *uuid, (ret ? WSREP_SEQNO_UNDEFINED : seqno)}; + + wsrep->sst_sent (wsrep, &state_id, ret); + + return ret; +} + +wsrep_seqno_t wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED; + +static int run_sql_command(THD *thd, const char *query) +{ + thd->set_query((char *)query, strlen(query)); + + Parser_state ps; + if (ps.init(thd, thd->query(), thd->query_length())) + { + WSREP_ERROR("SST query: %s failed", query); + return -1; + } + + mysql_parse(thd, thd->query(), thd->query_length(), &ps); + if (thd->is_error()) + { + int const err= thd->get_stmt_da()->sql_errno(); + WSREP_WARN ("error executing '%s': %d (%s)%s", + query, err, thd->get_stmt_da()->message(), + err == ER_UNKNOWN_SYSTEM_VARIABLE ? + ". Was mysqld built with --with-innodb-disallow-writes ?" : ""); + thd->clear_error(); + return -1; + } + return 0; +} + +static int sst_flush_tables(THD* thd) +{ + WSREP_INFO("Flushing tables for SST..."); + + int err; + int not_used; + CHARSET_INFO *current_charset; + + current_charset = thd->variables.character_set_client; + + if (!is_supported_parser_charset(current_charset)) + { + /* Do not use non-supported parser character sets */ + WSREP_WARN("Current client character set is non-supported parser character set: %s", current_charset->csname); + thd->variables.character_set_client = &my_charset_latin1; + WSREP_WARN("For SST temporally setting character set to : %s", + my_charset_latin1.csname); + } + + if (run_sql_command(thd, "FLUSH TABLES WITH READ LOCK")) + { + WSREP_ERROR("Failed to flush and lock tables"); + err = -1; + } + else + { + /* make sure logs are flushed after global read lock acquired */ + err= reload_acl_and_cache(thd, REFRESH_ENGINE_LOG | REFRESH_BINARY_LOG, + (TABLE_LIST*) 0, ¬_used); + } + + thd->variables.character_set_client = current_charset; + + + if (err) + { + WSREP_ERROR("Failed to flush tables: %d (%s)", err, strerror(err)); + } + else + { + WSREP_INFO("Tables flushed."); + const char base_name[]= "tables_flushed"; + ssize_t const full_len= strlen(mysql_real_data_home) + strlen(base_name)+2; + char real_name[full_len]; + sprintf(real_name, "%s/%s", mysql_real_data_home, base_name); + char tmp_name[full_len + 4]; + sprintf(tmp_name, "%s.tmp", real_name); + + FILE* file= fopen(tmp_name, "w+"); + if (0 == file) + { + err= errno; + WSREP_ERROR("Failed to open '%s': %d (%s)", tmp_name, err,strerror(err)); + } + else + { + fprintf(file, "%s:%lld\n", + wsrep_cluster_state_uuid, (long long)wsrep_locked_seqno); + fsync(fileno(file)); + fclose(file); + if (rename(tmp_name, real_name) == -1) + { + err= errno; + WSREP_ERROR("Failed to rename '%s' to '%s': %d (%s)", + tmp_name, real_name, err,strerror(err)); + } + } + } + + return err; +} + +static void sst_disallow_writes (THD* thd, bool yes) +{ + char query_str[64] = { 0, }; + ssize_t const query_max = sizeof(query_str) - 1; + CHARSET_INFO *current_charset; + + current_charset = thd->variables.character_set_client; + + if (!is_supported_parser_charset(current_charset)) + { + /* Do not use non-supported parser character sets */ + WSREP_WARN("Current client character set is non-supported parser character set: %s", current_charset->csname); + thd->variables.character_set_client = &my_charset_latin1; + WSREP_WARN("For SST temporally setting character set to : %s", + my_charset_latin1.csname); + } + + snprintf (query_str, query_max, "SET GLOBAL innodb_disallow_writes=%d", + yes ? 1 : 0); + + if (run_sql_command(thd, query_str)) + { + WSREP_ERROR("Failed to disallow InnoDB writes"); + } + thd->variables.character_set_client = current_charset; +} + +static void* sst_donor_thread (void* a) +{ + sst_thread_arg* arg= (sst_thread_arg*)a; + + WSREP_INFO("Running: '%s'", arg->cmd); + + int err= 1; + bool locked= false; + + const char* out= NULL; + const size_t out_len= 128; + char out_buf[out_len]; + + wsrep_uuid_t ret_uuid= WSREP_UUID_UNDEFINED; + wsrep_seqno_t ret_seqno= WSREP_SEQNO_UNDEFINED; // seqno of complete SST + + wsp::thd thd(FALSE); // we turn off wsrep_on for this THD so that it can + // operate with wsrep_ready == OFF + wsp::process proc(arg->cmd, "r"); + + err= proc.error(); + +/* Inform server about SST script startup and release TO isolation */ + mysql_mutex_lock (&arg->lock); + arg->err = -err; + mysql_cond_signal (&arg->cond); + mysql_mutex_unlock (&arg->lock); //! @note arg is unusable after that. + + if (proc.pipe() && !err) + { +wait_signal: + out= my_fgets (out_buf, out_len, proc.pipe()); + + if (out) + { + const char magic_flush[]= "flush tables"; + const char magic_cont[]= "continue"; + const char magic_done[]= "done"; + + if (!strcasecmp (out, magic_flush)) + { + err= sst_flush_tables (thd.ptr); + if (!err) + { + sst_disallow_writes (thd.ptr, true); + locked= true; + goto wait_signal; + } + } + else if (!strcasecmp (out, magic_cont)) + { + if (locked) + { + sst_disallow_writes (thd.ptr, false); + thd.ptr->global_read_lock.unlock_global_read_lock (thd.ptr); + locked= false; + } + err= 0; + goto wait_signal; + } + else if (!strncasecmp (out, magic_done, strlen(magic_done))) + { + err= sst_scan_uuid_seqno (out + strlen(magic_done) + 1, + &ret_uuid, &ret_seqno); + } + else + { + WSREP_WARN("Received unknown signal: '%s'", out); + } + } + else + { + WSREP_ERROR("Failed to read from: %s", proc.cmd()); + proc.wait(); + } + if (!err && proc.error()) err= proc.error(); + } + else + { + WSREP_ERROR("Failed to execute: %s : %d (%s)", + proc.cmd(), err, strerror(err)); + } + + if (locked) // don't forget to unlock server before return + { + sst_disallow_writes (thd.ptr, false); + thd.ptr->global_read_lock.unlock_global_read_lock (thd.ptr); + } + + // signal to donor that SST is over + struct wsrep_gtid const state_id = { + ret_uuid, err ? WSREP_SEQNO_UNDEFINED : ret_seqno + }; + wsrep->sst_sent (wsrep, &state_id, -err); + proc.wait(); + + return NULL; +} + + + +static int sst_donate_other (const char* method, + const char* addr, + const char* uuid, + wsrep_seqno_t seqno, + bool bypass) +{ + ssize_t cmd_len = 4096; + char cmd_str[cmd_len]; + const char* binlog_opt= ""; + char* binlog_opt_val= NULL; + + int ret; + if ((ret= generate_binlog_opt_val(&binlog_opt_val))) + { + WSREP_ERROR("sst_donate_other(): generate_binlog_opt_val() failed: %d",ret); + return ret; + } + if (strlen(binlog_opt_val)) binlog_opt= WSREP_SST_OPT_BINLOG; + + ret= snprintf (cmd_str, cmd_len, + "wsrep_sst_%s " + WSREP_SST_OPT_ROLE" 'donor' " + WSREP_SST_OPT_ADDR" '%s' " + WSREP_SST_OPT_AUTH" '%s' " + WSREP_SST_OPT_SOCKET" '%s' " + WSREP_SST_OPT_DATA" '%s' " + WSREP_SST_OPT_CONF" '%s' " + " %s '%s' " + WSREP_SST_OPT_GTID" '%s:%lld'" + "%s", + method, addr, sst_auth_real, mysqld_unix_port, + mysql_real_data_home, wsrep_defaults_file, + binlog_opt, binlog_opt_val, + uuid, (long long) seqno, + bypass ? " "WSREP_SST_OPT_BYPASS : ""); + my_free(binlog_opt_val); + + if (ret < 0 || ret >= cmd_len) + { + WSREP_ERROR("sst_donate_other(): snprintf() failed: %d", ret); + return (ret < 0 ? ret : -EMSGSIZE); + } + + if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(FALSE); + + pthread_t tmp; + sst_thread_arg arg(cmd_str); + mysql_mutex_lock (&arg.lock); + ret = pthread_create (&tmp, NULL, sst_donor_thread, &arg); + if (ret) + { + WSREP_ERROR("sst_donate_other(): pthread_create() failed: %d (%s)", + ret, strerror(ret)); + return ret; + } + mysql_cond_wait (&arg.cond, &arg.lock); + + WSREP_INFO("sst_donor_thread signaled with %d", arg.err); + return arg.err; +} + +wsrep_cb_status_t wsrep_sst_donate_cb (void* app_ctx, void* recv_ctx, + const void* msg, size_t msg_len, + const wsrep_gtid_t* current_gtid, + const char* state, size_t state_len, + bool bypass) +{ + /* This will be reset when sync callback is called. + * Should we set wsrep_ready to FALSE here too? */ +// wsrep_notify_status(WSREP_MEMBER_DONOR); + local_status.set(WSREP_MEMBER_DONOR); + + const char* method = (char*)msg; + size_t method_len = strlen (method); + const char* data = method + method_len + 1; + + char uuid_str[37]; + wsrep_uuid_print (¤t_gtid->uuid, uuid_str, sizeof(uuid_str)); + + int ret; + if (!strcmp (WSREP_SST_MYSQLDUMP, method)) + { + ret = sst_donate_mysqldump(data, ¤t_gtid->uuid, uuid_str, + current_gtid->seqno, bypass); + } + else + { + ret = sst_donate_other(method, data, uuid_str, current_gtid->seqno,bypass); + } + + return (ret > 0 ? WSREP_CB_SUCCESS : WSREP_CB_FAILURE); +} + +void wsrep_SE_init_grab() +{ + if (mysql_mutex_lock (&LOCK_wsrep_sst_init)) abort(); +} + +void wsrep_SE_init_wait() +{ + while (SE_initialized == false) + { + mysql_cond_wait (&COND_wsrep_sst_init, &LOCK_wsrep_sst_init); + } + mysql_mutex_unlock (&LOCK_wsrep_sst_init); +} + +void wsrep_SE_init_done() +{ + mysql_cond_signal (&COND_wsrep_sst_init); + mysql_mutex_unlock (&LOCK_wsrep_sst_init); +} + +void wsrep_SE_initialized() +{ + SE_initialized = true; +} diff --git a/sql/wsrep_sst.h b/sql/wsrep_sst.h new file mode 100644 index 00000000000..6b2b419e63a --- /dev/null +++ b/sql/wsrep_sst.h @@ -0,0 +1,68 @@ +/* Copyright (C) 2013 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + +#ifndef WSREP_SST_H +#define WSREP_SST_H + +#include // my_bool + +#define WSREP_SST_OPT_ROLE "--role" +#define WSREP_SST_OPT_ADDR "--address" +#define WSREP_SST_OPT_AUTH "--auth" +#define WSREP_SST_OPT_DATA "--datadir" +#define WSREP_SST_OPT_CONF "--defaults-file" +#define WSREP_SST_OPT_PARENT "--parent" +#define WSREP_SST_OPT_BINLOG "--binlog" + +// mysqldump-specific options +#define WSREP_SST_OPT_USER "--user" +#define WSREP_SST_OPT_PSWD "--password" +#define WSREP_SST_OPT_HOST "--host" +#define WSREP_SST_OPT_PORT "--port" +#define WSREP_SST_OPT_LPORT "--local-port" + +// donor-specific +#define WSREP_SST_OPT_SOCKET "--socket" +#define WSREP_SST_OPT_GTID "--gtid" +#define WSREP_SST_OPT_BYPASS "--bypass" + +#define WSREP_SST_MYSQLDUMP "mysqldump" +#define WSREP_SST_RSYNC "rsync" +#define WSREP_SST_SKIP "skip" +#define WSREP_SST_DEFAULT WSREP_SST_RSYNC +#define WSREP_SST_ADDRESS_AUTO "AUTO" +#define WSREP_SST_AUTH_MASK "********" + +/* system variables */ +extern const char* wsrep_sst_method; +extern const char* wsrep_sst_receive_address; +extern const char* wsrep_sst_donor; +extern char* wsrep_sst_auth; +extern my_bool wsrep_sst_donor_rejects_queries; + +/*! Synchronizes applier thread start with init thread */ +extern void wsrep_sst_grab(); +/*! Init thread waits for SST completion */ +extern bool wsrep_sst_wait(); +/*! Signals wsrep that initialization is complete, writesets can be applied */ +extern void wsrep_sst_continue(); +extern void wsrep_sst_auth_free(); + +extern void wsrep_SE_init_grab(); /*! grab init critical section */ +extern void wsrep_SE_init_wait(); /*! wait for SE init to complete */ +extern void wsrep_SE_init_done(); /*! signal that SE init is complte */ +extern void wsrep_SE_initialized(); /*! mark SE initialization complete */ + +#endif /* WSREP_SST_H */ diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc new file mode 100644 index 00000000000..b485daa2a9c --- /dev/null +++ b/sql/wsrep_thd.cc @@ -0,0 +1,584 @@ +/* Copyright (C) 2013 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + +#include "wsrep_thd.h" + +#include "transaction.h" +#include "rpl_rli.h" +#include "log_event.h" +#include "sql_parse.h" +//#include "global_threads.h" // LOCK_thread_count, etc. +#include "sql_base.h" // close_thread_tables() +#include "mysqld.h" // start_wsrep_THD(); + +#include "slave.h" // opt_log_slave_updates +#include "rpl_filter.h" +#include "rpl_rli.h" +#include "rpl_mi.h" + +#if (__LP64__) +static volatile int64 wsrep_bf_aborts_counter(0); +#define WSREP_ATOMIC_LOAD_LONG my_atomic_load64 +#define WSREP_ATOMIC_ADD_LONG my_atomic_add64 +#else +static volatile int32 wsrep_bf_aborts_counter(0); +#define WSREP_ATOMIC_LOAD_LONG my_atomic_load32 +#define WSREP_ATOMIC_ADD_LONG my_atomic_add32 +#endif + +int wsrep_show_bf_aborts (THD *thd, SHOW_VAR *var, char *buff) +{ + wsrep_local_bf_aborts = WSREP_ATOMIC_LOAD_LONG(&wsrep_bf_aborts_counter); + var->type = SHOW_LONGLONG; + var->value = (char*)&wsrep_local_bf_aborts; + return 0; +} + +/* must have (&thd->LOCK_wsrep_thd) */ +void wsrep_client_rollback(THD *thd) +{ + WSREP_DEBUG("client rollback due to BF abort for (%ld), query: %s", + thd->thread_id, thd->query()); + + WSREP_ATOMIC_ADD_LONG(&wsrep_bf_aborts_counter, 1); + + thd->wsrep_conflict_state= ABORTING; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + trans_rollback(thd); + + if (thd->locked_tables_mode && thd->lock) + { + WSREP_DEBUG("unlocking tables for BF abort (%ld)", thd->thread_id); + thd->locked_tables_list.unlock_locked_tables(thd); + thd->variables.option_bits&= ~(OPTION_TABLE_LOCK); + } + + if (thd->global_read_lock.is_acquired()) + { + WSREP_DEBUG("unlocking GRL for BF abort (%ld)", thd->thread_id); + thd->global_read_lock.unlock_global_read_lock(thd); + } + + /* Release transactional metadata locks. */ + thd->mdl_context.release_transactional_locks(); + + /* release explicit MDL locks */ + thd->mdl_context.release_explicit_locks(); + + if (thd->get_binlog_table_maps()) + { + WSREP_DEBUG("clearing binlog table map for BF abort (%ld)", thd->thread_id); + thd->clear_binlog_table_maps(); + } + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + thd->wsrep_conflict_state= ABORTED; +} + +#define NUMBER_OF_FIELDS_TO_IDENTIFY_COORDINATOR 1 +#define NUMBER_OF_FIELDS_TO_IDENTIFY_WORKER 2 +//#include "rpl_info_factory.h" + +static Relay_log_info* wsrep_relay_log_init(const char* log_fname) +{ + + /* MySQL 5.6 version has rli factory: */ +#ifdef MYSQL_56 + uint rli_option = INFO_REPOSITORY_DUMMY; + Relay_log_info *rli= NULL; + rli = Rpl_info_factory::create_rli(rli_option, false); + rli->set_rli_description_event( + new Format_description_log_event(BINLOG_VERSION)); +#endif + Relay_log_info* rli= new Relay_log_info(false); + rli->sql_driver_thd= current_thd; + + rli->no_storage= true; + rli->relay_log.description_event_for_exec= + new Format_description_log_event(4); + + return rli; +} + +class Master_info; + +static rpl_group_info* wsrep_relay_group_init(const char* log_fname) +{ + Relay_log_info* rli= new Relay_log_info(false); + + rli->no_storage= true; + if (!rli->relay_log.description_event_for_exec) + { + rli->relay_log.description_event_for_exec= + new Format_description_log_event(4); + } + static LEX_STRING dbname= { C_STRING_WITH_LEN("mysql") }; + + rli->mi = new Master_info( &dbname, false); + //rli->mi = new Master_info( &(C_STRING_WITH_LEN("wsrep")), false); + + rli->mi->rpl_filter = new Rpl_filter; + copy_filter_setting(rli->mi->rpl_filter, get_or_create_rpl_filter("", 0)); + + rli->sql_driver_thd= current_thd; + + struct rpl_group_info *rgi= new rpl_group_info(rli); + rgi->thd= current_thd; + + return rgi; +} + +static void wsrep_prepare_bf_thd(THD *thd, struct wsrep_thd_shadow* shadow) +{ + shadow->options = thd->variables.option_bits; + shadow->server_status = thd->server_status; + shadow->wsrep_exec_mode = thd->wsrep_exec_mode; + shadow->vio = thd->net.vio; + + if (opt_log_slave_updates) + thd->variables.option_bits|= OPTION_BIN_LOG; + else + thd->variables.option_bits&= ~(OPTION_BIN_LOG); + + //if (!thd->wsrep_rli) thd->wsrep_rli= wsrep_relay_log_init("wsrep_relay"); + if (!thd->wsrep_rgi) thd->wsrep_rgi= wsrep_relay_group_init("wsrep_relay"); + // thd->wsrep_rli->info_thd = thd; + + thd->wsrep_exec_mode= REPL_RECV; + thd->net.vio= 0; + thd->clear_error(); + + shadow->tx_isolation = thd->variables.tx_isolation; + thd->variables.tx_isolation = ISO_READ_COMMITTED; + thd->tx_isolation = ISO_READ_COMMITTED; + + shadow->db = thd->db; + shadow->db_length = thd->db_length; + thd->reset_db(NULL, 0); +} + +static void wsrep_return_from_bf_mode(THD *thd, struct wsrep_thd_shadow* shadow) +{ + thd->variables.option_bits = shadow->options; + thd->server_status = shadow->server_status; + thd->wsrep_exec_mode = shadow->wsrep_exec_mode; + thd->net.vio = shadow->vio; + thd->variables.tx_isolation = shadow->tx_isolation; + thd->reset_db(shadow->db, shadow->db_length); + + delete thd->wsrep_rgi->rli->mi->rpl_filter; + delete thd->wsrep_rgi->rli->mi; + delete thd->wsrep_rgi->rli; + delete thd->wsrep_rgi; + thd->wsrep_rgi = NULL; +; +} + +void wsrep_replay_transaction(THD *thd) +{ + /* checking if BF trx must be replayed */ + if (thd->wsrep_conflict_state== MUST_REPLAY) { + DBUG_ASSERT(wsrep_thd_trx_seqno(thd)); + if (thd->wsrep_exec_mode!= REPL_RECV) { + if (thd->get_stmt_da()->is_sent()) + { + WSREP_ERROR("replay issue, thd has reported status already"); + } + thd->get_stmt_da()->reset_diagnostics_area(); + + thd->wsrep_conflict_state= REPLAYING; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + + mysql_reset_thd_for_next_command(thd); + thd->killed= NOT_KILLED; + close_thread_tables(thd); + if (thd->locked_tables_mode && thd->lock) + { + WSREP_DEBUG("releasing table lock for replaying (%ld)", + thd->thread_id); + thd->locked_tables_list.unlock_locked_tables(thd); + thd->variables.option_bits&= ~(OPTION_TABLE_LOCK); + } + thd->mdl_context.release_transactional_locks(); + /* + Replaying will call MYSQL_START_STATEMENT when handling + BEGIN Query_log_event so end statement must be called before + replaying. + */ + MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da()); + thd->m_statement_psi= NULL; + thd_proc_info(thd, "wsrep replaying trx"); + WSREP_DEBUG("replay trx: %s %lld", + thd->query() ? thd->query() : "void", + (long long)wsrep_thd_trx_seqno(thd)); + struct wsrep_thd_shadow shadow; + wsrep_prepare_bf_thd(thd, &shadow); + + /* From trans_begin() */ + thd->variables.option_bits|= OPTION_BEGIN; + thd->server_status|= SERVER_STATUS_IN_TRANS; + + int rcode = wsrep->replay_trx(wsrep, + &thd->wsrep_ws_handle, + (void *)thd); + + wsrep_return_from_bf_mode(thd, &shadow); + if (thd->wsrep_conflict_state!= REPLAYING) + WSREP_WARN("lost replaying mode: %d", thd->wsrep_conflict_state ); + + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + + switch (rcode) + { + case WSREP_OK: + thd->wsrep_conflict_state= NO_CONFLICT; + wsrep->post_commit(wsrep, &thd->wsrep_ws_handle); + WSREP_DEBUG("trx_replay successful for: %ld %llu", + thd->thread_id, (long long)thd->real_id); + if (thd->get_stmt_da()->is_sent()) + { + WSREP_WARN("replay ok, thd has reported status"); + } + else if (thd->get_stmt_da()->is_set()) + { + if (thd->get_stmt_da()->status() != Diagnostics_area::DA_OK) + { + WSREP_WARN("replay ok, thd has error status %d", + thd->get_stmt_da()->status()); + } + } + else + { + my_ok(thd); + } + break; + case WSREP_TRX_FAIL: + if (thd->get_stmt_da()->is_sent()) + { + WSREP_ERROR("replay failed, thd has reported status"); + } + else + { + WSREP_DEBUG("replay failed, rolling back"); + //my_error(ER_LOCK_DEADLOCK, MYF(0), "wsrep aborted transaction"); + } + thd->wsrep_conflict_state= ABORTED; + wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle); + break; + default: + WSREP_ERROR("trx_replay failed for: %d, query: %s", + rcode, thd->query() ? thd->query() : "void"); + /* we're now in inconsistent state, must abort */ + unireg_abort(1); + break; + } + + wsrep_cleanup_transaction(thd); + + mysql_mutex_lock(&LOCK_wsrep_replaying); + wsrep_replaying--; + WSREP_DEBUG("replaying decreased: %d, thd: %lu", + wsrep_replaying, thd->thread_id); + mysql_cond_broadcast(&COND_wsrep_replaying); + mysql_mutex_unlock(&LOCK_wsrep_replaying); + } + } +} + +static void wsrep_replication_process(THD *thd) +{ + int rcode; + DBUG_ENTER("wsrep_replication_process"); + + struct wsrep_thd_shadow shadow; + wsrep_prepare_bf_thd(thd, &shadow); + + /* From trans_begin() */ + thd->variables.option_bits|= OPTION_BEGIN; + thd->server_status|= SERVER_STATUS_IN_TRANS; + + rcode = wsrep->recv(wsrep, (void *)thd); + DBUG_PRINT("wsrep",("wsrep_repl returned: %d", rcode)); + + WSREP_INFO("applier thread exiting (code:%d)", rcode); + + switch (rcode) { + case WSREP_OK: + case WSREP_NOT_IMPLEMENTED: + case WSREP_CONN_FAIL: + /* provider does not support slave operations / disconnected from group, + * just close applier thread */ + break; + case WSREP_NODE_FAIL: + /* data inconsistency => SST is needed */ + /* Note: we cannot just blindly restart replication here, + * SST might require server restart if storage engines must be + * initialized after SST */ + WSREP_ERROR("node consistency compromised, aborting"); + wsrep_kill_mysql(thd); + break; + case WSREP_WARNING: + case WSREP_TRX_FAIL: + case WSREP_TRX_MISSING: + /* these suggests a bug in provider code */ + WSREP_WARN("bad return from recv() call: %d", rcode); + /* fall through to node shutdown */ + case WSREP_FATAL: + /* Cluster connectivity is lost. + * + * If applier was killed on purpose (KILL_CONNECTION), we + * avoid mysql shutdown. This is because the killer will then handle + * shutdown processing (or replication restarting) + */ + if (thd->killed != KILL_CONNECTION) + { + wsrep_kill_mysql(thd); + } + break; + } + + mysql_mutex_lock(&LOCK_thread_count); + wsrep_close_applier(thd); + mysql_cond_broadcast(&COND_thread_count); + mysql_mutex_unlock(&LOCK_thread_count); + + TABLE *tmp; + while ((tmp = thd->temporary_tables)) + { + WSREP_WARN("Applier %lu, has temporary tables at exit: %s.%s", + thd->thread_id, + (tmp->s) ? tmp->s->db.str : "void", + (tmp->s) ? tmp->s->table_name.str : "void"); + } + wsrep_return_from_bf_mode(thd, &shadow); + DBUG_VOID_RETURN; +} + +void wsrep_create_appliers(long threads) +{ + if (!wsrep_connected) + { + /* see wsrep_replication_start() for the logic */ + if (wsrep_cluster_address && strlen(wsrep_cluster_address) && + wsrep_provider && strcasecmp(wsrep_provider, "none")) + { + WSREP_ERROR("Trying to launch slave threads before creating " + "connection at '%s'", wsrep_cluster_address); + assert(0); + } + return; + } + + long wsrep_threads=0; + pthread_t hThread; + while (wsrep_threads++ < threads) { + if (pthread_create( + &hThread, &connection_attrib, + start_wsrep_THD, (void*)wsrep_replication_process)) + WSREP_WARN("Can't create thread to manage wsrep replication"); + } +} + +static void wsrep_rollback_process(THD *thd) +{ + DBUG_ENTER("wsrep_rollback_process"); + + mysql_mutex_lock(&LOCK_wsrep_rollback); + wsrep_aborting_thd= NULL; + + while (thd->killed == NOT_KILLED) { + thd_proc_info(thd, "wsrep aborter idle"); + thd->mysys_var->current_mutex= &LOCK_wsrep_rollback; + thd->mysys_var->current_cond= &COND_wsrep_rollback; + + mysql_cond_wait(&COND_wsrep_rollback,&LOCK_wsrep_rollback); + + WSREP_DEBUG("WSREP rollback thread wakes for signal"); + + mysql_mutex_lock(&thd->mysys_var->mutex); + thd_proc_info(thd, "wsrep aborter active"); + thd->mysys_var->current_mutex= 0; + thd->mysys_var->current_cond= 0; + mysql_mutex_unlock(&thd->mysys_var->mutex); + + /* check for false alarms */ + if (!wsrep_aborting_thd) + { + WSREP_DEBUG("WSREP rollback thread has empty abort queue"); + } + /* process all entries in the queue */ + while (wsrep_aborting_thd) { + THD *aborting; + wsrep_aborting_thd_t next = wsrep_aborting_thd->next; + aborting = wsrep_aborting_thd->aborting_thd; + my_free(wsrep_aborting_thd); + wsrep_aborting_thd= next; + /* + * must release mutex, appliers my want to add more + * aborting thds in our work queue, while we rollback + */ + mysql_mutex_unlock(&LOCK_wsrep_rollback); + + mysql_mutex_lock(&aborting->LOCK_wsrep_thd); + if (aborting->wsrep_conflict_state== ABORTED) + { + WSREP_DEBUG("WSREP, thd already aborted: %llu state: %d", + (long long)aborting->real_id, + aborting->wsrep_conflict_state); + + mysql_mutex_unlock(&aborting->LOCK_wsrep_thd); + mysql_mutex_lock(&LOCK_wsrep_rollback); + continue; + } + aborting->wsrep_conflict_state= ABORTING; + + mysql_mutex_unlock(&aborting->LOCK_wsrep_thd); + + set_current_thd(aborting); + aborting->store_globals(); + + mysql_mutex_lock(&aborting->LOCK_wsrep_thd); + wsrep_client_rollback(aborting); + WSREP_DEBUG("WSREP rollbacker aborted thd: (%lu %llu)", + aborting->thread_id, (long long)aborting->real_id); + mysql_mutex_unlock(&aborting->LOCK_wsrep_thd); + + set_current_thd(thd); + thd->store_globals(); + + mysql_mutex_lock(&LOCK_wsrep_rollback); + } + } + + mysql_mutex_unlock(&LOCK_wsrep_rollback); + sql_print_information("WSREP: rollbacker thread exiting"); + + DBUG_PRINT("wsrep",("wsrep rollbacker thread exiting")); + DBUG_VOID_RETURN; +} + +void wsrep_create_rollbacker() +{ + if (wsrep_provider && strcasecmp(wsrep_provider, "none")) + { + pthread_t hThread; + /* create rollbacker */ + if (pthread_create( &hThread, &connection_attrib, + start_wsrep_THD, (void*)wsrep_rollback_process)) + WSREP_WARN("Can't create thread to manage wsrep rollback"); + } +} + +void wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe) +{ + if (thd_ptr) + { + THD* thd = (THD*)thd_ptr; + thd->wsrep_PA_safe = safe; + } +} + +int wsrep_thd_conflict_state(void *thd_ptr, my_bool sync) +{ + int state = -1; + if (thd_ptr) + { + THD* thd = (THD*)thd_ptr; + if (sync) mysql_mutex_lock(&thd->LOCK_wsrep_thd); + + state = thd->wsrep_conflict_state; + if (sync) mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } + return state; +} + +my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync) +{ + my_bool status = FALSE; + if (thd_ptr) + { + THD* thd = (THD*)thd_ptr; + if (sync) mysql_mutex_lock(&thd->LOCK_wsrep_thd); + + status = ((thd->wsrep_exec_mode == REPL_RECV) || + (thd->wsrep_exec_mode == TOTAL_ORDER)); + if (sync) mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } + return status; +} + +extern "C" +my_bool wsrep_thd_is_BF_or_commit(void *thd_ptr, my_bool sync) +{ + bool status = FALSE; + if (thd_ptr) + { + THD* thd = (THD*)thd_ptr; + if (sync) mysql_mutex_lock(&thd->LOCK_wsrep_thd); + + status = ((thd->wsrep_exec_mode == REPL_RECV) || + (thd->wsrep_exec_mode == TOTAL_ORDER) || + (thd->wsrep_exec_mode == LOCAL_COMMIT)); + if (sync) mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } + return status; +} + +extern "C" +my_bool wsrep_thd_is_local(void *thd_ptr, my_bool sync) +{ + bool status = FALSE; + if (thd_ptr) + { + THD* thd = (THD*)thd_ptr; + if (sync) mysql_mutex_lock(&thd->LOCK_wsrep_thd); + + status = (thd->wsrep_exec_mode == LOCAL_STATE); + if (sync) mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } + return status; +} + +int wsrep_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr, my_bool signal) +{ + THD *victim_thd = (THD *) victim_thd_ptr; + THD *bf_thd = (THD *) bf_thd_ptr; + DBUG_ENTER("wsrep_abort_thd"); + + if ( (WSREP(bf_thd) || + ( (WSREP_ON || wsrep_OSU_method_options == WSREP_OSU_RSU) && + bf_thd->wsrep_exec_mode == TOTAL_ORDER) ) && + victim_thd) + { + WSREP_DEBUG("wsrep_abort_thd, by: %llu, victim: %llu", (bf_thd) ? + (long long)bf_thd->real_id : 0, (long long)victim_thd->real_id); + ha_wsrep_abort_transaction(bf_thd, victim_thd, signal); + } + else + { + WSREP_DEBUG("wsrep_abort_thd not effective: %p %p", bf_thd, victim_thd); + } + + DBUG_RETURN(1); +} + +extern "C" +int wsrep_thd_in_locking_session(void *thd_ptr) +{ + if (thd_ptr && ((THD *)thd_ptr)->in_lock_tables) { + return 1; + } + return 0; +} + diff --git a/sql/wsrep_thd.h b/sql/wsrep_thd.h new file mode 100644 index 00000000000..a7e34c35101 --- /dev/null +++ b/sql/wsrep_thd.h @@ -0,0 +1,38 @@ +/* Copyright (C) 2013 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + +#ifndef WSREP_THD_H +#define WSREP_THD_H + +#include "sql_class.h" + +int wsrep_show_bf_aborts (THD *thd, SHOW_VAR *var, char *buff); +void wsrep_client_rollback(THD *thd); +void wsrep_replay_transaction(THD *thd); +void wsrep_create_appliers(long threads); +void wsrep_create_rollbacker(); + +int wsrep_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr, + my_bool signal); + +extern void wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe); +extern my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync); +extern int wsrep_thd_conflict_state(void *thd_ptr, my_bool sync); +//extern "C" my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync); +extern "C" my_bool wsrep_thd_is_BF_or_commit(void *thd_ptr, my_bool sync); +extern "C" my_bool wsrep_thd_is_local(void *thd_ptr, my_bool sync); +extern "C" int wsrep_thd_in_locking_session(void *thd_ptr); + +#endif /* WSREP_THD_H */ diff --git a/sql/wsrep_utils.cc b/sql/wsrep_utils.cc new file mode 100644 index 00000000000..cdee1c2cece --- /dev/null +++ b/sql/wsrep_utils.cc @@ -0,0 +1,524 @@ +/* Copyright 2010 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//! @file some utility functions and classes not directly related to replication + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE // POSIX_SPAWN_USEVFORK flag +#endif + +#include "wsrep_utils.h" +#include "wsrep_mysqld.h" + +#include + +#include // posix_spawn() +#include // pipe() +#include // errno +#include // strerror() +#include // waitpid() +#include +#include +#include // getaddrinfo() + +extern char** environ; // environment variables + +static wsp::string wsrep_PATH; + +void +wsrep_prepend_PATH (const char* path) +{ + int count = 0; + + while (environ[count]) + { + if (strncmp (environ[count], "PATH=", 5)) + { + count++; + continue; + } + + char* const old_path (environ[count]); + + if (strstr (old_path, path)) return; // path already there + + size_t const new_path_len(strlen(old_path) + strlen(":") + + strlen(path) + 1); + + char* const new_path (reinterpret_cast(malloc(new_path_len))); + + if (new_path) + { + snprintf (new_path, new_path_len, "PATH=%s:%s", path, + old_path + strlen("PATH=")); + + wsrep_PATH.set (new_path); + environ[count] = new_path; + } + else + { + WSREP_ERROR ("Failed to allocate 'PATH' environment variable " + "buffer of size %zu.", new_path_len); + } + + return; + } + + WSREP_ERROR ("Failed to find 'PATH' environment variable. " + "State snapshot transfer may not be working."); +} + +namespace wsp +{ + +#define PIPE_READ 0 +#define PIPE_WRITE 1 +#define STDIN_FD 0 +#define STDOUT_FD 1 + +#ifndef POSIX_SPAWN_USEVFORK +# define POSIX_SPAWN_USEVFORK 0 +#endif + +process::process (const char* cmd, const char* type) + : str_(cmd ? strdup(cmd) : strdup("")), io_(NULL), err_(EINVAL), pid_(0) +{ + if (0 == str_) + { + WSREP_ERROR ("Can't allocate command line of size: %zu", strlen(cmd)); + err_ = ENOMEM; + return; + } + + if (0 == strlen(str_)) + { + WSREP_ERROR ("Can't start a process: null or empty command line."); + return; + } + + if (NULL == type || (strcmp (type, "w") && strcmp(type, "r"))) + { + WSREP_ERROR ("type argument should be either \"r\" or \"w\"."); + return; + } + + int pipe_fds[2] = { -1, }; + if (::pipe(pipe_fds)) + { + err_ = errno; + WSREP_ERROR ("pipe() failed: %d (%s)", err_, strerror(err_)); + return; + } + + // which end of pipe will be returned to parent + int const parent_end (strcmp(type,"w") ? PIPE_READ : PIPE_WRITE); + int const child_end (parent_end == PIPE_READ ? PIPE_WRITE : PIPE_READ); + int const close_fd (parent_end == PIPE_READ ? STDOUT_FD : STDIN_FD); + + char* const pargv[4] = { strdup("sh"), strdup("-c"), strdup(str_), NULL }; + if (!(pargv[0] && pargv[1] && pargv[2])) + { + err_ = ENOMEM; + WSREP_ERROR ("Failed to allocate pargv[] array."); + goto cleanup_pipe; + } + + posix_spawnattr_t attr; + err_ = posix_spawnattr_init (&attr); + if (err_) + { + WSREP_ERROR ("posix_spawnattr_init() failed: %d (%s)", + err_, strerror(err_)); + goto cleanup_pipe; + } + + err_ = posix_spawnattr_setflags (&attr, POSIX_SPAWN_SETSIGDEF | + POSIX_SPAWN_USEVFORK); + if (err_) + { + WSREP_ERROR ("posix_spawnattr_setflags() failed: %d (%s)", + err_, strerror(err_)); + goto cleanup_attr; + } + + posix_spawn_file_actions_t fact; + err_ = posix_spawn_file_actions_init (&fact); + if (err_) + { + WSREP_ERROR ("posix_spawn_file_actions_init() failed: %d (%s)", + err_, strerror(err_)); + goto cleanup_attr; + } + + // close child's stdout|stdin depending on what we returning + err_ = posix_spawn_file_actions_addclose (&fact, close_fd); + if (err_) + { + WSREP_ERROR ("posix_spawn_file_actions_addclose() failed: %d (%s)", + err_, strerror(err_)); + goto cleanup_fact; + } + + // substitute our pipe descriptor in place of the closed one + err_ = posix_spawn_file_actions_adddup2 (&fact, + pipe_fds[child_end], close_fd); + if (err_) + { + WSREP_ERROR ("posix_spawn_file_actions_addup2() failed: %d (%s)", + err_, strerror(err_)); + goto cleanup_fact; + } + + err_ = posix_spawnp (&pid_, pargv[0], &fact, &attr, pargv, environ); + if (err_) + { + WSREP_ERROR ("posix_spawnp(%s) failed: %d (%s)", + pargv[2], err_, strerror(err_)); + pid_ = 0; // just to make sure it was not messed up in the call + goto cleanup_fact; + } + + io_ = fdopen (pipe_fds[parent_end], type); + + if (io_) + { + pipe_fds[parent_end] = -1; // skip close on cleanup + } + else + { + err_ = errno; + WSREP_ERROR ("fdopen() failed: %d (%s)", err_, strerror(err_)); + } + +cleanup_fact: + int err; // to preserve err_ code + err = posix_spawn_file_actions_destroy (&fact); + if (err) + { + WSREP_ERROR ("posix_spawn_file_actions_destroy() failed: %d (%s)\n", + err, strerror(err)); + } + +cleanup_attr: + err = posix_spawnattr_destroy (&attr); + if (err) + { + WSREP_ERROR ("posix_spawnattr_destroy() failed: %d (%s)", + err, strerror(err)); + } + +cleanup_pipe: + if (pipe_fds[0] >= 0) close (pipe_fds[0]); + if (pipe_fds[1] >= 0) close (pipe_fds[1]); + + free (pargv[0]); + free (pargv[1]); + free (pargv[2]); +} + +process::~process () +{ + if (io_) + { + assert (pid_); + assert (str_); + + WSREP_WARN("Closing pipe to child process: %s, PID(%ld) " + "which might still be running.", str_, (long)pid_); + + if (fclose (io_) == -1) + { + err_ = errno; + WSREP_ERROR("fclose() failed: %d (%s)", err_, strerror(err_)); + } + } + + if (str_) free (const_cast(str_)); +} + +int +process::wait () +{ + if (pid_) + { + int status; + if (-1 == waitpid(pid_, &status, 0)) + { + err_ = errno; assert (err_); + WSREP_ERROR("Waiting for process failed: %s, PID(%ld): %d (%s)", + str_, (long)pid_, err_, strerror (err_)); + } + else + { // command completed, check exit status + if (WIFEXITED (status)) { + err_ = WEXITSTATUS (status); + } + else { // command didn't complete with exit() + WSREP_ERROR("Process was aborted."); + err_ = errno ? errno : ECHILD; + } + + if (err_) { + switch (err_) /* Translate error codes to more meaningful */ + { + case 126: err_ = EACCES; break; /* Permission denied */ + case 127: err_ = ENOENT; break; /* No such file or directory */ + } + WSREP_ERROR("Process completed with error: %s: %d (%s)", + str_, err_, strerror(err_)); + } + + pid_ = 0; + if (io_) fclose (io_); + io_ = NULL; + } + } + else { + assert (NULL == io_); + WSREP_ERROR("Command did not run: %s", str_); + } + + return err_; +} + +thd::thd (my_bool won) : init(), ptr(new THD) +{ + if (ptr) + { + ptr->thread_stack= (char*) &ptr; + ptr->store_globals(); + ptr->variables.option_bits&= ~OPTION_BIN_LOG; // disable binlog + ptr->variables.wsrep_on = won; + ptr->security_ctx->master_access= ~(ulong)0; + lex_start(ptr); + } +} + +thd::~thd () +{ + if (ptr) + { + delete ptr; + my_pthread_setspecific_ptr (THR_THD, 0); + } +} + +} // namespace wsp + +/* Returns INADDR_NONE, INADDR_ANY, INADDR_LOOPBACK or something else */ +unsigned int wsrep_check_ip (const char* const addr) +{ +#if 0 + if (addr && 0 == strcasecmp(addr, MY_BIND_ALL_ADDRESSES)) return INADDR_ANY; +#endif + + unsigned int ret = INADDR_NONE; + struct addrinfo *res, hints; + + memset (&hints, 0, sizeof(hints)); + hints.ai_flags= AI_PASSIVE/*|AI_ADDRCONFIG*/; + hints.ai_socktype= SOCK_STREAM; + hints.ai_family= AF_UNSPEC; + + int gai_ret = getaddrinfo(addr, NULL, &hints, &res); + if (0 == gai_ret) + { + if (AF_INET == res->ai_family) /* IPv4 */ + { + struct sockaddr_in* a= (struct sockaddr_in*)res->ai_addr; + ret= htonl(a->sin_addr.s_addr); + } + else /* IPv6 */ + { + struct sockaddr_in6* a= (struct sockaddr_in6*)res->ai_addr; + if (IN6_IS_ADDR_UNSPECIFIED(&a->sin6_addr)) + ret= INADDR_ANY; + else if (IN6_IS_ADDR_LOOPBACK(&a->sin6_addr)) + ret= INADDR_LOOPBACK; + else + ret= 0xdeadbeef; + } + freeaddrinfo (res); + } + else { + WSREP_ERROR ("getaddrinfo() failed on '%s': %d (%s)", + addr, gai_ret, gai_strerror(gai_ret)); + } + + // uint8_t* b= (uint8_t*)&ret; + // fprintf (stderr, "########## wsrep_check_ip returning: %hhu.%hhu.%hhu.%hhu\n", + // b[0], b[1], b[2], b[3]); + + return ret; +} + +extern char* my_bind_addr_str; + +size_t wsrep_guess_ip (char* buf, size_t buf_len) +{ + size_t ip_len = 0; + + if (my_bind_addr_str && strlen(my_bind_addr_str)) + { + unsigned int const ip_type= wsrep_check_ip(my_bind_addr_str); + + if (INADDR_NONE == ip_type) { + WSREP_ERROR("Networking not configured, cannot receive state transfer."); + return 0; + } + + if (INADDR_ANY != ip_type) {; + strncpy (buf, my_bind_addr_str, buf_len); + return strlen(buf); + } + } + + // mysqld binds to all interfaces - try IP from wsrep_node_address + if (wsrep_node_address && wsrep_node_address[0] != '\0') { + const char* const colon_ptr = strchr(wsrep_node_address, ':'); + + if (colon_ptr) + ip_len = colon_ptr - wsrep_node_address; + else + ip_len = strlen(wsrep_node_address); + + if (ip_len >= buf_len) { + WSREP_WARN("default_ip(): buffer too short: %zu <= %zd", buf_len, ip_len); + return 0; + } + + memcpy (buf, wsrep_node_address, ip_len); + buf[ip_len] = '\0'; + return ip_len; + } + + // try to find the address of the first one +#if (TARGET_OS_LINUX == 1) + const char cmd[] = "/sbin/ifconfig | " +// "grep -m1 -1 -E '^[a-z]?eth[0-9]' | tail -n 1 | " + "grep -E '^[[:space:]]+inet addr:' | grep -m1 -v 'inet addr:127' | " + "sed 's/:/ /' | awk '{ print $3 }'"; +#elif defined(__sun__) + const char cmd[] = "/sbin/ifconfig -a | " + "/usr/gnu/bin/grep -m1 -1 -E 'net[0-9]:' | tail -n 1 | awk '{ print $2 }'"; +#elif defined(__APPLE__) || defined(__FreeBSD__) + const char cmd[] = "/sbin/route -nv get 8.8.8.8 | tail -n1 | awk '{print $(NF)}'"; +#else + char *cmd; +#error "OS not supported" +#endif + wsp::process proc (cmd, "r"); + + if (NULL != proc.pipe()) { + char* ret; + + ret = fgets (buf, buf_len, proc.pipe()); + + if (proc.wait()) return 0; + + if (NULL == ret) { + WSREP_ERROR("Failed to read output of: '%s'", cmd); + return 0; + } + } + else { + WSREP_ERROR("Failed to execute: '%s'", cmd); + return 0; + } + + // clear possible \n at the end of ip string left by fgets() + ip_len = strlen (buf); + if (ip_len > 0 && '\n' == buf[ip_len - 1]) { + ip_len--; + buf[ip_len] = '\0'; + } + + if (INADDR_NONE == inet_addr(buf)) { + if (strlen(buf) != 0) { + WSREP_WARN("Shell command returned invalid address: '%s'", buf); + } + return 0; + } + + return ip_len; +} + +size_t wsrep_guess_address(char* buf, size_t buf_len) +{ + size_t addr_len = wsrep_guess_ip (buf, buf_len); + + if (addr_len && addr_len < buf_len) { + addr_len += snprintf (buf + addr_len, buf_len - addr_len, + ":%u", mysqld_port); + } + + return addr_len; +} + +/* + * WSREPXid + */ + +#define WSREP_XID_PREFIX "WSREPXid" +#define WSREP_XID_PREFIX_LEN MYSQL_XID_PREFIX_LEN +#define WSREP_XID_UUID_OFFSET 8 +#define WSREP_XID_SEQNO_OFFSET (WSREP_XID_UUID_OFFSET + sizeof(wsrep_uuid_t)) +#define WSREP_XID_GTRID_LEN (WSREP_XID_SEQNO_OFFSET + sizeof(wsrep_seqno_t)) + +void wsrep_xid_init(XID* xid, const wsrep_uuid_t* uuid, wsrep_seqno_t seqno) +{ + xid->formatID= 1; + xid->gtrid_length= WSREP_XID_GTRID_LEN; + xid->bqual_length= 0; + memset(xid->data, 0, sizeof(xid->data)); + memcpy(xid->data, WSREP_XID_PREFIX, WSREP_XID_PREFIX_LEN); + memcpy(xid->data + WSREP_XID_UUID_OFFSET, uuid, sizeof(wsrep_uuid_t)); + memcpy(xid->data + WSREP_XID_SEQNO_OFFSET, &seqno, sizeof(wsrep_seqno_t)); +} + +const wsrep_uuid_t* wsrep_xid_uuid(const XID* xid) +{ + if (wsrep_is_wsrep_xid(xid)) + return reinterpret_cast(xid->data + + WSREP_XID_UUID_OFFSET); + else + return &WSREP_UUID_UNDEFINED; +} + +wsrep_seqno_t wsrep_xid_seqno(const XID* xid) +{ + + if (wsrep_is_wsrep_xid(xid)) + { + wsrep_seqno_t seqno; + memcpy(&seqno, xid->data + WSREP_XID_SEQNO_OFFSET, sizeof(wsrep_seqno_t)); + return seqno; + } + else + { + return WSREP_SEQNO_UNDEFINED; + } +} + +extern +int wsrep_is_wsrep_xid(const void* xid_ptr) +{ + const XID* xid= reinterpret_cast(xid_ptr); + return (xid->formatID == 1 && + xid->gtrid_length == WSREP_XID_GTRID_LEN && + xid->bqual_length == 0 && + !memcmp(xid->data, WSREP_XID_PREFIX, WSREP_XID_PREFIX_LEN)); +} diff --git a/sql/wsrep_utils.h b/sql/wsrep_utils.h new file mode 100644 index 00000000000..337678238f8 --- /dev/null +++ b/sql/wsrep_utils.h @@ -0,0 +1,208 @@ +/* Copyright (C) 2013 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + +#ifndef WSREP_UTILS_H +#define WSREP_UTILS_H + +#include "wsrep_priv.h" + +unsigned int wsrep_check_ip (const char* addr); +size_t wsrep_guess_ip (char* buf, size_t buf_len); +size_t wsrep_guess_address(char* buf, size_t buf_len); + +namespace wsp { +class node_status +{ +public: + node_status() : status(WSREP_MEMBER_UNDEFINED) {} + void set(wsrep_member_status_t new_status, + const wsrep_view_info_t* view = 0) + { + if (status != new_status || 0 != view) + { + wsrep_notify_status(new_status, view); + status = new_status; + } + } + wsrep_member_status_t get() const { return status; } +private: + wsrep_member_status_t status; +}; +} /* namespace wsp */ + +extern wsp::node_status local_status; + +namespace wsp { +/* A small class to run external programs. */ +class process +{ +private: + const char* const str_; + FILE* io_; + int err_; + pid_t pid_; + +public: +/*! @arg type is a pointer to a null-terminated string which must contain + either the letter 'r' for reading or the letter 'w' for writing. + */ + process (const char* cmd, const char* type); + ~process (); + + FILE* pipe () { return io_; } + int error() { return err_; } + int wait (); + const char* cmd() { return str_; } +}; + +class thd +{ + class thd_init + { + public: + thd_init() { my_thread_init(); } + ~thd_init() { my_thread_end(); } + } + init; + + thd (const thd&); + thd& operator= (const thd&); + +public: + + thd(my_bool wsrep_on); + ~thd(); + THD* const ptr; +}; + +class string +{ +public: + string() : string_(0) {} + void set(char* str) { if (string_) free (string_); string_ = str; } + ~string() { set (0); } +private: + char* string_; +}; + +#ifdef REMOVED +class lock +{ + pthread_mutex_t* const mtx_; + +public: + + lock (pthread_mutex_t* mtx) : mtx_(mtx) + { + int err = pthread_mutex_lock (mtx_); + + if (err) + { + WSREP_ERROR("Mutex lock failed: %s", strerror(err)); + abort(); + } + } + + virtual ~lock () + { + int err = pthread_mutex_unlock (mtx_); + + if (err) + { + WSREP_ERROR("Mutex unlock failed: %s", strerror(err)); + abort(); + } + } + + inline void wait (pthread_cond_t* cond) + { + pthread_cond_wait (cond, mtx_); + } + +private: + + lock (const lock&); + lock& operator=(const lock&); + +}; + +class monitor +{ + int mutable refcnt; + pthread_mutex_t mutable mtx; + pthread_cond_t mutable cond; + +public: + + monitor() : refcnt(0) + { + pthread_mutex_init (&mtx, NULL); + pthread_cond_init (&cond, NULL); + } + + ~monitor() + { + pthread_mutex_destroy (&mtx); + pthread_cond_destroy (&cond); + } + + void enter() const + { + lock l(&mtx); + + while (refcnt) + { + l.wait(&cond); + } + refcnt++; + } + + void leave() const + { + lock l(&mtx); + + refcnt--; + if (refcnt == 0) + { + pthread_cond_signal (&cond); + } + } + +private: + + monitor (const monitor&); + monitor& operator= (const monitor&); +}; + +class critical +{ + const monitor& mon; + +public: + + critical(const monitor& m) : mon(m) { mon.enter(); } + + ~critical() { mon.leave(); } + +private: + + critical (const critical&); + critical& operator= (const critical&); +}; +#endif + +} // namespace wsrep + +#endif /* WSREP_UTILS_H */ diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc new file mode 100644 index 00000000000..b965c26c184 --- /dev/null +++ b/sql/wsrep_var.cc @@ -0,0 +1,584 @@ +/* Copyright 2008 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "wsrep_var.h" + +#include +#include +#include +#include +#include +#include "wsrep_priv.h" +#include "wsrep_thd.h" +#include +#include +#include + +const char* wsrep_provider = 0; +const char* wsrep_provider_options = 0; +const char* wsrep_cluster_address = 0; +const char* wsrep_cluster_name = 0; +const char* wsrep_node_name = 0; +const char* wsrep_node_address = 0; +const char* wsrep_node_incoming_address = 0; +const char* wsrep_start_position = 0; +ulong wsrep_OSU_method_options; + +int wsrep_init_vars() +{ + wsrep_provider = my_strdup(WSREP_NONE, MYF(MY_WME)); + wsrep_provider_options= my_strdup("", MYF(MY_WME)); + wsrep_cluster_address = my_strdup("", MYF(MY_WME)); + wsrep_cluster_name = my_strdup(WSREP_CLUSTER_NAME, MYF(MY_WME)); + wsrep_node_name = my_strdup("", MYF(MY_WME)); + wsrep_node_address = my_strdup("", MYF(MY_WME)); + wsrep_node_incoming_address= my_strdup(WSREP_NODE_INCOMING_AUTO, MYF(MY_WME)); + wsrep_start_position = my_strdup(WSREP_START_POSITION_ZERO, MYF(MY_WME)); + + global_system_variables.binlog_format=BINLOG_FORMAT_ROW; + return 0; +} + +bool wsrep_on_update (sys_var *self, THD* thd, enum_var_type var_type) +{ + if (var_type == OPT_GLOBAL) { + // FIXME: this variable probably should be changed only per session + thd->variables.wsrep_on = global_system_variables.wsrep_on; + } + return false; +} + +void wsrep_causal_reads_update (sys_var *self, THD* thd, enum_var_type var_type) +{ + if (var_type == OPT_GLOBAL) { + thd->variables.wsrep_causal_reads = global_system_variables.wsrep_causal_reads; + } +} + +static int wsrep_start_position_verify (const char* start_str) +{ + size_t start_len; + wsrep_uuid_t uuid; + ssize_t uuid_len; + + start_len = strlen (start_str); + if (start_len < 34) + return 1; + + uuid_len = wsrep_uuid_scan (start_str, start_len, &uuid); + if (uuid_len < 0 || (start_len - uuid_len) < 2) + return 1; + + if (start_str[uuid_len] != ':') // separator should follow UUID + return 1; + + char* endptr; + wsrep_seqno_t const seqno __attribute__((unused)) // to avoid GCC warnings + (strtoll(&start_str[uuid_len + 1], &endptr, 10)); + + if (*endptr == '\0') return 0; // remaining string was seqno + + return 1; +} + +bool wsrep_start_position_check (sys_var *self, THD* thd, set_var* var) +{ + char start_pos_buf[FN_REFLEN]; + + if ((! var->save_result.string_value.str) || + (var->save_result.string_value.length > (FN_REFLEN - 1))) // safety + goto err; + + memcpy(start_pos_buf, var->save_result.string_value.str, + var->save_result.string_value.length); + start_pos_buf[var->save_result.string_value.length]= 0; + + if (!wsrep_start_position_verify(start_pos_buf)) return 0; + +err: + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, + var->save_result.string_value.str ? + var->save_result.string_value.str : "NULL"); + return 1; +} + +void wsrep_set_local_position (const char* value) +{ + size_t value_len = strlen (value); + size_t uuid_len = wsrep_uuid_scan (value, value_len, &local_uuid); + + local_seqno = strtoll (value + uuid_len + 1, NULL, 10); + + XID xid; + wsrep_xid_init(&xid, &local_uuid, local_seqno); + wsrep_set_SE_checkpoint(&xid); + WSREP_INFO ("wsrep_start_position var submitted: '%s'", wsrep_start_position); +} + +bool wsrep_start_position_update (sys_var *self, THD* thd, enum_var_type type) +{ + // since this value passed wsrep_start_position_check, don't check anything + // here + wsrep_set_local_position (wsrep_start_position); + + if (wsrep) { + wsrep_sst_received (wsrep, &local_uuid, local_seqno, NULL, 0); + } + + return 0; +} + +void wsrep_start_position_init (const char* val) +{ + if (NULL == val || wsrep_start_position_verify (val)) + { + WSREP_ERROR("Bad initial value for wsrep_start_position: %s", + (val ? val : "")); + return; + } + + wsrep_set_local_position (val); +} + +static bool refresh_provider_options() +{ + WSREP_DEBUG("refresh_provider_options: %s", + (wsrep_provider_options) ? wsrep_provider_options : "null"); + char* opts= wsrep->options_get(wsrep); + if (opts) + { + if (wsrep_provider_options) my_free((void *)wsrep_provider_options); + wsrep_provider_options = (char*)my_memdup(opts, strlen(opts) + 1, + MYF(MY_WME)); + } + else + { + WSREP_ERROR("Failed to get provider options"); + return true; + } + return false; +} + +static int wsrep_provider_verify (const char* provider_str) +{ + MY_STAT f_stat; + char path[FN_REFLEN]; + + if (!provider_str || strlen(provider_str)== 0) + return 1; + + if (!strcmp(provider_str, WSREP_NONE)) + return 0; + + if (!unpack_filename(path, provider_str)) + return 1; + + /* check that provider file exists */ + bzero(&f_stat, sizeof(MY_STAT)); + if (!my_stat(path, &f_stat, MYF(0))) + { + return 1; + } + return 0; +} + +bool wsrep_provider_check (sys_var *self, THD* thd, set_var* var) +{ + char wsrep_provider_buf[FN_REFLEN]; + + if ((! var->save_result.string_value.str) || + (var->save_result.string_value.length > (FN_REFLEN - 1))) // safety + goto err; + + memcpy(wsrep_provider_buf, var->save_result.string_value.str, + var->save_result.string_value.length); + wsrep_provider_buf[var->save_result.string_value.length]= 0; + + if (!wsrep_provider_verify(wsrep_provider_buf)) return 0; + +err: + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, + var->save_result.string_value.str ? + var->save_result.string_value.str : "NULL"); + return 1; +} + +bool wsrep_provider_update (sys_var *self, THD* thd, enum_var_type type) +{ + bool rcode= false; + + bool wsrep_on_saved= thd->variables.wsrep_on; + thd->variables.wsrep_on= false; + + WSREP_DEBUG("wsrep_provider_update: %s", wsrep_provider); + + /* stop replication is heavy operation, and includes closing all client + connections. Closing clients may need to get LOCK_global_system_variables + at least in MariaDB. + + Note: releasing LOCK_global_system_variables may cause race condition, if + there can be several concurrent clients changing wsrep_provider + */ + mysql_mutex_unlock(&LOCK_global_system_variables); + wsrep_stop_replication(thd); + mysql_mutex_lock(&LOCK_global_system_variables); + + if (wsrep_inited == 1) + wsrep_deinit(false); + + char* tmp= strdup(wsrep_provider); // wsrep_init() rewrites provider + //when fails + if (wsrep_init()) + { + my_error(ER_CANT_OPEN_LIBRARY, MYF(0), tmp); + rcode = true; + } + free(tmp); + + // we sure don't want to use old address with new provider + wsrep_cluster_address_init(NULL); + wsrep_provider_options_init(NULL); + + thd->variables.wsrep_on= wsrep_on_saved; + + refresh_provider_options(); + + return rcode; +} + +void wsrep_provider_init (const char* value) +{ + WSREP_DEBUG("wsrep_provider_init: %s -> %s", + (wsrep_provider) ? wsrep_provider : "null", + (value) ? value : "null"); + if (NULL == value || wsrep_provider_verify (value)) + { + WSREP_ERROR("Bad initial value for wsrep_provider: %s", + (value ? value : "")); + return; + } + + if (wsrep_provider) my_free((void *)wsrep_provider); + wsrep_provider = my_strdup(value, MYF(0)); +} + +bool wsrep_provider_options_check(sys_var *self, THD* thd, set_var* var) +{ + return 0; +} + +bool wsrep_provider_options_update(sys_var *self, THD* thd, enum_var_type type) +{ + wsrep_status_t ret= wsrep->options_set(wsrep, wsrep_provider_options); + if (ret != WSREP_OK) + { + WSREP_ERROR("Set options returned %d", ret); + refresh_provider_options(); + return true; + } + return refresh_provider_options(); +} + +void wsrep_provider_options_init(const char* value) +{ + if (wsrep_provider_options && wsrep_provider_options != value) + my_free((void *)wsrep_provider_options); + wsrep_provider_options = (value) ? my_strdup(value, MYF(0)) : NULL; +} + +static int wsrep_cluster_address_verify (const char* cluster_address_str) +{ + /* There is no predefined address format, it depends on provider. */ + return 0; +} + +bool wsrep_cluster_address_check (sys_var *self, THD* thd, set_var* var) +{ + char addr_buf[FN_REFLEN]; + + if ((! var->save_result.string_value.str) || + (var->save_result.string_value.length > (FN_REFLEN - 1))) // safety + goto err; + + memcpy(addr_buf, var->save_result.string_value.str, + var->save_result.string_value.length); + addr_buf[var->save_result.string_value.length]= 0; + + if (!wsrep_cluster_address_verify(addr_buf)) return 0; + + err: + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, + var->save_result.string_value.str ? + var->save_result.string_value.str : "NULL"); + return 1; +} + +bool wsrep_cluster_address_update (sys_var *self, THD* thd, enum_var_type type) +{ + bool wsrep_on_saved= thd->variables.wsrep_on; + thd->variables.wsrep_on= false; + + /* stop replication is heavy operation, and includes closing all client + connections. Closing clients may need to get LOCK_global_system_variables + at least in MariaDB. + + Note: releasing LOCK_global_system_variables may cause race condition, if + there can be several concurrent clients changing wsrep_provider + */ + mysql_mutex_unlock(&LOCK_global_system_variables); + wsrep_stop_replication(thd); + mysql_mutex_lock(&LOCK_global_system_variables); + + if (wsrep_start_replication()) + { + wsrep_create_rollbacker(); + wsrep_create_appliers(wsrep_slave_threads); + } + + thd->variables.wsrep_on= wsrep_on_saved; + + return false; +} + +void wsrep_cluster_address_init (const char* value) +{ + WSREP_DEBUG("wsrep_cluster_address_init: %s -> %s", + (wsrep_cluster_address) ? wsrep_cluster_address : "null", + (value) ? value : "null"); + + if (wsrep_cluster_address) my_free ((void*)wsrep_cluster_address); + wsrep_cluster_address = (value) ? my_strdup(value, MYF(0)) : NULL; +} + +/* wsrep_cluster_name cannot be NULL or an empty string. */ +bool wsrep_cluster_name_check (sys_var *self, THD* thd, set_var* var) +{ + if (!var->save_result.string_value.str || + (var->save_result.string_value.length == 0)) + { + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, + (var->save_result.string_value.str ? + var->save_result.string_value.str : "NULL")); + return 1; + } + return 0; +} + +bool wsrep_cluster_name_update (sys_var *self, THD* thd, enum_var_type type) +{ + return 0; +} + +bool wsrep_node_name_check (sys_var *self, THD* thd, set_var* var) +{ + // TODO: for now 'allow' 0-length string to be valid (default) + if (!var->save_result.string_value.str) + { + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, + (var->save_result.string_value.str ? + var->save_result.string_value.str : "NULL")); + return 1; + } + return 0; +} + +bool wsrep_node_name_update (sys_var *self, THD* thd, enum_var_type type) +{ + return 0; +} + +// TODO: do something more elaborate, like checking connectivity +bool wsrep_node_address_check (sys_var *self, THD* thd, set_var* var) +{ + char addr_buf[FN_REFLEN]; + + if ((! var->save_result.string_value.str) || + (var->save_result.string_value.length > (FN_REFLEN - 1))) // safety + goto err; + + memcpy(addr_buf, var->save_result.string_value.str, + var->save_result.string_value.length); + addr_buf[var->save_result.string_value.length]= 0; + + // TODO: for now 'allow' 0-length string to be valid (default) + return 0; + +err: + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, + var->save_result.string_value.str ? + var->save_result.string_value.str : "NULL"); + return 1; +} + +bool wsrep_node_address_update (sys_var *self, THD* thd, enum_var_type type) +{ + return 0; +} + +void wsrep_node_address_init (const char* value) +{ + if (wsrep_node_address && strcmp(wsrep_node_address, value)) + my_free ((void*)wsrep_node_address); + + wsrep_node_address = (value) ? my_strdup(value, MYF(0)) : NULL; +} + +bool wsrep_slave_threads_check (sys_var *self, THD* thd, set_var* var) +{ + mysql_mutex_lock(&LOCK_wsrep_slave_threads); + wsrep_slave_count_change += (var->save_result.ulonglong_value - + wsrep_slave_threads); + mysql_mutex_unlock(&LOCK_wsrep_slave_threads); + + return 0; +} + +bool wsrep_slave_threads_update (sys_var *self, THD* thd, enum_var_type type) +{ + if (wsrep_slave_count_change > 0) + { + wsrep_create_appliers(wsrep_slave_count_change); + wsrep_slave_count_change = 0; + } + return false; +} + +bool wsrep_desync_check (sys_var *self, THD* thd, set_var* var) +{ + bool new_wsrep_desync= (bool) var->save_result.ulonglong_value; + if (wsrep_desync == new_wsrep_desync) { + if (new_wsrep_desync) { + push_warning (thd, Sql_condition::WARN_LEVEL_WARN, + ER_WRONG_VALUE_FOR_VAR, + "'wsrep_desync' is already ON."); + } else { + push_warning (thd, Sql_condition::WARN_LEVEL_WARN, + ER_WRONG_VALUE_FOR_VAR, + "'wsrep_desync' is already OFF."); + } + } + return 0; +} + +bool wsrep_desync_update (sys_var *self, THD* thd, enum_var_type type) +{ + wsrep_status_t ret(WSREP_WARNING); + if (wsrep_desync) { + ret = wsrep->desync (wsrep); + if (ret != WSREP_OK) { + WSREP_WARN ("SET desync failed %d for %s", ret, thd->query()); + my_error (ER_CANNOT_USER, MYF(0), "'desync'", thd->query()); + return true; + } + } else { + ret = wsrep->resync (wsrep); + if (ret != WSREP_OK) { + WSREP_WARN ("SET resync failed %d for %s", ret, thd->query()); + my_error (ER_CANNOT_USER, MYF(0), "'resync'", thd->query()); + return true; + } + } + return false; +} + +/* + * Status variables stuff below + */ +static inline void +wsrep_assign_to_mysql (SHOW_VAR* mysql, wsrep_stats_var* wsrep) +{ + mysql->name = wsrep->name; + switch (wsrep->type) { + case WSREP_VAR_INT64: + mysql->value = (char*) &wsrep->value._int64; + mysql->type = SHOW_LONGLONG; + break; + case WSREP_VAR_STRING: + mysql->value = (char*) &wsrep->value._string; + mysql->type = SHOW_CHAR_PTR; + break; + case WSREP_VAR_DOUBLE: + mysql->value = (char*) &wsrep->value._double; + mysql->type = SHOW_DOUBLE; + break; + } +} + +#if DYNAMIC +// somehow this mysql status thing works only with statically allocated arrays. +static SHOW_VAR* mysql_status_vars = NULL; +static int mysql_status_len = -1; +#else +static SHOW_VAR mysql_status_vars[512 + 1]; +static const int mysql_status_len = 512; +#endif + +static void export_wsrep_status_to_mysql(THD* thd) +{ + int wsrep_status_len, i; + + thd->wsrep_status_vars = wsrep->stats_get(wsrep); + + if (!thd->wsrep_status_vars) { + return; + } + + for (wsrep_status_len = 0; + thd->wsrep_status_vars[wsrep_status_len].name != NULL; + wsrep_status_len++); + +#if DYNAMIC + if (wsrep_status_len != mysql_status_len) { + void* tmp = realloc (mysql_status_vars, + (wsrep_status_len + 1) * sizeof(SHOW_VAR)); + if (!tmp) { + + sql_print_error ("Out of memory for wsrep status variables." + "Number of variables: %d", wsrep_status_len); + return; + } + + mysql_status_len = wsrep_status_len; + mysql_status_vars = (SHOW_VAR*)tmp; + } + /* @TODO: fix this: */ +#else + if (mysql_status_len < wsrep_status_len) wsrep_status_len= mysql_status_len; +#endif + + for (i = 0; i < wsrep_status_len; i++) + wsrep_assign_to_mysql (mysql_status_vars + i, thd->wsrep_status_vars + i); + + mysql_status_vars[wsrep_status_len].name = NullS; + mysql_status_vars[wsrep_status_len].value = NullS; + mysql_status_vars[wsrep_status_len].type = SHOW_LONG; +} + +int wsrep_show_status (THD *thd, SHOW_VAR *var, char *buff) +{ + export_wsrep_status_to_mysql(thd); + var->type= SHOW_ARRAY; + var->value= (char *) &mysql_status_vars; + return 0; +} + +void wsrep_free_status (THD* thd) +{ + if (thd->wsrep_status_vars) + { + wsrep->stats_free (wsrep, thd->wsrep_status_vars); + thd->wsrep_status_vars = 0; + } +} diff --git a/sql/wsrep_var.h b/sql/wsrep_var.h new file mode 100644 index 00000000000..2a5e94b6724 --- /dev/null +++ b/sql/wsrep_var.h @@ -0,0 +1,85 @@ +/* Copyright (C) 2013 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + +#ifndef WSREP_VAR_H +#define WSREP_VAR_H + +#define WSREP_CLUSTER_NAME "my_wsrep_cluster" +#define WSREP_NODE_INCOMING_AUTO "AUTO" +#define WSREP_START_POSITION_ZERO "00000000-0000-0000-0000-000000000000:-1" + +// MySQL variables funcs + +#include "sql_priv.h" +class sys_var; +class set_var; +class THD; + +int wsrep_init_vars(); + +#define CHECK_ARGS (sys_var *self, THD* thd, set_var *var) +#define UPDATE_ARGS (sys_var *self, THD* thd, enum_var_type type) +#define DEFAULT_ARGS (THD* thd, enum_var_type var_type) +#define INIT_ARGS (const char* opt) + +extern bool wsrep_on_update UPDATE_ARGS; +extern void wsrep_causal_reads_update UPDATE_ARGS; +extern bool wsrep_start_position_check CHECK_ARGS; +extern bool wsrep_start_position_update UPDATE_ARGS; +extern void wsrep_start_position_init INIT_ARGS; + +extern bool wsrep_provider_check CHECK_ARGS; +extern bool wsrep_provider_update UPDATE_ARGS; +extern void wsrep_provider_init INIT_ARGS; + +extern bool wsrep_provider_options_check CHECK_ARGS; +extern bool wsrep_provider_options_update UPDATE_ARGS; +extern void wsrep_provider_options_init INIT_ARGS; + +extern bool wsrep_cluster_address_check CHECK_ARGS; +extern bool wsrep_cluster_address_update UPDATE_ARGS; +extern void wsrep_cluster_address_init INIT_ARGS; + +extern bool wsrep_cluster_name_check CHECK_ARGS; +extern bool wsrep_cluster_name_update UPDATE_ARGS; + +extern bool wsrep_node_name_check CHECK_ARGS; +extern bool wsrep_node_name_update UPDATE_ARGS; + +extern bool wsrep_node_address_check CHECK_ARGS; +extern bool wsrep_node_address_update UPDATE_ARGS; +extern void wsrep_node_address_init INIT_ARGS; + +extern bool wsrep_sst_method_check CHECK_ARGS; +extern bool wsrep_sst_method_update UPDATE_ARGS; +extern void wsrep_sst_method_init INIT_ARGS; + +extern bool wsrep_sst_receive_address_check CHECK_ARGS; +extern bool wsrep_sst_receive_address_update UPDATE_ARGS; + +extern bool wsrep_sst_auth_check CHECK_ARGS; +extern bool wsrep_sst_auth_update UPDATE_ARGS; +extern void wsrep_sst_auth_init INIT_ARGS; + +extern bool wsrep_sst_donor_check CHECK_ARGS; +extern bool wsrep_sst_donor_update UPDATE_ARGS; + +extern bool wsrep_slave_threads_check CHECK_ARGS; +extern bool wsrep_slave_threads_update UPDATE_ARGS; + +extern bool wsrep_desync_check CHECK_ARGS; +extern bool wsrep_desync_update UPDATE_ARGS; + +#endif /* WSREP_VAR_H */ diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt index 622fff87536..12d43bba5bc 100644 --- a/storage/innobase/CMakeLists.txt +++ b/storage/innobase/CMakeLists.txt @@ -251,6 +251,27 @@ ENDIF() INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/storage/innobase/include ${CMAKE_SOURCE_DIR}/storage/innobase/handler) +IF(WITH_WSREP) + # ssl include directory + INCLUDE_DIRECTORIES(${SSL_INCLUDE_DIRS} + ${CMAKE_SOURCE_DIR}/storage/innobase/wsrep) + + IF(SSL_DEFINES) + ADD_DEFINITIONS(${SSL_DEFINES}) + ENDIF() + + LINK_LIBRARIES(${SSL_LIBRARIES}) + + # We do RESTRICT_SYMBOL_EXPORTS(yassl) elsewhere. + # In order to get correct symbol visibility, these files + # must be compiled with "-fvisibility=hidden" + IF(WITH_SSL STREQUAL "bundled" AND HAVE_VISIBILITY_HIDDEN) + SET_SOURCE_FILES_PROPERTIES( + {CMAKE_CURRENT_SOURCE_DIR}/wsrep/md5.cc + PROPERTIES COMPILE_FLAGS "-fvisibility=hidden") + ENDIF() +ENDIF() + # Sun Studio bug with -xO2 IF(CMAKE_CXX_COMPILER_ID MATCHES "SunPro" AND CMAKE_CXX_FLAGS_RELEASE MATCHES "O2" @@ -397,6 +418,10 @@ SET(INNOBASE_SOURCES ut/ut0vec.cc ut/ut0wqueue.cc) +IF(WITH_WSREP) + SET(INNOBASE_SOURCES ${INNOBASE_SOURCES} wsrep/md5.cc) +ENDIF() + IF(WITH_INNODB) # Legacy option SET(WITH_INNOBASE_STORAGE_ENGINE TRUE) diff --git a/storage/innobase/buf/buf0rea.cc b/storage/innobase/buf/buf0rea.cc index ec76c9923fe..9e81d010d0f 100644 --- a/storage/innobase/buf/buf0rea.cc +++ b/storage/innobase/buf/buf0rea.cc @@ -1,7 +1,6 @@ /***************************************************************************** Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2013, 2014, SkySQL Ab. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -185,14 +184,15 @@ buf_read_page_low( *err = fil_io(OS_FILE_READ | wake_later | ignore_nonexistent_pages, sync, space, zip_size, offset, 0, zip_size, - bpage->zip.data, bpage, &bpage->write_size); + bpage->zip.data, bpage, &bpage->write_size); } else { ut_a(buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE); *err = fil_io(OS_FILE_READ | wake_later | ignore_nonexistent_pages, sync, space, 0, offset, 0, UNIV_PAGE_SIZE, - ((buf_block_t*) bpage)->frame, bpage, 0); + ((buf_block_t*) bpage)->frame, bpage, + &bpage->write_size); } if (sync) { diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 0c83089478a..72a0f39e19e 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -3237,7 +3237,29 @@ dict_foreign_find_index( return(NULL); } - +#ifdef WITH_WSREP +dict_index_t* +wsrep_dict_foreign_find_index( +/*====================*/ + dict_table_t* table, /*!< in: table */ + const char** col_names, /*!< in: column names, or NULL + to use table->col_names */ + const char** columns,/*!< in: array of column names */ + ulint n_cols, /*!< in: number of columns */ + dict_index_t* types_idx, /*!< in: NULL or an index to whose types the + column types must match */ + ibool check_charsets, + /*!< in: whether to check charsets. + only has an effect if types_idx != NULL */ + ulint check_null) + /*!< in: nonzero if none of the columns must + be declared NOT NULL */ +{ + return dict_foreign_find_index( + table, col_names, columns, n_cols, types_idx, check_charsets, + check_null); +} +#endif /* WITH_WSREP */ /**********************************************************************//** Report an error in a foreign key definition. */ static diff --git a/storage/innobase/fil/fil0pagecompress.cc b/storage/innobase/fil/fil0pagecompress.cc index a81a982db6c..f324631dff1 100644 --- a/storage/innobase/fil/fil0pagecompress.cc +++ b/storage/innobase/fil/fil0pagecompress.cc @@ -490,7 +490,9 @@ fil_decompress_page( ulint actual_size = 0; ulint compression_alg = 0; byte *in_buf; +#ifdef HAVE_LZO ulint olen=0; +#endif ulint ptype; ut_ad(buf); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index ead86fd3085..ed562f5172d 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -117,6 +117,46 @@ this program; if not, write to the Free Software Foundation, Inc., # define MYSQL_PLUGIN_IMPORT /* nothing */ # endif /* MYSQL_PLUGIN_IMPORT */ +#ifdef WITH_WSREP +#include "dict0priv.h" +#include "../storage/innobase/include/ut0byte.h" +#include +#include + +extern my_bool wsrep_certify_nonPK; +class binlog_trx_data; +extern handlerton *binlog_hton; + +extern MYSQL_PLUGIN_IMPORT MYSQL_BIN_LOG mysql_bin_log; +extern MYSQL_PLUGIN_IMPORT mysql_mutex_t LOCK_wsrep_rollback; +extern MYSQL_PLUGIN_IMPORT mysql_cond_t COND_wsrep_rollback; +extern MYSQL_PLUGIN_IMPORT wsrep_aborting_thd_t wsrep_aborting_thd; + +static inline wsrep_ws_handle_t* +wsrep_ws_handle(THD* thd, const trx_t* trx) { + return wsrep_ws_handle_for_trx(wsrep_thd_ws_handle(thd), + (wsrep_trx_id_t)trx->id); +} + +extern bool wsrep_prepare_key_for_innodb(const uchar *cache_key, + size_t cache_key_len, + const uchar* row_id, + size_t row_id_len, + wsrep_buf_t* key, + size_t* key_len); + +extern handlerton * wsrep_hton; +extern TC_LOG* tc_log; +extern void wsrep_cleanup_transaction(THD *thd); +static int +wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd, + my_bool signal); +static void +wsrep_fake_trx_id(handlerton* hton, THD *thd); +static int innobase_wsrep_set_checkpoint(handlerton* hton, const XID* xid); +static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid); +#endif /* WITH_WSREP */ + /** to protect innobase_open_files */ static mysql_mutex_t innobase_share_mutex; /** to force correct commit order in binlog */ @@ -1253,6 +1293,10 @@ innobase_srv_conc_enter_innodb( /*===========================*/ trx_t* trx) /*!< in: transaction handle */ { +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd) && + wsrep_thd_is_BF(trx->mysql_thd, FALSE)) return; +#endif /* WITH_WSREP */ if (srv_thread_concurrency) { if (trx->n_tickets_to_enter_innodb > 0) { @@ -1287,6 +1331,10 @@ innobase_srv_conc_exit_innodb( #ifdef UNIV_SYNC_DEBUG ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch)); #endif /* UNIV_SYNC_DEBUG */ +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd) && + wsrep_thd_is_BF(trx->mysql_thd, FALSE)) return; +#endif /* WITH_WSREP */ /* This is to avoid making an unnecessary function call. */ if (trx->declared_to_be_inside_innodb @@ -1407,6 +1455,15 @@ thd_to_trx( { return(*(trx_t**) thd_ha_data(thd, innodb_hton_ptr)); } +#ifdef WITH_WSREP +ulonglong +thd_to_trx_id( +/*=======*/ + THD* thd) /*!< in: MySQL thread */ +{ + return(thd_to_trx(thd)->id); +} +#endif /* WITH_WSREP */ /********************************************************************//** Call this function when mysqld passes control to the client. That is to @@ -1892,6 +1949,9 @@ int innobase_mysql_tmpfile(void) /*========================*/ { +#ifdef WITH_INNODB_DISALLOW_WRITES + os_event_wait(srv_allow_writes_event); +#endif /* WITH_INNODB_DISALLOW_WRITES */ int fd2 = -1; File fd; @@ -2957,6 +3017,12 @@ innobase_init( innobase_hton->release_temporary_latches = innobase_release_temporary_latches; +#ifdef WITH_WSREP + innobase_hton->wsrep_abort_transaction=wsrep_abort_transaction; + innobase_hton->wsrep_set_checkpoint=innobase_wsrep_set_checkpoint; + innobase_hton->wsrep_get_checkpoint=innobase_wsrep_get_checkpoint; + innobase_hton->wsrep_fake_trx_id=wsrep_fake_trx_id; +#endif /* WITH_WSREP */ innobase_hton->kill_query = innobase_kill_query; if (srv_file_per_table) @@ -3615,10 +3681,30 @@ innobase_commit_low( /*================*/ trx_t* trx) /*!< in: transaction handle */ { +#ifdef WITH_WSREP + THD* thd = (THD*)trx->mysql_thd; + const char* tmp = 0; + if (wsrep_on((void*)thd)) { +#ifdef WSREP_PROC_INFO + char info[64]; + info[sizeof(info) - 1] = '\0'; + snprintf(info, sizeof(info) - 1, + "innobase_commit_low():trx_commit_for_mysql(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); + tmp = thd_proc_info(thd, info); + +#else + tmp = thd_proc_info(thd, "innobase_commit_low()"); +#endif /* WSREP_PROC_INFO */ + } +#endif /* WITH_WSREP */ if (trx_is_started(trx)) { trx_commit_for_mysql(trx); } +#ifdef WITH_WSREP + if (wsrep_on((void*)thd)) { thd_proc_info(thd, tmp); } +#endif /* WITH_WSREP */ } /*****************************************************************//** @@ -4343,6 +4429,20 @@ innobase_kill_query( DBUG_ENTER("innobase_kill_query"); DBUG_ASSERT(hton == innodb_hton_ptr); +#ifdef WITH_WSREP + wsrep_thd_LOCK(thd); + if (wsrep_thd_conflict_state(thd) != NO_CONFLICT) { + /* if victim has been signaled by BF thread and/or aborting + is already progressing, following query aborting is not necessary + any more. + Also, BF thread should own trx mutex for the victim, which would + conflict with trx_mutex_enter() below + */ + wsrep_thd_UNLOCK(thd); + DBUG_VOID_RETURN; + } + wsrep_thd_UNLOCK(thd); +#endif /* WITH_WSREP */ trx = thd_to_trx(thd); if (trx) @@ -4513,7 +4613,11 @@ ha_innobase::max_supported_key_length() const case 8192: return(1536); default: +#ifdef WITH_WSREP return(3500); +#else + return(3500); +#endif } } @@ -5620,6 +5724,117 @@ get_field_offset( return((uint) (field->ptr - table->record[0])); } +#ifdef WITH_WSREP +UNIV_INTERN +int +wsrep_innobase_mysql_sort( +/*===============*/ + /* out: str contains sort string */ + int mysql_type, /* in: MySQL type */ + uint charset_number, /* in: number of the charset */ + unsigned char* str, /* in: data field */ + unsigned int str_length, /* in: data field length, + not UNIV_SQL_NULL */ + unsigned int buf_length) /* in: total str buffer length */ + +{ + CHARSET_INFO* charset; + enum_field_types mysql_tp; + int ret_length = str_length; + + DBUG_ASSERT(str_length != UNIV_SQL_NULL); + + mysql_tp = (enum_field_types) mysql_type; + + switch (mysql_tp) { + + case MYSQL_TYPE_BIT: + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_VARCHAR: + { + uchar tmp_str[REC_VERSION_56_MAX_INDEX_COL_LEN]; + uint tmp_length = REC_VERSION_56_MAX_INDEX_COL_LEN; + + /* Use the charset number to pick the right charset struct for + the comparison. Since the MySQL function get_charset may be + slow before Bar removes the mutex operation there, we first + look at 2 common charsets directly. */ + + if (charset_number == default_charset_info->number) { + charset = default_charset_info; + } else if (charset_number == my_charset_latin1.number) { + charset = &my_charset_latin1; + } else { + charset = get_charset(charset_number, MYF(MY_WME)); + + if (charset == NULL) { + sql_print_error("InnoDB needs charset %lu for doing " + "a comparison, but MySQL cannot " + "find that charset.", + (ulong) charset_number); + ut_a(0); + } + } + + ut_a(str_length <= tmp_length); + memcpy(tmp_str, str, str_length); + + tmp_length = charset->coll->strnxfrm(charset, str, str_length, + str_length, tmp_str, + tmp_length, 0); + DBUG_ASSERT(tmp_length <= str_length); + if (wsrep_protocol_version < 3) { + tmp_length = charset->coll->strnxfrm( + charset, str, str_length, + str_length, tmp_str, tmp_length, 0); + DBUG_ASSERT(tmp_length <= str_length); + } else { + /* strnxfrm will expand the destination string, + protocols < 3 truncated the sorted sring + protocols > 3 gets full sorted sring + */ + tmp_length = charset->coll->strnxfrm( + charset, str, buf_length, + str_length, tmp_str, tmp_length, 0); + DBUG_ASSERT(tmp_length <= buf_length); + ret_length = tmp_length; + } + + break; + } + case MYSQL_TYPE_DECIMAL : + case MYSQL_TYPE_TINY : + case MYSQL_TYPE_SHORT : + case MYSQL_TYPE_LONG : + case MYSQL_TYPE_FLOAT : + case MYSQL_TYPE_DOUBLE : + case MYSQL_TYPE_NULL : + case MYSQL_TYPE_TIMESTAMP : + case MYSQL_TYPE_LONGLONG : + case MYSQL_TYPE_INT24 : + case MYSQL_TYPE_DATE : + case MYSQL_TYPE_TIME : + case MYSQL_TYPE_DATETIME : + case MYSQL_TYPE_YEAR : + case MYSQL_TYPE_NEWDATE : + case MYSQL_TYPE_NEWDECIMAL : + case MYSQL_TYPE_ENUM : + case MYSQL_TYPE_SET : + case MYSQL_TYPE_GEOMETRY : + break; + default: + break; + } + + return ret_length; +} +#endif /* WITH_WSREP */ + /*************************************************************//** InnoDB uses this function to compare two data fields for which the data type is such that we must use MySQL code to compare them. NOTE that the prototype @@ -6120,11 +6335,261 @@ innobase_read_from_2_little_endian( return((uint) ((ulint)(buf[0]) + 256 * ((ulint)(buf[1])))); } +#ifdef WITH_WSREP /*******************************************************************//** Stores a key value for a row to a buffer. @return key value length as stored in buff */ UNIV_INTERN uint +wsrep_store_key_val_for_row( +/*===============================*/ + TABLE* table, + uint keynr, /*!< in: key number */ + char* buff, /*!< in/out: buffer for the key value (in MySQL + format) */ + uint buff_len,/*!< in: buffer length */ + const uchar* record, + ibool* key_is_null)/*!< out: full key was null */ +{ + KEY* key_info = table->key_info + keynr; + KEY_PART_INFO* key_part = key_info->key_part; + KEY_PART_INFO* end = key_part + key_info->user_defined_key_parts; + char* buff_start = buff; + enum_field_types mysql_type; + Field* field; + + DBUG_ENTER("wsrep_store_key_val_for_row"); + + memset(buff, 0, buff_len); + *key_is_null = TRUE; + + for (; key_part != end; key_part++) { + uchar sorted[REC_VERSION_56_MAX_INDEX_COL_LEN] = {'\0'}; + ibool part_is_null = FALSE; + + if (key_part->null_bit) { + if (record[key_part->null_offset] & + key_part->null_bit) { + *buff = 1; + part_is_null = TRUE; + } else { + *buff = 0; + } + buff++; + } + if (!part_is_null) *key_is_null = FALSE; + + field = key_part->field; + mysql_type = field->type(); + + if (mysql_type == MYSQL_TYPE_VARCHAR) { + /* >= 5.0.3 true VARCHAR */ + ulint lenlen; + ulint len; + const byte* data; + ulint key_len; + ulint true_len; + const CHARSET_INFO* cs; + int error=0; + + key_len = key_part->length; + + if (part_is_null) { + buff += key_len + 2; + + continue; + } + cs = field->charset(); + + lenlen = (ulint) + (((Field_varstring*)field)->length_bytes); + + data = row_mysql_read_true_varchar(&len, + (byte*) (record + + (ulint)get_field_offset(table, field)), + lenlen); + + true_len = len; + + /* For multi byte character sets we need to calculate + the true length of the key */ + + if (len > 0 && cs->mbmaxlen > 1) { + true_len = (ulint) cs->cset->well_formed_len(cs, + (const char *) data, + (const char *) data + len, + (uint) (key_len / + cs->mbmaxlen), + &error); + } + + /* In a column prefix index, we may need to truncate + the stored value: */ + + if (true_len > key_len) { + true_len = key_len; + } + + memcpy(sorted, data, true_len); + true_len = wsrep_innobase_mysql_sort( + mysql_type, cs->number, sorted, true_len, + REC_VERSION_56_MAX_INDEX_COL_LEN); + + if (wsrep_protocol_version > 1) { + memcpy(buff, sorted, true_len); + /* Note that we always reserve the maximum possible + length of the true VARCHAR in the key value, though + only len first bytes after the 2 length bytes contain + actual data. The rest of the space was reset to zero + in the bzero() call above. */ + buff += true_len; + } else { + buff += key_len; + } + } else if (mysql_type == MYSQL_TYPE_TINY_BLOB + || mysql_type == MYSQL_TYPE_MEDIUM_BLOB + || mysql_type == MYSQL_TYPE_BLOB + || mysql_type == MYSQL_TYPE_LONG_BLOB + /* MYSQL_TYPE_GEOMETRY data is treated + as BLOB data in innodb. */ + || mysql_type == MYSQL_TYPE_GEOMETRY) { + + const CHARSET_INFO* cs; + ulint key_len; + ulint true_len; + int error=0; + ulint blob_len; + const byte* blob_data; + + ut_a(key_part->key_part_flag & HA_PART_KEY_SEG); + + key_len = key_part->length; + + if (part_is_null) { + buff += key_len + 2; + + continue; + } + + cs = field->charset(); + + blob_data = row_mysql_read_blob_ref(&blob_len, + (byte*) (record + + (ulint)get_field_offset(table, field)), + (ulint) field->pack_length()); + + true_len = blob_len; + + ut_a(get_field_offset(table, field) + == key_part->offset); + + /* For multi byte character sets we need to calculate + the true length of the key */ + + if (blob_len > 0 && cs->mbmaxlen > 1) { + true_len = (ulint) cs->cset->well_formed_len(cs, + (const char *) blob_data, + (const char *) blob_data + + blob_len, + (uint) (key_len / + cs->mbmaxlen), + &error); + } + + /* All indexes on BLOB and TEXT are column prefix + indexes, and we may need to truncate the data to be + stored in the key value: */ + + if (true_len > key_len) { + true_len = key_len; + } + + memcpy(sorted, blob_data, true_len); + true_len = wsrep_innobase_mysql_sort( + mysql_type, cs->number, sorted, true_len, + REC_VERSION_56_MAX_INDEX_COL_LEN); + + memcpy(buff, sorted, true_len); + + /* Note that we always reserve the maximum possible + length of the BLOB prefix in the key value. */ + if (wsrep_protocol_version > 1) { + buff += true_len; + } else { + buff += key_len; + } + } else { + /* Here we handle all other data types except the + true VARCHAR, BLOB and TEXT. Note that the column + value we store may be also in a column prefix + index. */ + + const CHARSET_INFO* cs = NULL; + ulint true_len; + ulint key_len; + const uchar* src_start; + int error=0; + enum_field_types real_type; + + key_len = key_part->length; + + if (part_is_null) { + buff += key_len; + + continue; + } + + src_start = record + key_part->offset; + real_type = field->real_type(); + true_len = key_len; + + /* Character set for the field is defined only + to fields whose type is string and real field + type is not enum or set. For these fields check + if character set is multi byte. */ + + if (real_type != MYSQL_TYPE_ENUM + && real_type != MYSQL_TYPE_SET + && ( mysql_type == MYSQL_TYPE_VAR_STRING + || mysql_type == MYSQL_TYPE_STRING)) { + + cs = field->charset(); + + /* For multi byte character sets we need to + calculate the true length of the key */ + + if (key_len > 0 && cs->mbmaxlen > 1) { + + true_len = (ulint) + cs->cset->well_formed_len(cs, + (const char *)src_start, + (const char *)src_start + + key_len, + (uint) (key_len / + cs->mbmaxlen), + &error); + } + memcpy(sorted, src_start, true_len); + true_len = wsrep_innobase_mysql_sort( + mysql_type, cs->number, sorted, true_len, + REC_VERSION_56_MAX_INDEX_COL_LEN); + + memcpy(buff, sorted, true_len); + } else { + memcpy(buff, src_start, true_len); + } + buff += true_len; + + } + } + + ut_a(buff <= buff_start + buff_len); + + DBUG_RETURN((uint)(buff - buff_start)); +} +#endif /* WITH_WSREP */ +UNIV_INTERN +uint ha_innobase::store_key_val_for_row( /*===============================*/ uint keynr, /*!< in: key number */ @@ -6965,6 +7430,9 @@ ha_innobase::write_row( dberr_t error; int error_result= 0; ibool auto_inc_used= FALSE; +#ifdef WITH_WSREP + ibool auto_inc_inserted= FALSE; /* if NULL was inserted */ +#endif ulint sql_command; trx_t* trx = thd_to_trx(user_thd); @@ -6998,8 +7466,20 @@ ha_innobase::write_row( if ((sql_command == SQLCOM_ALTER_TABLE || sql_command == SQLCOM_OPTIMIZE || sql_command == SQLCOM_CREATE_INDEX +#ifdef WITH_WSREP + || (wsrep_on(user_thd) && wsrep_load_data_splitting && + sql_command == SQLCOM_LOAD && + !thd_test_options( + user_thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) +#endif /* WITH_WSREP */ || sql_command == SQLCOM_DROP_INDEX) && num_write_row >= 10000) { +#ifdef WITH_WSREP + if (wsrep_on(user_thd) && sql_command == SQLCOM_LOAD) { + WSREP_DEBUG("forced trx split for LOAD: %s", + wsrep_thd_query(user_thd)); + } +#endif /* WITH_WSREP */ /* ALTER TABLE is COMMITted at every 10000 copied rows. The IX table lock for the original table has to be re-issued. As this method will be called on a temporary table where the @@ -7033,6 +7513,21 @@ no_commit: */ ; } else if (src_table == prebuilt->table) { +#ifdef WITH_WSREP + switch (wsrep_run_wsrep_commit(user_thd, wsrep_hton, 1)) + { + case WSREP_TRX_OK: + break; + case WSREP_TRX_SIZE_EXCEEDED: + case WSREP_TRX_CERT_FAIL: + case WSREP_TRX_ERROR: + DBUG_RETURN(1); + } + + if (binlog_hton->commit(binlog_hton, user_thd, 1)) + DBUG_RETURN(1); + wsrep_post_commit(user_thd, TRUE); +#endif /* WITH_WSREP */ /* Source table is not in InnoDB format: no need to re-acquire locks on it. */ @@ -7043,6 +7538,21 @@ no_commit: /* We will need an IX lock on the destination table. */ prebuilt->sql_stat_start = TRUE; } else { +#ifdef WITH_WSREP + switch (wsrep_run_wsrep_commit(user_thd, wsrep_hton, 1)) + { + case WSREP_TRX_OK: + break; + case WSREP_TRX_SIZE_EXCEEDED: + case WSREP_TRX_CERT_FAIL: + case WSREP_TRX_ERROR: + DBUG_RETURN(1); + } + + if (binlog_hton->commit(binlog_hton, user_thd, 1)) + DBUG_RETURN(1); + wsrep_post_commit(user_thd, TRUE); +#endif /* WITH_WSREP */ /* Ensure that there are no other table locks than LOCK_IX and LOCK_AUTO_INC on the destination table. */ @@ -7072,6 +7582,10 @@ no_commit: innobase_get_auto_increment(). */ prebuilt->autoinc_error = DB_SUCCESS; +#ifdef WITH_WSREP + auto_inc_inserted= (table->next_number_field->val_int() == 0); +#endif + if ((error_result = update_auto_increment())) { /* We don't want to mask autoinc overflow errors. */ @@ -7150,6 +7664,33 @@ no_commit: case SQLCOM_REPLACE_SELECT: goto set_max_autoinc; +#ifdef WITH_WSREP + /* workaround for LP bug #355000, retrying the insert */ + case SQLCOM_INSERT: + if (wsrep_on(current_thd) && + auto_inc_inserted && + wsrep_drupal_282555_workaround && + wsrep_thd_retry_counter(current_thd) == 0 && + !thd_test_options(current_thd, + OPTION_NOT_AUTOCOMMIT | + OPTION_BEGIN)) { + WSREP_DEBUG( + "retrying insert: %s", + (*wsrep_thd_query(current_thd)) ? + wsrep_thd_query(current_thd) : + (char *)"void"); + error= DB_SUCCESS; + wsrep_thd_set_conflict_state( + current_thd, MUST_ABORT); + innobase_srv_conc_exit_innodb( + prebuilt->trx); + /* jump straight to func exit over + * later wsrep hooks */ + goto func_exit; + } + break; +#endif /* WITH_WSREP */ + default: break; } @@ -7209,6 +7750,21 @@ report_error: prebuilt->table->flags, user_thd); +#ifdef WITH_WSREP + if (!error_result && wsrep_thd_exec_mode(user_thd) == LOCAL_STATE && + wsrep_on(user_thd) && !wsrep_consistency_check(user_thd) && + (sql_command != SQLCOM_LOAD || + thd_binlog_format(user_thd) == BINLOG_FORMAT_ROW)) { + + if (wsrep_append_keys(user_thd, false, record, NULL)) { + DBUG_PRINT("wsrep", ("row key failed")); + error_result = HA_ERR_INTERNAL_ERROR; + goto wsrep_error; + } + } +wsrep_error: +#endif /* WITH_WSREP */ + if (error_result == HA_FTS_INVALID_DOCID) { my_error(HA_FTS_INVALID_DOCID, MYF(0)); } @@ -7496,6 +8052,87 @@ calc_row_difference( return(DB_SUCCESS); } +#ifdef WITH_WSREP +static +int +wsrep_calc_row_hash( +/*================*/ + byte* digest, /*!< in/out: md5 sum */ + const uchar* row, /*!< in: row in MySQL format */ + TABLE* table, /*!< in: table in MySQL data + dictionary */ + row_prebuilt_t* prebuilt, /*!< in: InnoDB prebuilt struct */ + THD* thd) /*!< in: user thread */ +{ + Field* field; + enum_field_types field_mysql_type; + uint n_fields; + ulint len; + const byte* ptr; + ulint col_type; + uint i; + + void *ctx = wsrep_md5_init(); + + n_fields = table->s->fields; + + for (i = 0; i < n_fields; i++) { + byte null_byte=0; + byte true_byte=1; + + field = table->field[i]; + + ptr = (const byte*) row + get_field_offset(table, field); + len = field->pack_length(); + + field_mysql_type = field->type(); + + col_type = prebuilt->table->cols[i].mtype; + + switch (col_type) { + + case DATA_BLOB: + ptr = row_mysql_read_blob_ref(&len, ptr, len); + + break; + + case DATA_VARCHAR: + case DATA_BINARY: + case DATA_VARMYSQL: + if (field_mysql_type == MYSQL_TYPE_VARCHAR) { + /* This is a >= 5.0.3 type true VARCHAR where + the real payload data length is stored in + 1 or 2 bytes */ + + ptr = row_mysql_read_true_varchar( + &len, ptr, + (ulint) + (((Field_varstring*)field)->length_bytes)); + + } + + break; + default: + ; + } + /* + if (field->null_ptr && + field_in_record_is_null(table, field, (char*) row)) { + */ + + if (field->is_null_in_record(row)) { + wsrep_md5_update(ctx, (char*)&null_byte, 1); + } else { + wsrep_md5_update(ctx, (char*)&true_byte, 1); + wsrep_md5_update(ctx, (char*)ptr, len); + } + } + + wsrep_compute_md5_hash((char*)digest, ctx); + + return(0); +} +#endif /* WITH_WSREP */ /**********************************************************************//** Updates a row given as a parameter to a new value. Note that we are given whole rows, not just the fields which are updated: this incurs some @@ -7633,6 +8270,24 @@ func_exit: innobase_active_small(); +#ifdef WITH_WSREP + if (error == DB_SUCCESS && + wsrep_thd_exec_mode(user_thd) == LOCAL_STATE && + wsrep_on(user_thd)) { + + DBUG_PRINT("wsrep", ("update row key")); + + if (wsrep_append_keys(user_thd, false, old_row, new_row)) { + WSREP_DEBUG("WSREP: UPDATE_ROW_KEY FAILED"); + DBUG_PRINT("wsrep", ("row key failed")); + err = HA_ERR_INTERNAL_ERROR; + goto wsrep_error; + } + } +wsrep_error: +#endif /* WITH_WSREP */ + + DBUG_RETURN(err); } @@ -7680,6 +8335,19 @@ ha_innobase::delete_row( innobase_active_small(); +#ifdef WITH_WSREP + if (error == DB_SUCCESS && + wsrep_thd_exec_mode(user_thd) == LOCAL_STATE && + wsrep_on(user_thd)) { + + if (wsrep_append_keys(user_thd, false, record, NULL)) { + DBUG_PRINT("wsrep", ("delete fail")); + error = (dberr_t)HA_ERR_INTERNAL_ERROR; + goto wsrep_error; + } + } +wsrep_error: +#endif DBUG_RETURN(convert_error_code_to_mysql( error, prebuilt->table->flags, user_thd)); } @@ -8840,6 +9508,396 @@ ha_innobase::ft_end() rnd_end(); } +#ifdef WITH_WSREP +extern dict_index_t* +wsrep_dict_foreign_find_index( + dict_table_t* table, + const char** col_names, + const char** columns, + ulint n_cols, + dict_index_t* types_idx, + ibool check_charsets, + ulint check_null); + + +extern dberr_t +wsrep_append_foreign_key( +/*===========================*/ + trx_t* trx, /*!< in: trx */ + dict_foreign_t* foreign, /*!< in: foreign key constraint */ + const rec_t* rec, /*!mysql_thd; + ulint rcode = DB_SUCCESS; + char cache_key[513] = {'\0'}; + int cache_key_len; + bool const copy = true; + + if (!wsrep_on(trx->mysql_thd) || + wsrep_thd_exec_mode(thd) != LOCAL_STATE) + return DB_SUCCESS; + + if (!thd || !foreign || + (!foreign->referenced_table && !foreign->foreign_table)) + { + WSREP_INFO("FK: %s missing in: %s", + (!thd) ? "thread" : + ((!foreign) ? "constraint" : + ((!foreign->referenced_table) ? + "referenced table" : "foreign table")), + (thd && wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + return DB_ERROR; + } + + if ( !((referenced) ? + foreign->referenced_table : foreign->foreign_table)) + { + WSREP_DEBUG("pulling %s table into cache", + (referenced) ? "referenced" : "foreign"); + mutex_enter(&(dict_sys->mutex)); + if (referenced) + { + foreign->referenced_table = + dict_table_get_low( + foreign->referenced_table_name_lookup); + if (foreign->referenced_table) + { + foreign->referenced_index = + wsrep_dict_foreign_find_index( + foreign->referenced_table, NULL, + foreign->referenced_col_names, + foreign->n_fields, + foreign->foreign_index, + TRUE, FALSE); + } + } + else + { + foreign->foreign_table = + dict_table_get_low( + foreign->foreign_table_name_lookup); + if (foreign->foreign_table) + { + foreign->foreign_index = + wsrep_dict_foreign_find_index( + foreign->foreign_table, NULL, + foreign->foreign_col_names, + foreign->n_fields, + foreign->referenced_index, + TRUE, FALSE); + } + } + mutex_exit(&(dict_sys->mutex)); + } + + if ( !((referenced) ? + foreign->referenced_table : foreign->foreign_table)) + { + WSREP_WARN("FK: %s missing in query: %s", + (!foreign->referenced_table) ? + "referenced table" : "foreign table", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + return DB_ERROR; + } + byte key[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + ulint len = WSREP_MAX_SUPPORTED_KEY_LENGTH; + + dict_index_t *idx_target = (referenced) ? + foreign->referenced_index : index; + dict_index_t *idx = (referenced) ? + UT_LIST_GET_FIRST(foreign->referenced_table->indexes) : + UT_LIST_GET_FIRST(foreign->foreign_table->indexes); + int i = 0; + while (idx != NULL && idx != idx_target) { + if (innobase_strcasecmp (idx->name, innobase_index_reserve_name) != 0) { + i++; + } + idx = UT_LIST_GET_NEXT(indexes, idx); + } + ut_a(idx); + key[0] = (char)i; + + rcode = wsrep_rec_get_foreign_key( + &key[1], &len, rec, index, idx, + wsrep_protocol_version > 1); + if (rcode != DB_SUCCESS) { + WSREP_ERROR( + "FK key set failed: %lu (%lu %lu), index: %s %s, %s", + rcode, referenced, shared, + (index && index->name) ? index->name : + "void index", + (index && index->table_name) ? index->table_name : + "void table", + wsrep_thd_query(thd)); + return DB_ERROR; + } + strncpy(cache_key, + (wsrep_protocol_version > 1) ? + ((referenced) ? + foreign->referenced_table->name : + foreign->foreign_table->name) : + foreign->foreign_table->name, sizeof(cache_key) - 1); + cache_key_len = strlen(cache_key); +#ifdef WSREP_DEBUG_PRINT + ulint j; + fprintf(stderr, "FK parent key, table: %s %s len: %lu ", + cache_key, (shared) ? "shared" : "exclusive", len+1); + for (j=0; jreferenced_table->name, + foreign->foreign_table->name); + } + + wsrep_buf_t wkey_part[3]; + wsrep_key_t wkey = {wkey_part, 3}; + if (!wsrep_prepare_key_for_innodb( + (const uchar*)cache_key, + cache_key_len + 1, + (const uchar*)key, len+1, + wkey_part, + (size_t*)&wkey.key_parts_num)) { + WSREP_WARN("key prepare failed for cascaded FK: %s", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + return DB_ERROR; + } + rcode = (int)wsrep->append_key( + wsrep, + wsrep_ws_handle(thd, trx), + &wkey, + 1, + shared ? WSREP_KEY_SHARED : WSREP_KEY_EXCLUSIVE, + copy); + if (rcode) { + DBUG_PRINT("wsrep", ("row key failed: %lu", rcode)); + WSREP_ERROR("Appending cascaded fk row key failed: %s, %lu", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void", rcode); + return DB_ERROR; + } + + return DB_SUCCESS; +} + +static int +wsrep_append_key( +/*==================*/ + THD *thd, + trx_t *trx, + TABLE_SHARE *table_share, + TABLE *table, + const char* key, + uint16_t key_len, + bool shared +) +{ + DBUG_ENTER("wsrep_append_key"); + bool const copy = true; +#ifdef WSREP_DEBUG_PRINT + fprintf(stderr, "%s conn %ld, trx %llu, keylen %d, table %s ", + (shared) ? "Shared" : "Exclusive", + wsrep_thd_thread_id(thd), (long long)trx->id, key_len, + table_share->table_name.str); + for (int i=0; itable_cache_key.str, + table_share->table_cache_key.length, + (const uchar*)key, key_len, + wkey_part, + (size_t*)&wkey.key_parts_num)) { + WSREP_WARN("key prepare failed for: %s", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + } + + int rcode = (int)wsrep->append_key( + wsrep, + wsrep_ws_handle(thd, trx), + &wkey, + 1, + shared ? WSREP_KEY_SHARED : WSREP_KEY_EXCLUSIVE, + copy); + if (rcode) { + DBUG_PRINT("wsrep", ("row key failed: %d", rcode)); + WSREP_WARN("Appending row key failed: %s, %d", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void", rcode); + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + } + DBUG_RETURN(0); +} + +extern void compute_md5_hash(char *digest, const char *buf, int len); +#define MD5_HASH compute_md5_hash + +int +ha_innobase::wsrep_append_keys( +/*==================*/ + THD *thd, + bool shared, + const uchar* record0, /* in: row in MySQL format */ + const uchar* record1) /* in: row in MySQL format */ +{ + int rcode; + DBUG_ENTER("wsrep_append_keys"); + + bool key_appended = false; + trx_t *trx = thd_to_trx(thd); + + if (table_share && table_share->tmp_table != NO_TMP_TABLE) { + WSREP_DEBUG("skipping tmp table DML: THD: %lu tmp: %d SQL: %s", + wsrep_thd_thread_id(thd), + table_share->tmp_table, + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + DBUG_RETURN(0); + } + + if (wsrep_protocol_version == 0) { + uint len; + char keyval[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + char *key = &keyval[0]; + KEY *key_info = table->key_info; + ibool is_null; + + len = wsrep_store_key_val_for_row( + table, 0, key, key_info->key_length, record0, &is_null); + + if (!is_null) { + rcode = wsrep_append_key( + thd, trx, table_share, table, keyval, + len, shared); + if (rcode) DBUG_RETURN(rcode); + } + else + { + WSREP_DEBUG("NULL key skipped (proto 0): %s", + wsrep_thd_query(thd)); + } + } else { + ut_a(table->s->keys <= 256); + uint i; + bool hasPK= false; + + for (i=0; is->keys; ++i) { + KEY* key_info = table->key_info + i; + if (key_info->flags & HA_NOSAME) { + hasPK = true; + if (i != table->s->primary_key) { + wsrep_thd_set_PA_safe(thd, FALSE); + } + } + } + + for (i=0; is->keys; ++i) { + uint len; + char keyval0[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + char keyval1[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + char* key0 = &keyval0[1]; + char* key1 = &keyval1[1]; + KEY* key_info = table->key_info + i; + ibool is_null; + + dict_index_t* idx = innobase_get_index(i); + dict_table_t* tab = (idx) ? idx->table : NULL; + + keyval0[0] = (char)i; + keyval1[0] = (char)i; + + if (!tab) { + WSREP_WARN("MySQL-InnoDB key mismatch %s %s", + table->s->table_name.str, + key_info->name); + } + /* !hasPK == table with no PK, must append all non-unique keys */ + if (!hasPK || key_info->flags & HA_NOSAME || + ((tab && + dict_table_get_referenced_constraint(tab, idx)) || + (!tab && referenced_by_foreign_key()))) { + + len = wsrep_store_key_val_for_row( + table, i, key0, key_info->key_length, + record0, &is_null); + if (!is_null) { + rcode = wsrep_append_key( + thd, trx, table_share, table, + keyval0, len+1, shared); + if (rcode) DBUG_RETURN(rcode); + + if (key_info->flags & HA_NOSAME || shared) + key_appended = true; + + } + else + { + WSREP_DEBUG("NULL key skipped: %s", + wsrep_thd_query(thd)); + } + if (record1) { + len = wsrep_store_key_val_for_row( + table, i, key1, key_info->key_length, + record1, &is_null); + if (!is_null && memcmp(key0, key1, len)) { + rcode = wsrep_append_key( + thd, trx, table_share, + table, + keyval1, len+1, shared); + if (rcode) DBUG_RETURN(rcode); + } + } + } + } + } + + /* if no PK, calculate hash of full row, to be the key value */ + if (!key_appended && wsrep_certify_nonPK) { + uchar digest[16]; + int rcode; + + wsrep_calc_row_hash(digest, record0, table, prebuilt, thd); + if ((rcode = wsrep_append_key(thd, trx, table_share, table, + (const char*) digest, 16, + shared))) { + DBUG_RETURN(rcode); + } + + if (record1) { + wsrep_calc_row_hash( + digest, record1, table, prebuilt, thd); + if ((rcode = wsrep_append_key(thd, trx, table_share, + table, + (const char*) digest, + 16, shared))) { + DBUG_RETURN(rcode); + } + } + DBUG_RETURN(0); + } + + DBUG_RETURN(0); +} +#endif /* WITH_WSREP */ /*********************************************************************//** Stores a reference to the current row to 'ref' field of the handle. Note @@ -12699,11 +13757,18 @@ ha_innobase::external_lock( /* used by test case */ DBUG_EXECUTE_IF("no_innodb_binlog_errors", skip = true;); if (!skip) { +#ifdef WITH_WSREP + if (!wsrep_on(thd) || wsrep_thd_exec_mode(thd) == LOCAL_STATE) + { +#endif /* WITH_WSREP */ my_error(ER_BINLOG_STMT_MODE_AND_ROW_ENGINE, MYF(0), " InnoDB is limited to row-logging when " "transaction isolation level is " "READ COMMITTED or READ UNCOMMITTED."); DBUG_RETURN(HA_ERR_LOGGING_IMPOSSIBLE); +#ifdef WITH_WSREP + } +#endif /* WITH_WSREP */ } } @@ -14157,6 +15222,9 @@ innobase_xa_prepare( to the session variable take effect only in the next transaction */ if (!trx->support_xa) { +#ifdef WITH_WSREP + thd_get_xid(thd, (MYSQL_XID*) &trx->xid); +#endif // WITH_WSREP return(0); } @@ -16225,6 +17293,303 @@ static SHOW_VAR innodb_status_variables_export[]= { static struct st_mysql_storage_engine innobase_storage_engine= { MYSQL_HANDLERTON_INTERFACE_VERSION }; +#ifdef WITH_WSREP +void +wsrep_abort_slave_trx(wsrep_seqno_t bf_seqno, wsrep_seqno_t victim_seqno) +{ + WSREP_ERROR("Trx %lld tries to abort slave trx %lld. This could be " + "caused by:\n\t" + "1) unsupported configuration options combination, please check documentation.\n\t" + "2) a bug in the code.\n\t" + "3) a database corruption.\n Node consistency compromized, " + "need to abort. Restart the node to resync with cluster.", + (long long)bf_seqno, (long long)victim_seqno); + abort(); +} +/*******************************************************************//** +This function is used to kill one transaction in BF. */ + +int +wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, + const trx_t * const bf_trx, + trx_t *victim_trx, ibool signal) +{ + ut_ad(lock_mutex_own()); + ut_ad(trx_mutex_own(victim_trx)); + ut_ad(bf_thd_ptr); + ut_ad(victim_trx); + + DBUG_ENTER("wsrep_innobase_kill_one_trx"); + THD *bf_thd = bf_thd_ptr ? (THD*) bf_thd_ptr : NULL; + THD *thd = (THD *) victim_trx->mysql_thd; + int64_t bf_seqno = (bf_thd) ? wsrep_thd_trx_seqno(bf_thd) : 0; + + if (!thd) { + DBUG_PRINT("wsrep", ("no thd for conflicting lock")); + WSREP_WARN("no THD for trx: %llu", victim_trx->id); + DBUG_RETURN(1); + } + if (!bf_thd) { + DBUG_PRINT("wsrep", ("no BF thd for conflicting lock")); + WSREP_WARN("no BF THD for trx: %llu", (bf_trx) ? bf_trx->id : 0); + DBUG_RETURN(1); + } + + WSREP_LOG_CONFLICT(bf_thd, thd, TRUE); + + WSREP_DEBUG("BF kill (%lu, seqno: %lld), victim: (%lu) trx: %llu", + signal, (long long)bf_seqno, + wsrep_thd_thread_id(thd), + victim_trx->id); + + WSREP_DEBUG("Aborting query: %s", + (thd && wsrep_thd_query(thd)) ? wsrep_thd_query(thd) : "void"); + + wsrep_thd_LOCK(thd); + + if (wsrep_thd_query_state(thd) == QUERY_EXITING) { + WSREP_DEBUG("kill trx EXITING for %llu", victim_trx->id); + wsrep_thd_UNLOCK(thd); + DBUG_RETURN(0); + } + if(wsrep_thd_exec_mode(thd) != LOCAL_STATE) { + WSREP_DEBUG("withdraw for BF trx: %llu, state: %d", + victim_trx->id, + wsrep_thd_conflict_state(thd)); + } + + switch (wsrep_thd_conflict_state(thd)) { + case NO_CONFLICT: + wsrep_thd_set_conflict_state(thd, MUST_ABORT); + break; + case MUST_ABORT: + WSREP_DEBUG("victim %llu in MUST ABORT state", + victim_trx->id); + wsrep_thd_UNLOCK(thd); + wsrep_thd_awake(thd, signal); + DBUG_RETURN(0); + break; + case ABORTED: + case ABORTING: // fall through + default: + WSREP_DEBUG("victim %llu in state %d", + victim_trx->id, wsrep_thd_conflict_state(thd)); + wsrep_thd_UNLOCK(thd); + DBUG_RETURN(0); + break; + } + + switch (wsrep_thd_query_state(thd)) { + case QUERY_COMMITTING: + enum wsrep_status rcode; + + WSREP_DEBUG("kill query for: %ld", + wsrep_thd_thread_id(thd)); + WSREP_DEBUG("kill trx QUERY_COMMITTING for %llu", + victim_trx->id); + + if (wsrep_thd_exec_mode(thd) == REPL_RECV) { + wsrep_abort_slave_trx(bf_seqno, + wsrep_thd_trx_seqno(thd)); + } else { + rcode = wsrep->abort_pre_commit( + wsrep, bf_seqno, + (wsrep_trx_id_t)victim_trx->id + ); + + switch (rcode) { + case WSREP_WARNING: + WSREP_DEBUG("cancel commit warning: %llu", + victim_trx->id); + wsrep_thd_UNLOCK(thd); + wsrep_thd_awake(thd, signal); + DBUG_RETURN(1); + break; + case WSREP_OK: + break; + default: + WSREP_ERROR( + "cancel commit bad exit: %d %llu", + rcode, + victim_trx->id); + /* unable to interrupt, must abort */ + /* note: kill_mysql() will block, if we cannot. + * kill the lock holder first. + */ + abort(); + break; + } + } + wsrep_thd_UNLOCK(thd); + wsrep_thd_awake(thd, signal); + break; + case QUERY_EXEC: + /* it is possible that victim trx is itself waiting for some + * other lock. We need to cancel this waiting + */ + WSREP_DEBUG("kill trx QUERY_EXEC for %llu", victim_trx->id); + + victim_trx->lock.was_chosen_as_deadlock_victim= TRUE; + if (victim_trx->lock.wait_lock) { + WSREP_DEBUG("victim has wait flag: %ld", + wsrep_thd_thread_id(thd)); + lock_t* wait_lock = victim_trx->lock.wait_lock; + if (wait_lock) { + WSREP_DEBUG("canceling wait lock"); + victim_trx->lock.was_chosen_as_deadlock_victim= TRUE; + lock_cancel_waiting_and_release(wait_lock); + } + + wsrep_thd_UNLOCK(thd); + wsrep_thd_awake(thd, signal); + } else { + /* abort currently executing query */ + DBUG_PRINT("wsrep",("sending KILL_QUERY to: %ld", + wsrep_thd_thread_id(thd))); + WSREP_DEBUG("kill query for: %ld", + wsrep_thd_thread_id(thd)); + /* Note that innobase_kill_connection will take lock_mutex + and trx_mutex */ + wsrep_thd_UNLOCK(thd); + wsrep_thd_awake(thd, signal); + + /* for BF thd, we need to prevent him from committing */ + if (wsrep_thd_exec_mode(thd) == REPL_RECV) { + wsrep_abort_slave_trx(bf_seqno, + wsrep_thd_trx_seqno(thd)); + } + } + break; + case QUERY_IDLE: + { + bool skip_abort= false; + wsrep_aborting_thd_t abortees; + + WSREP_DEBUG("kill IDLE for %llu", victim_trx->id); + + if (wsrep_thd_exec_mode(thd) == REPL_RECV) { + WSREP_DEBUG("kill BF IDLE, seqno: %lld", + (long long)wsrep_thd_trx_seqno(thd)); + wsrep_thd_UNLOCK(thd); + wsrep_abort_slave_trx(bf_seqno, + wsrep_thd_trx_seqno(thd)); + DBUG_RETURN(0); + } + /* This will lock thd from proceeding after net_read() */ + wsrep_thd_set_conflict_state(thd, ABORTING); + + mysql_mutex_lock(&LOCK_wsrep_rollback); + + abortees = wsrep_aborting_thd; + while (abortees && !skip_abort) { + /* check if we have a kill message for this already */ + if (abortees->aborting_thd == thd) { + skip_abort = true; + WSREP_WARN("duplicate thd aborter %lu", + wsrep_thd_thread_id(thd)); + } + abortees = abortees->next; + } + if (!skip_abort) { + wsrep_aborting_thd_t aborting = (wsrep_aborting_thd_t) + my_malloc(sizeof(struct wsrep_aborting_thd), + MYF(0)); + aborting->aborting_thd = thd; + aborting->next = wsrep_aborting_thd; + wsrep_aborting_thd = aborting; + DBUG_PRINT("wsrep",("enqueuing trx abort for %lu", + wsrep_thd_thread_id(thd))); + WSREP_DEBUG("enqueuing trx abort for (%lu)", + wsrep_thd_thread_id(thd)); + } + + DBUG_PRINT("wsrep",("signalling wsrep rollbacker")); + WSREP_DEBUG("signaling aborter"); + mysql_cond_signal(&COND_wsrep_rollback); + mysql_mutex_unlock(&LOCK_wsrep_rollback); + wsrep_thd_UNLOCK(thd); + + break; + } + default: + WSREP_WARN("bad wsrep query state: %d", + wsrep_thd_query_state(thd)); + wsrep_thd_UNLOCK(thd); + break; + } + + DBUG_RETURN(0); +} +static int +wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd, + my_bool signal) +{ + DBUG_ENTER("wsrep_innobase_abort_thd"); + trx_t* victim_trx = thd_to_trx(victim_thd); + trx_t* bf_trx = (bf_thd) ? thd_to_trx(bf_thd) : NULL; + WSREP_DEBUG("abort transaction: BF: %s victim: %s", + wsrep_thd_query(bf_thd), + wsrep_thd_query(victim_thd)); + + if (victim_trx) + { + lock_mutex_enter(); + trx_mutex_enter(victim_trx); + int rcode = wsrep_innobase_kill_one_trx(bf_thd, bf_trx, + victim_trx, signal); + trx_mutex_exit(victim_trx); + lock_mutex_exit(); + wsrep_srv_conc_cancel_wait(victim_trx); + + DBUG_RETURN(rcode); + } else { + WSREP_DEBUG("victim does not have transaction"); + wsrep_thd_LOCK(victim_thd); + wsrep_thd_set_conflict_state(victim_thd, MUST_ABORT); + wsrep_thd_UNLOCK(victim_thd); + wsrep_thd_awake(victim_thd, signal); + } + DBUG_RETURN(-1); +} + +static int innobase_wsrep_set_checkpoint(handlerton* hton, const XID* xid) +{ + DBUG_ASSERT(hton == innodb_hton_ptr); + if (wsrep_is_wsrep_xid(xid)) { + mtr_t mtr; + mtr_start(&mtr); + trx_sysf_t* sys_header = trx_sysf_get(&mtr); + trx_sys_update_wsrep_checkpoint(xid, sys_header, &mtr); + mtr_commit(&mtr); + innobase_flush_logs(hton); + return 0; + } else { + return 1; + } +} + +static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid) +{ + DBUG_ASSERT(hton == innodb_hton_ptr); + trx_sys_read_wsrep_checkpoint(xid); + return 0; +} + +static void +wsrep_fake_trx_id( +/*==================*/ + handlerton *hton, + THD *thd) /*!< in: user thread handle */ +{ + mutex_enter(&trx_sys->mutex); + trx_id_t trx_id = trx_sys_get_new_trx_id(); + mutex_exit(&trx_sys->mutex); + + (void *)wsrep_ws_handle_for_trx(wsrep_thd_ws_handle(thd), trx_id); +} + +#endif /* WITH_WSREP */ + /* plugin options */ static MYSQL_SYSVAR_ENUM(checksum_algorithm, srv_checksum_algorithm, @@ -16957,6 +18322,40 @@ static MYSQL_SYSVAR_BOOL(disable_background_merge, NULL, NULL, FALSE); #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ +#ifdef WITH_INNODB_DISALLOW_WRITES +/******************************************************* + * innobase_disallow_writes variable definition * + *******************************************************/ + +/* Must always init to FALSE. */ +static my_bool innobase_disallow_writes = FALSE; + +/************************************************************************** +An "update" method for innobase_disallow_writes variable. */ +static +void +innobase_disallow_writes_update( +/*============================*/ + THD* thd, /* in: thread handle */ + st_mysql_sys_var* var, /* in: pointer to system + variable */ + void* var_ptr, /* out: pointer to dynamic + variable */ + const void* save) /* in: temporary storage */ +{ + *(my_bool*)var_ptr = *(my_bool*)save; + ut_a(srv_allow_writes_event); + if (*(my_bool*)var_ptr) + os_event_reset(srv_allow_writes_event); + else + os_event_set(srv_allow_writes_event); +} + +static MYSQL_SYSVAR_BOOL(disallow_writes, innobase_disallow_writes, + PLUGIN_VAR_NOCMDOPT, + "Tell InnoDB to stop any writes to disk", + NULL, innobase_disallow_writes_update, FALSE); +#endif /* WITH_INNODB_DISALLOW_WRITES */ static MYSQL_SYSVAR_BOOL(random_read_ahead, srv_random_read_ahead, PLUGIN_VAR_NOCMDARG, "Whether to use read ahead for random access within an extent.", @@ -17218,6 +18617,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(change_buffering_debug), MYSQL_SYSVAR(disable_background_merge), #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ +#ifdef WITH_INNODB_DISALLOW_WRITES + MYSQL_SYSVAR(disallow_writes), +#endif /* WITH_INNODB_DISALLOW_WRITES */ MYSQL_SYSVAR(random_read_ahead), MYSQL_SYSVAR(read_ahead_threshold), MYSQL_SYSVAR(read_only), diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 912be30c0ec..1fa9fe139fb 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -119,6 +119,10 @@ class ha_innobase: public handler void innobase_initialize_autoinc(); dict_index_t* innobase_get_index(uint keynr); +#ifdef WITH_WSREP + int wsrep_append_keys(THD *thd, bool shared, + const uchar* record0, const uchar* record1); +#endif /* Init values for the class: */ public: ha_innobase(handlerton *hton, TABLE_SHARE *table_arg); @@ -466,7 +470,40 @@ __attribute__((nonnull)); */ extern void mysql_bin_log_commit_pos(THD *thd, ulonglong *out_pos, const char **out_file); -struct trx_t; +#ifdef WITH_WSREP +#include +//extern "C" int wsrep_trx_order_before(void *thd1, void *thd2); + +extern "C" bool wsrep_thd_is_wsrep_on(THD *thd); + +extern "C" enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd); +extern "C" enum wsrep_conflict_state wsrep_thd_conflict_state(THD *thd); +extern "C" enum wsrep_query_state wsrep_thd_query_state(THD *thd); +extern "C" const char * wsrep_thd_exec_mode_str(THD *thd); +extern "C" const char * wsrep_thd_conflict_state_str(THD *thd); +extern "C" const char * wsrep_thd_query_state_str(THD *thd); +extern "C" wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd); + +extern "C" void wsrep_thd_set_exec_mode(THD *thd, enum wsrep_exec_mode mode); +extern "C" void wsrep_thd_set_query_state( + THD *thd, enum wsrep_query_state state); +extern "C" void wsrep_thd_set_conflict_state( + THD *thd, enum wsrep_conflict_state state); + +extern "C" void wsrep_thd_set_trx_to_replay(THD *thd, uint64 trx_id); + +extern "C"void wsrep_thd_LOCK(THD *thd); +extern "C"void wsrep_thd_UNLOCK(THD *thd); +extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd); +extern "C" time_t wsrep_thd_query_start(THD *thd); +extern "C" my_thread_id wsrep_thd_thread_id(THD *thd); +extern "C" int64_t wsrep_thd_trx_seqno(THD *thd); +extern "C" query_id_t wsrep_thd_query_id(THD *thd); +extern "C" char * wsrep_thd_query(THD *thd); +extern "C" query_id_t wsrep_thd_wsrep_last_query_id(THD *thd); +extern "C" void wsrep_thd_set_wsrep_last_query_id(THD *thd, query_id_t id); +extern "C" void wsrep_thd_awake(THD* thd, my_bool signal); +#endif extern const struct _ft_vft ft_vft_result; @@ -504,6 +541,9 @@ innobase_index_name_is_reserved( __attribute__((nonnull, warn_unused_result)); /*****************************************************************//** +#ifdef WITH_WSREP +extern "C" int wsrep_trx_is_aborting(void *thd_ptr); +#endif Determines InnoDB table flags. @retval true if successful, false if error */ UNIV_INTERN diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index a621a59042e..0b13573abc6 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -49,6 +49,10 @@ Smart ALTER TABLE #include "pars0pars.h" #include "row0sel.h" #include "ha_innodb.h" +#ifdef WITH_WSREP +//#include "wsrep_api.h" +#include // PROCESS_ACL +#endif /** Operations for creating secondary indexes (no rebuild needed) */ static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_ONLINE_CREATE diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index b026210b214..b5e62e53a72 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -518,6 +518,9 @@ be REC_VERSION_56_MAX_INDEX_COL_LEN (3072) bytes */ /** Defines the maximum fixed length column size */ #define DICT_MAX_FIXED_COL_LEN DICT_ANTELOPE_MAX_INDEX_COL_LEN +#ifdef WITH_WSREP +#define WSREP_MAX_SUPPORTED_KEY_LENGTH 3500 +#endif /* WITH_WSREP */ /** Data structure for a field in an index */ struct dict_field_t{ diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h index a02b8f1893a..336ff92a619 100644 --- a/storage/innobase/include/ha_prototypes.h +++ b/storage/innobase/include/ha_prototypes.h @@ -286,6 +286,22 @@ innobase_casedn_str( /*================*/ char* a); /*!< in/out: string to put in lower case */ +#ifdef WITH_WSREP +UNIV_INTERN +int +wsrep_innobase_kill_one_trx(void *thd_ptr, + const trx_t *bf_trx, trx_t *victim_trx, ibool signal); +my_bool wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe); +int wsrep_thd_conflict_state(void *thd_ptr, my_bool sync); +my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync); +int wsrep_trx_order_before(void *thd1, void *thd2); +int wsrep_innobase_mysql_sort(int mysql_type, uint charset_number, + unsigned char* str, unsigned int str_length, + unsigned int buf_length); +int +wsrep_on(void *thd_ptr); +extern "C" int wsrep_is_wsrep_xid(const void*); +#endif /* WITH_WSREP */ /**********************************************************************//** Determines the connection character set. @return connection character set */ diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h index 6d5ed35d5d8..385853bdb68 100644 --- a/storage/innobase/include/lock0lock.h +++ b/storage/innobase/include/lock0lock.h @@ -972,6 +972,16 @@ extern lock_sys_t* lock_sys; mutex_exit(&lock_sys->wait_mutex); \ } while (0) +#ifdef WITH_WSREP +/*********************************************************************//** +Cancels a waiting lock request and releases possible other transactions +waiting behind it. */ +UNIV_INTERN +void +lock_cancel_waiting_and_release( +/*============================*/ + lock_t* lock); /*!< in/out: waiting lock request */ +#endif /* WITH_WSREP */ #ifndef UNIV_NONINL #include "lock0lock.ic" #endif diff --git a/storage/innobase/include/rem0rec.h b/storage/innobase/include/rem0rec.h index 8e7d5ff2d48..238cb04e1f8 100644 --- a/storage/innobase/include/rem0rec.h +++ b/storage/innobase/include/rem0rec.h @@ -981,6 +981,15 @@ are given in one byte (resp. two byte) format. */ two upmost bits in a two byte offset for special purposes */ #define REC_MAX_DATA_SIZE (16 * 1024) +#ifdef WITH_WSREP +int wsrep_rec_get_foreign_key( + byte *buf, /* out: extracted key */ + ulint *buf_len, /* in/out: length of buf */ + const rec_t* rec, /* in: physical record */ + dict_index_t* index_for, /* in: index for foreign table */ + dict_index_t* index_ref, /* in: index for referenced table */ + ibool new_protocol); /* in: protocol > 1 */ +#endif /* WITH_WSREP */ #ifndef UNIV_NONINL #include "rem0rec.ic" #endif diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 905d4a0afa7..a1da2ee03b1 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -304,6 +304,10 @@ extern ulong srv_flush_log_at_trx_commit; extern uint srv_flush_log_at_timeout; extern char srv_adaptive_flushing; +#ifdef WITH_INNODB_DISALLOW_WRITES +/* When this event is reset we do not allow any file writes to take place. */ +extern os_event_t srv_allow_writes_event; +#endif /* WITH_INNODB_DISALLOW_WRITES */ /* If this flag is TRUE, then we will load the indexes' (and tables') metadata even if they are marked as "corrupted". Mostly it is for DBA to process corrupted index and table */ @@ -955,5 +959,13 @@ struct srv_slot_t{ # define srv_start_raw_disk_in_use 0 # define srv_file_per_table 1 #endif /* !UNIV_HOTBACKUP */ +#ifdef WITH_WSREP +UNIV_INTERN +void +wsrep_srv_conc_cancel_wait( +/*==================*/ + trx_t* trx); /*!< in: transaction object associated with the + thread */ +#endif /* WITH_WSREP */ #endif diff --git a/storage/innobase/include/sync0sync.ic b/storage/innobase/include/sync0sync.ic index cb375cb4a4f..f34f3f90b63 100644 --- a/storage/innobase/include/sync0sync.ic +++ b/storage/innobase/include/sync0sync.ic @@ -204,7 +204,10 @@ mutex_enter_func( ulint line) /*!< in: line where locked */ { ut_ad(mutex_validate(mutex)); +#ifndef WITH_WSREP + /* this cannot be be granted when BF trx kills a trx in lock wait state */ ut_ad(!mutex_own(mutex)); +#endif /* WITH_WSREP */ /* Note that we do not peek at the value of lock_word before trying the atomic test_and_set; we could peek, and possibly save time. */ diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h index 70f214d1ac7..9ffc8d99a7f 100644 --- a/storage/innobase/include/trx0sys.h +++ b/storage/innobase/include/trx0sys.h @@ -42,6 +42,9 @@ Created 3/26/1996 Heikki Tuuri #include "read0types.h" #include "page0types.h" #include "ut0bh.h" +#ifdef WITH_WSREP +#include "trx0xa.h" +#endif /* WITH_WSREP */ typedef UT_LIST_BASE_NODE_T(trx_t) trx_list_t; @@ -293,6 +296,9 @@ trx_sys_update_mysql_binlog_offset( ib_int64_t offset, /*!< in: position in that log file */ ulint field, /*!< in: offset of the MySQL log info field in the trx sys header */ +#ifdef WITH_WSREP + trx_sysf_t* sys_header, /*!< in: trx sys header */ +#endif /* WITH_WSREP */ mtr_t* mtr); /*!< in: mtr */ /*****************************************************************//** Prints to stderr the MySQL binlog offset info in the trx system header if @@ -301,6 +307,19 @@ UNIV_INTERN void trx_sys_print_mysql_binlog_offset(void); /*===================================*/ +#ifdef WITH_WSREP +/** Update WSREP checkpoint XID in sys header. */ +void +trx_sys_update_wsrep_checkpoint( + const XID* xid, /*!< in: WSREP XID */ + trx_sysf_t* sys_header, /*!< in: sys_header */ + mtr_t* mtr); /*!< in: mtr */ + +void +/** Read WSREP checkpoint XID from sys header. */ +trx_sys_read_wsrep_checkpoint( + XID* xid); /*!< out: WSREP XID */ +#endif /* WITH_WSREP */ /*****************************************************************//** Prints to stderr the MySQL master log offset info in the trx system header if the magic number shows it valid. */ @@ -529,6 +548,20 @@ this contains the same fields as TRX_SYS_MYSQL_LOG_INFO below */ within that file */ #define TRX_SYS_MYSQL_LOG_NAME 12 /*!< MySQL log file name */ +#ifdef WITH_WSREP +/* The offset to WSREP XID headers */ +#define TRX_SYS_WSREP_XID_INFO (UNIV_PAGE_SIZE - 3500) +#define TRX_SYS_WSREP_XID_MAGIC_N_FLD 0 +#define TRX_SYS_WSREP_XID_MAGIC_N 0x77737265 + +/* XID field: formatID, gtrid_len, bqual_len, xid_data */ +#define TRX_SYS_WSREP_XID_LEN (4 + 4 + 4 + XIDDATASIZE) +#define TRX_SYS_WSREP_XID_FORMAT 4 +#define TRX_SYS_WSREP_XID_GTRID_LEN 8 +#define TRX_SYS_WSREP_XID_BQUAL_LEN 12 +#define TRX_SYS_WSREP_XID_DATA 16 +#endif /* WITH_WSREP*/ + /** Doublewrite buffer */ /* @{ */ /** The offset of the doublewrite buffer header on the trx system header page */ diff --git a/storage/innobase/include/trx0sys.ic b/storage/innobase/include/trx0sys.ic index e097e29b551..7265a97ae25 100644 --- a/storage/innobase/include/trx0sys.ic +++ b/storage/innobase/include/trx0sys.ic @@ -445,7 +445,10 @@ trx_id_t trx_sys_get_new_trx_id(void) /*========================*/ { +#ifndef WITH_WSREP + /* wsrep_fake_trx_id violates this assert */ ut_ad(mutex_own(&trx_sys->mutex)); +#endif /* WITH_WSREP */ /* VERY important: after the database is started, max_trx_id value is divisible by TRX_SYS_TRX_ID_WRITE_MARGIN, and the following if diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 34e4c0067e2..a30bbdbebb2 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -1004,6 +1004,9 @@ struct trx_t{ /*------------------------------*/ char detailed_error[256]; /*!< detailed error message for last error, or empty. */ +#ifdef WITH_WSREP + os_event_t wsrep_event; /* event waited for in srv_conc_slot */ +#endif /* WITH_WSREP */ }; /* Transaction isolation levels (trx->isolation_level) */ diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index e4db2c30751..14ebb68fa9e 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -50,6 +50,11 @@ Created 5/7/1996 Heikki Tuuri #include "dict0boot.h" #include +#ifdef WITH_WSREP +extern my_bool wsrep_debug; +extern my_bool wsrep_log_conflicts; +#include "ha_prototypes.h" +#endif /* Restricts the length of search we will do in the waits-for graph of transactions */ #define LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK 1000000 @@ -945,6 +950,9 @@ UNIV_INLINE ibool lock_rec_has_to_wait( /*=================*/ +#ifdef WITH_WSREP + ibool for_locking, /*!< is caller locking or releasing */ +#endif /* WITH_WSREP */ const trx_t* trx, /*!< in: trx of new lock */ ulint type_mode,/*!< in: precise mode of the new lock to set: LOCK_S or LOCK_X, possibly @@ -1015,6 +1023,49 @@ lock_rec_has_to_wait( return(FALSE); } +#ifdef WITH_WSREP + /* if BF thread is locking and has conflict with another BF + thread, we need to look at trx ordering and lock types */ + if (for_locking && + wsrep_thd_is_BF(trx->mysql_thd, FALSE) && + wsrep_thd_is_BF(lock2->trx->mysql_thd, TRUE)) { + + if (wsrep_debug) { + fprintf(stderr, "\n BF-BF lock conflict \n"); + lock_rec_print(stderr, lock2); + } + + if (wsrep_trx_order_before(trx->mysql_thd, + lock2->trx->mysql_thd) && + (type_mode & LOCK_MODE_MASK) == LOCK_X && + (lock2->type_mode & LOCK_MODE_MASK) == LOCK_X) + { + /* exclusive lock conflicts are not accepted */ + fprintf(stderr, "BF-BF X lock conflict," + "type_mode: %lu supremum: %lu\n", + type_mode, lock_is_on_supremum); + fprintf(stderr, "conflicts states: my %d locked %d\n", + wsrep_thd_conflict_state(trx->mysql_thd, FALSE), + wsrep_thd_conflict_state(lock2->trx->mysql_thd, FALSE) ); + lock_rec_print(stderr, lock2); + abort(); + } else { + /* if lock2->index->n_uniq <= + lock2->index->n_user_defined_cols + operation is on uniq index + */ + if (wsrep_debug) fprintf(stderr, + "BF conflict, modes: %lu %lu, " + "idx: %s-%s n_uniq %u n_user %u\n", + type_mode, lock2->type_mode, + lock2->index->name, + lock2->index->table_name, + lock2->index->n_uniq, + lock2->index->n_user_defined_cols); + return FALSE; + } + } +#endif /* WITH_WSREP */ return(TRUE); } @@ -1045,7 +1096,11 @@ lock_has_to_wait( /* If this lock request is for a supremum record then the second bit on the lock bitmap is set */ +#ifdef WITH_WSREP + return(lock_rec_has_to_wait(FALSE, lock1->trx, +#else return(lock_rec_has_to_wait(lock1->trx, +#endif /* WITH_WSREP */ lock1->type_mode, lock2, lock_rec_get_nth_bit( lock1, 1))); @@ -1514,6 +1569,11 @@ lock_rec_has_expl( return(NULL); } +#ifdef WITH_WSREP +static +void +lock_rec_discard(lock_t* in_lock); +#endif #ifdef UNIV_DEBUG /*********************************************************************//** Checks if some other transaction has a lock request in the queue. @@ -1562,6 +1622,58 @@ lock_rec_other_has_expl_req( } #endif /* UNIV_DEBUG */ +#ifdef WITH_WSREP +static void +wsrep_kill_victim(const trx_t * const trx, const lock_t *lock) { + ut_ad(lock_mutex_own()); + ut_ad(trx_mutex_own(lock->trx)); + my_bool bf_this = wsrep_thd_is_BF(trx->mysql_thd, FALSE); + my_bool bf_other = wsrep_thd_is_BF(lock->trx->mysql_thd, TRUE); + + if ((bf_this && !bf_other) || + (bf_this && bf_other && wsrep_trx_order_before( + trx->mysql_thd, lock->trx->mysql_thd))) { + + if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { + if (wsrep_debug) + fprintf(stderr, "WSREP: BF victim waiting\n"); + /* cannot release lock, until our lock + is in the queue*/ + } else if (lock->trx != trx) { + if (wsrep_log_conflicts) { + mutex_enter(&trx_sys->mutex); + if (bf_this) + fputs("\n*** Priority TRANSACTION:\n", + stderr); + else + fputs("\n*** Victim TRANSACTION:\n", + stderr); + trx_print_latched(stderr, trx, 3000); + + if (bf_other) + fputs("\n*** Priority TRANSACTION:\n", + stderr); + else + fputs("\n*** Victim TRANSACTION:\n", + stderr); + trx_print_latched(stderr, lock->trx, 3000); + + mutex_exit(&trx_sys->mutex); + fputs("*** WAITING FOR THIS LOCK TO BE GRANTED:\n", + stderr); + + if (lock_get_type(lock) == LOCK_REC) { + lock_rec_print(stderr, lock); + } else { + lock_table_print(stderr, lock); + } + } + wsrep_innobase_kill_one_trx(trx->mysql_thd, + (const trx_t*) trx, lock->trx, TRUE); + } + } +} +#endif /*********************************************************************//** Checks if some other transaction has a conflicting explicit lock request in the queue, so that we have to wait. @@ -1590,7 +1702,15 @@ lock_rec_other_has_conflicting( lock != NULL; lock = lock_rec_get_next_const(heap_no, lock)) { - if (lock_rec_has_to_wait(trx, mode, lock, is_supremum)) { +#ifdef WITH_WSREP + if (lock_rec_has_to_wait(TRUE, trx, mode, lock, is_supremum)) { + trx_mutex_enter(lock->trx); + wsrep_kill_victim(trx, lock); + trx_mutex_exit(lock->trx); +#else + if (lock_rec_has_to_wait(trx, mode, lock, is_supremum)) { +#endif /* WITH_WSREP */ + return(lock); } } @@ -1771,6 +1891,28 @@ lock_number_of_rows_locked( /*============== RECORD LOCK CREATION AND QUEUE MANAGEMENT =============*/ +#ifdef WITH_WSREP +static +void +wsrep_print_wait_locks( +/*============*/ + lock_t* c_lock) /* conflicting lock to print */ +{ + if (wsrep_debug && c_lock->trx->lock.wait_lock != c_lock) { + fprintf(stderr, "WSREP: c_lock != wait lock\n"); + if (lock_get_type_low(c_lock) & LOCK_TABLE) + lock_table_print(stderr, c_lock); + else + lock_rec_print(stderr, c_lock); + + if (lock_get_type_low(c_lock->trx->lock.wait_lock) & LOCK_TABLE) + lock_table_print(stderr, c_lock->trx->lock.wait_lock); + else + lock_rec_print(stderr, c_lock->trx->lock.wait_lock); + } +} +#endif /* WITH_WSREP */ + /*********************************************************************//** Creates a new record lock and inserts it to the lock queue. Does NOT check for deadlocks or lock compatibility! @@ -1779,6 +1921,10 @@ static lock_t* lock_rec_create( /*============*/ +#ifdef WITH_WSREP + lock_t* const c_lock, /* conflicting lock */ + que_thr_t* thr, +#endif ulint type_mode,/*!< in: lock mode and wait flag, type is ignored and replaced by LOCK_REC */ @@ -1850,8 +1996,78 @@ lock_rec_create( ut_ad(index->table->n_ref_count > 0 || !index->table->can_be_evicted); +#ifdef WITH_WSREP + if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + lock_t *hash = (lock_t *)c_lock->hash; + lock_t *prev = NULL; + + while (hash && + wsrep_thd_is_BF(((lock_t *)hash)->trx->mysql_thd, TRUE) && + wsrep_trx_order_before( + ((lock_t *)hash)->trx->mysql_thd, + trx->mysql_thd)) { + prev = hash; + hash = (lock_t *)hash->hash; + } + lock->hash = hash; + if (prev) { + prev->hash = lock; + } else { + c_lock->hash = lock; + } + /* + * delayed conflict resolution '...kill_one_trx' was not called, + * if victim was waiting for some other lock + */ + trx_mutex_enter(c_lock->trx); + if (c_lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { + + c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE; + + if (wsrep_debug) wsrep_print_wait_locks(c_lock); + + trx->lock.que_state = TRX_QUE_LOCK_WAIT; + lock_set_lock_and_trx_wait(lock, trx); + UT_LIST_ADD_LAST(trx_locks, trx->lock.trx_locks, lock); + + ut_ad(thr != NULL); + trx->lock.wait_thr = thr; + thr->state = QUE_THR_LOCK_WAIT; + + /* have to release trx mutex for the duration of + victim lock release. This will eventually call + lock_grant, which wants to grant trx mutex again + */ + if (caller_owns_trx_mutex) trx_mutex_exit(trx); + lock_cancel_waiting_and_release( + c_lock->trx->lock.wait_lock); + if (caller_owns_trx_mutex) trx_mutex_enter(trx); + + /* trx might not wait for c_lock, but some other lock + does not matter if wait_lock was released above + */ + if (c_lock->trx->lock.wait_lock == c_lock) { + lock_reset_lock_and_trx_wait(lock); + } + trx_mutex_exit(c_lock->trx); + + if (wsrep_debug) fprintf( + stderr, + "WSREP: c_lock canceled %llu\n", + (ulonglong) c_lock->trx->id); + + /* have to bail out here to avoid lock_set_lock... */ + return(lock); + } + trx_mutex_exit(c_lock->trx); + } else { + HASH_INSERT(lock_t, hash, lock_sys->rec_hash, + lock_rec_fold(space, page_no), lock); + } +#else HASH_INSERT(lock_t, hash, lock_sys->rec_hash, lock_rec_fold(space, page_no), lock); +#endif /* WITH_WSREP */ if (!caller_owns_trx_mutex) { trx_mutex_enter(trx); @@ -1886,6 +2102,9 @@ static dberr_t lock_rec_enqueue_waiting( /*=====================*/ +#ifdef WITH_WSREP + lock_t* c_lock, /* conflicting lock */ +#endif ulint type_mode,/*!< in: lock mode this transaction is requesting: LOCK_S or LOCK_X, possibly @@ -1943,6 +2162,9 @@ lock_rec_enqueue_waiting( /* Enqueue the lock request that will wait to be granted, note that we already own the trx mutex. */ lock = lock_rec_create( +#ifdef WITH_WSREP + c_lock, thr, +#endif /* WITH_WSREP */ type_mode | LOCK_WAIT, block, heap_no, index, trx, TRUE); /* Release the mutex to obey the latching order. @@ -2043,7 +2265,19 @@ lock_rec_add_to_queue( const lock_t* other_lock = lock_rec_other_has_expl_req(mode, 0, LOCK_WAIT, block, heap_no, trx); +#ifdef WITH_WSREP + /* this can potentionally assert with wsrep */ + if (wsrep_on(trx->mysql_thd)) { + if (wsrep_debug && other_lock) { + fprintf(stderr, + "WSREP: InnoDB assert ignored\n"); + } + } else { + ut_a(!other_lock); + } +#else ut_a(!other_lock); +#endif /* WITH_WSREP */ } #endif /* UNIV_DEBUG */ @@ -2094,9 +2328,15 @@ lock_rec_add_to_queue( } somebody_waits: - return(lock_rec_create( +#ifdef WITH_WSREP + return(lock_rec_create(NULL, NULL, type_mode, block, heap_no, index, trx, caller_owns_trx_mutex)); +#else + return(lock_rec_create( + type_mode, block, heap_no, index, trx, + caller_owns_trx_mutex)); +#endif /* WITH_WSREP */ } /** Record locking request status */ @@ -2159,9 +2399,13 @@ lock_rec_lock_fast( if (lock == NULL) { if (!impl) { /* Note that we don't own the trx mutex. */ +#ifdef WITH_WSREP + lock = lock_rec_create(NULL, thr, + mode, block, heap_no, index, trx, FALSE); +#else lock = lock_rec_create( mode, block, heap_no, index, trx, FALSE); - +#endif /* WITH_WSREP */ } status = LOCK_REC_SUCCESS_CREATED; } else { @@ -2214,6 +2458,9 @@ lock_rec_lock_slow( que_thr_t* thr) /*!< in: query thread */ { trx_t* trx; +#ifdef WITH_WSREP + lock_t* c_lock(NULL); +#endif dberr_t err = DB_SUCCESS; ut_ad(lock_mutex_own()); @@ -2237,18 +2484,31 @@ lock_rec_lock_slow( /* The trx already has a strong enough lock on rec: do nothing */ - +#ifdef WITH_WSREP + } else if ((c_lock = (ib_lock_t*)lock_rec_other_has_conflicting( + static_cast(mode), + block, heap_no, trx))) { +#else } else if (lock_rec_other_has_conflicting( static_cast(mode), block, heap_no, trx)) { +#endif /* WITH_WSREP */ /* If another transaction has a non-gap conflicting request in the queue, as this transaction does not have a lock strong enough already granted on the record, we have to wait. */ +#ifdef WITH_WSREP + /* c_lock is NULL here if jump to enqueue_waiting happened + but it's ok because lock is not NULL in that case and c_lock + is not used. */ + err= + lock_rec_enqueue_waiting(c_lock, mode, block, heap_no, index, thr); +#else err = lock_rec_enqueue_waiting( mode, block, heap_no, index, thr); +#endif /* WITH_WSREP */ } else if (!impl) { /* Set the requested lock on the record, note that @@ -3738,9 +3998,19 @@ lock_deadlock_select_victim( /* The joining transaction is 'smaller', choose it as the victim and roll it back. */ +#ifdef WITH_WSREP + if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) + return(ctx->wait_lock->trx); + else +#endif /* WITH_WSREP */ return(ctx->start); } +#ifdef WITH_WSREP + if (wsrep_thd_is_BF(ctx->wait_lock->trx->mysql_thd, TRUE)) + return(ctx->start); + else +#endif /* WITH_WSREP */ return(ctx->wait_lock->trx); } @@ -3870,6 +4140,11 @@ lock_deadlock_search( ctx->too_deep = TRUE; +#ifdef WITH_WSREP + if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) + return(ctx->wait_lock->trx->id); + else +#endif /* WITH_WSREP */ /* Select the joining transaction as the victim. */ return(ctx->start->id); @@ -3888,7 +4163,12 @@ lock_deadlock_search( ctx->too_deep = TRUE; - return(ctx->start->id); +#ifdef WITH_WSREP + if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) + return(lock->trx->id); + else +#endif /* WITH_WSREP */ + return(ctx->start->id); } ctx->wait_lock = lock->trx->lock.wait_lock; @@ -4006,9 +4286,18 @@ lock_deadlock_check_and_resolve( ut_a(trx == ctx.start); ut_a(victim_trx_id == trx->id); - if (!srv_read_only_mode) { - lock_deadlock_joining_trx_print(trx, lock); +#ifdef WITH_WSREP + if (!wsrep_thd_is_BF(ctx.start->mysql_thd, TRUE)) + { +#endif /* WITH_WSREP */ + if (!srv_read_only_mode) { + lock_deadlock_joining_trx_print(trx, lock); + } +#ifdef WITH_WSREP + } else { + /* BF processor */; } +#endif /* WITH_WSREP */ MONITOR_INC(MONITOR_DEADLOCK); @@ -4046,6 +4335,9 @@ UNIV_INLINE lock_t* lock_table_create( /*==============*/ +#ifdef WITH_WSREP + lock_t* c_lock, /*!< in: conflicting lock */ +#endif dict_table_t* table, /*!< in/out: database table in dictionary cache */ ulint type_mode,/*!< in: lock mode possibly ORed with @@ -4089,7 +4381,47 @@ lock_table_create( ut_ad(table->n_ref_count > 0 || !table->can_be_evicted); UT_LIST_ADD_LAST(trx_locks, trx->lock.trx_locks, lock); + +#ifdef WITH_WSREP + if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + UT_LIST_INSERT_AFTER( + un_member.tab_lock.locks, table->locks, c_lock, lock); + } else { + UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); + } + + if (c_lock) trx_mutex_enter(c_lock->trx); + if (c_lock && c_lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { + + c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE; + + if (wsrep_debug) wsrep_print_wait_locks(c_lock); + + /* have to release trx mutex for the duration of + victim lock release. This will eventually call + lock_grant, which wants to grant trx mutex again + */ + /* caller has trx_mutex, have to release for lock cancel */ + trx_mutex_exit(trx); + lock_cancel_waiting_and_release(c_lock->trx->lock.wait_lock); + trx_mutex_enter(trx); + + /* trx might not wait for c_lock, but some other lock + does not matter if wait_lock was released above + */ + if (c_lock->trx->lock.wait_lock == c_lock) { + lock_reset_lock_and_trx_wait(lock); + } + + if (wsrep_debug) { + fprintf(stderr, "WSREP: c_lock canceled %llu\n", + (ulonglong) c_lock->trx->id); + } + } + if (c_lock) trx_mutex_exit(c_lock->trx); +#else UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); +#endif /* WITH_WSREP */ if (UNIV_UNLIKELY(type_mode & LOCK_WAIT)) { @@ -4246,6 +4578,9 @@ static dberr_t lock_table_enqueue_waiting( /*=======================*/ +#ifdef WITH_WSREP + lock_t* c_lock, /*!< in: conflicting lock */ +#endif ulint mode, /*!< in: lock mode this transaction is requesting */ dict_table_t* table, /*!< in/out: table */ @@ -4290,7 +4625,14 @@ lock_table_enqueue_waiting( /* Enqueue the lock request that will wait to be granted */ - lock = lock_table_create(table, mode | LOCK_WAIT, trx); +#ifdef WITH_WSREP + if (trx->lock.was_chosen_as_deadlock_victim) { + return(DB_DEADLOCK); + } + lock = lock_table_create(c_lock, table, mode | LOCK_WAIT, trx); +#else + lock = lock_table_create(table, mode | LOCK_WAIT, trx); +#endif /* WITH_WSREP */ /* Release the mutex to obey the latching order. This is safe, because lock_deadlock_check_and_resolve() @@ -4362,6 +4704,14 @@ lock_table_other_has_incompatible( && !lock_mode_compatible(lock_get_mode(lock), mode) && (wait || !lock_get_wait(lock))) { +#ifdef WITH_WSREP + if (wsrep_debug) + fprintf(stderr, "WSREP: table lock abort"); + trx_mutex_enter(lock->trx); + wsrep_kill_victim((trx_t *)trx, (lock_t *)lock); + trx_mutex_exit(lock->trx); +#endif + return(lock); } } @@ -4384,6 +4734,9 @@ lock_table( enum lock_mode mode, /*!< in: lock mode */ que_thr_t* thr) /*!< in: query thread */ { +#ifdef WITH_WSREP + lock_t *c_lock = NULL; +#endif trx_t* trx; dberr_t err; const lock_t* wait_for; @@ -4414,8 +4767,13 @@ lock_table( /* We have to check if the new lock is compatible with any locks other transactions have in the table lock queue. */ +#ifdef WITH_WSREP + wait_for = lock_table_other_has_incompatible( + trx, LOCK_WAIT, table, mode); +#else wait_for = lock_table_other_has_incompatible( trx, LOCK_WAIT, table, mode); +#endif trx_mutex_enter(trx); @@ -4423,9 +4781,17 @@ lock_table( mode: this trx may have to wait */ if (wait_for != NULL) { +#ifdef WITH_WSREP + err = lock_table_enqueue_waiting((ib_lock_t*)wait_for, mode | flags, table, thr); +#else err = lock_table_enqueue_waiting(mode | flags, table, thr); +#endif } else { +#ifdef WITH_WSREP + lock_table_create(c_lock, table, mode | flags, trx); +#else lock_table_create(table, mode | flags, trx); +#endif ut_a(!flags || mode == LOCK_S || mode == LOCK_X); @@ -4463,7 +4829,11 @@ lock_table_ix_resurrect( trx, LOCK_WAIT, table, LOCK_IX)); trx_mutex_enter(trx); +#ifdef WITH_WSREP + lock_table_create(NULL, table, LOCK_IX, trx); +#else lock_table_create(table, LOCK_IX, trx); +#endif lock_mutex_exit(); trx_mutex_exit(trx); } @@ -5594,6 +5964,7 @@ lock_rec_queue_validate( if (!lock_rec_get_gap(lock) && !lock_get_wait(lock)) { +#ifndef WITH_WSREP enum lock_mode mode; if (lock_get_mode(lock) == LOCK_S) { @@ -5603,6 +5974,7 @@ lock_rec_queue_validate( } ut_a(!lock_rec_other_has_expl_req( mode, 0, 0, block, heap_no, lock->trx)); +#endif /* WITH_WSREP */ } else if (lock_get_wait(lock) && !lock_rec_get_gap(lock)) { @@ -5906,6 +6278,9 @@ lock_rec_insert_check_and_lock( lock_t* lock; dberr_t err; ulint next_rec_heap_no; +#ifdef WITH_WSREP + lock_t* c_lock=NULL; +#endif ut_ad(block->frame == page_align(rec)); ut_ad(!dict_index_is_online_ddl(index) @@ -5962,17 +6337,30 @@ lock_rec_insert_check_and_lock( had to wait for their insert. Both had waiting gap type lock requests on the successor, which produced an unnecessary deadlock. */ +#ifdef WITH_WSREP + if ((c_lock = (ib_lock_t*)lock_rec_other_has_conflicting( + static_cast( + LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION), + block, next_rec_heap_no, trx))) { +#else if (lock_rec_other_has_conflicting( static_cast( LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION), block, next_rec_heap_no, trx)) { +#endif /* WITH_WSREP */ /* Note that we may get DB_SUCCESS also here! */ trx_mutex_enter(trx); +#ifdef WITH_WSREP + err = lock_rec_enqueue_waiting(c_lock, + LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION, + block, next_rec_heap_no, index, thr); +#else err = lock_rec_enqueue_waiting( LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION, block, next_rec_heap_no, index, thr); +#endif /* WITH_WSREP */ trx_mutex_exit(trx); } else { diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index 45ca07bc7c4..fd9e60d123b 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -104,6 +104,12 @@ UNIV_INTERN os_ib_mutex_t os_file_seek_mutexes[OS_FILE_N_SEEK_MUTEXES]; /* In simulated aio, merge at most this many consecutive i/os */ #define OS_AIO_MERGE_N_CONSECUTIVE 64 +#ifdef WITH_INNODB_DISALLOW_WRITES +#define WAIT_ALLOW_WRITES() os_event_wait(srv_allow_writes_event) +#else +#define WAIT_ALLOW_WRITES() do { } while (0) +#endif /* WITH_INNODB_DISALLOW_WRITES */ + /********************************************************************** InnoDB AIO Implementation: @@ -927,7 +933,9 @@ os_file_create_tmpfile(void) /*========================*/ { FILE* file = NULL; - int fd = innobase_mysql_tmpfile(); + int fd; + WAIT_ALLOW_WRITES(); + fd = innobase_mysql_tmpfile(); ut_ad(!srv_read_only_mode); @@ -1253,6 +1261,7 @@ os_file_create_directory( return(TRUE); #else int rcode; + WAIT_ALLOW_WRITES(); rcode = mkdir(pathname, 0770); @@ -1379,6 +1388,8 @@ os_file_create_simple_func( #else /* __WIN__ */ int create_flag; + if (create_mode != OS_FILE_OPEN && create_mode != OS_FILE_OPEN_RAW) + WAIT_ALLOW_WRITES(); ut_a(!(create_mode & OS_FILE_ON_ERROR_SILENT)); ut_a(!(create_mode & OS_FILE_ON_ERROR_NO_EXIT)); @@ -1566,6 +1577,8 @@ os_file_create_simple_no_error_handling_func( int create_flag; ut_a(name); + if (create_mode != OS_FILE_OPEN && create_mode != OS_FILE_OPEN_RAW) + WAIT_ALLOW_WRITES(); ut_a(!(create_mode & OS_FILE_ON_ERROR_SILENT)); ut_a(!(create_mode & OS_FILE_ON_ERROR_NO_EXIT)); @@ -1894,6 +1907,8 @@ os_file_create_func( #else /* __WIN__ */ int create_flag; const char* mode_str = NULL; + if (create_mode != OS_FILE_OPEN && create_mode != OS_FILE_OPEN_RAW) + WAIT_ALLOW_WRITES(); on_error_no_exit = create_mode & OS_FILE_ON_ERROR_NO_EXIT ? TRUE : FALSE; @@ -2089,6 +2104,7 @@ loop: goto loop; #else int ret; + WAIT_ALLOW_WRITES(); ret = unlink(name); @@ -2153,6 +2169,7 @@ loop: goto loop; #else int ret; + WAIT_ALLOW_WRITES(); ret = unlink(name); @@ -2206,6 +2223,7 @@ os_file_rename_func( return(FALSE); #else int ret; + WAIT_ALLOW_WRITES(); ret = rename(oldpath, newpath); @@ -2440,6 +2458,7 @@ os_file_set_eof( HANDLE h = (HANDLE) _get_osfhandle(fileno(file)); return(SetEndOfFile(h)); #else /* __WIN__ */ + WAIT_ALLOW_WRITES(); return(!ftruncate(fileno(file), ftell(file))); #endif /* __WIN__ */ } @@ -2534,6 +2553,7 @@ os_file_flush_func( return(FALSE); #else int ret; + WAIT_ALLOW_WRITES(); #if defined(HAVE_DARWIN_THREADS) # ifndef F_FULLFSYNC @@ -3251,6 +3271,7 @@ retry: return(FALSE); #else ssize_t ret; + WAIT_ALLOW_WRITES(); ret = os_file_pwrite(file, buf, n, offset); diff --git a/storage/innobase/rem/rem0rec.cc b/storage/innobase/rem/rem0rec.cc index 0d7b7c16785..3ff71d5c59e 100644 --- a/storage/innobase/rem/rem0rec.cc +++ b/storage/innobase/rem/rem0rec.cc @@ -33,6 +33,9 @@ Created 5/30/1994 Heikki Tuuri #include "mtr0mtr.h" #include "mtr0log.h" #include "fts0fts.h" +#ifdef WITH_WSREP +#include +#endif /* WITH_WSREP */ /* PHYSICAL RECORD (OLD STYLE) =========================== @@ -1961,3 +1964,134 @@ rec_get_trx_id( } # endif /* UNIV_DEBUG */ #endif /* !UNIV_HOTBACKUP */ + +#ifdef WITH_WSREP +int +wsrep_rec_get_foreign_key( + byte *buf, /* out: extracted key */ + ulint *buf_len, /* in/out: length of buf */ + const rec_t* rec, /* in: physical record */ + dict_index_t* index_for, /* in: index in foreign table */ + dict_index_t* index_ref, /* in: index in referenced table */ + ibool new_protocol) /* in: protocol > 1 */ +{ + const byte* data; + ulint len; + ulint key_len = 0; + ulint i; + uint key_parts; + mem_heap_t* heap = NULL; + ulint offsets_[REC_OFFS_NORMAL_SIZE]; + const ulint* offsets; + + ut_ad(index_for); + ut_ad(index_ref); + + rec_offs_init(offsets_); + offsets = rec_get_offsets(rec, index_for, offsets_, + ULINT_UNDEFINED, &heap); + + ut_ad(rec_offs_validate(rec, NULL, offsets)); + + ut_ad(rec); + + key_parts = dict_index_get_n_unique_in_tree(index_for); + for (i = 0; + i < key_parts && + (index_for->type & DICT_CLUSTERED || i < key_parts - 1); + i++) { + dict_field_t* field_f = + dict_index_get_nth_field(index_for, i); + const dict_col_t* col_f = dict_field_get_col(field_f); + dict_field_t* field_r = + dict_index_get_nth_field(index_ref, i); + const dict_col_t* col_r = dict_field_get_col(field_r); + + data = rec_get_nth_field(rec, offsets, i, &len); + if (key_len + ((len != UNIV_SQL_NULL) ? len + 1 : 1) > + *buf_len) { + fprintf (stderr, + "WSREP: FK key len exceeded %lu %lu %lu\n", + key_len, len, *buf_len); + goto err_out; + } + + if (len == UNIV_SQL_NULL) { + ut_a(!(col_f->prtype & DATA_NOT_NULL)); + *buf++ = 1; + key_len++; + } else if (!new_protocol) { + if (!(col_r->prtype & DATA_NOT_NULL)) { + *buf++ = 0; + key_len++; + } + memcpy(buf, data, len); + *buf_len = wsrep_innobase_mysql_sort( + (int)(col_f->prtype & DATA_MYSQL_TYPE_MASK), + (uint)dtype_get_charset_coll(col_f->prtype), + buf, len, *buf_len); + } else { /* new protocol */ + if (!(col_r->prtype & DATA_NOT_NULL)) { + *buf++ = 0; + key_len++; + } + switch (col_f->mtype) { + case DATA_INT: { + byte* ptr = buf+len; + for (;;) { + ptr--; + *ptr = *data; + if (ptr == buf) { + break; + } + data++; + } + + if (!(col_f->prtype & DATA_UNSIGNED)) { + buf[len-1] = (byte) (buf[len-1] ^ 128); + } + + break; + } + case DATA_VARCHAR: + case DATA_VARMYSQL: + case DATA_CHAR: + case DATA_MYSQL: + /* Copy the actual data */ + ut_memcpy(buf, data, len); + len = wsrep_innobase_mysql_sort( + (int) + (col_f->prtype & DATA_MYSQL_TYPE_MASK), + (uint) + dtype_get_charset_coll(col_f->prtype), + buf, len, *buf_len); + break; + case DATA_BLOB: + case DATA_BINARY: + memcpy(buf, data, len); + break; + default: + break; + } + + key_len += len; + buf += len; + } + } + + rec_validate(rec, offsets); + + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); + } + + *buf_len = key_len; + return DB_SUCCESS; + + err_out: + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); + } + return DB_ERROR; +} +#endif // WITH_WSREP diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 65a6c433f5c..e6487730a77 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -918,6 +918,14 @@ row_ins_invalidate_query_cache( innobase_invalidate_query_cache(thr_get_trx(thr), buf, len); mem_free(buf); } +#ifdef WITH_WSREP +dberr_t wsrep_append_foreign_key(trx_t *trx, + dict_foreign_t* foreign, + const rec_t* clust_rec, + dict_index_t* clust_index, + ibool referenced, + ibool shared); +#endif /* WITH_WSREP */ /*********************************************************************//** Perform referential actions or checks when a parent row is deleted or updated @@ -1269,7 +1277,19 @@ row_ins_foreign_check_on_constraint( cascade->state = UPD_NODE_UPDATE_CLUSTERED; - err = row_update_cascade_for_mysql(thr, cascade, +#ifdef WITH_WSREP + err = wsrep_append_foreign_key( + thr_get_trx(thr), + foreign, + clust_rec, + clust_index, + FALSE, FALSE); + if (err != DB_SUCCESS) { + fprintf(stderr, + "WSREP: foreign key append failed: %d\n", err); + } else +#endif /* WITH_WSREP */ + err = row_update_cascade_for_mysql(thr, cascade, foreign->foreign_table); if (foreign->foreign_table->n_foreign_key_checks_running == 0) { @@ -1601,7 +1621,14 @@ run_again: if (check_ref) { err = DB_SUCCESS; - +#ifdef WITH_WSREP + err = wsrep_append_foreign_key( + thr_get_trx(thr), + foreign, + rec, + check_index, + check_ref, TRUE); +#endif /* WITH_WSREP */ goto end_scan; } else if (foreign->type != 0) { /* There is an ON UPDATE or ON DELETE diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index fb626519132..7cbd91b65cd 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -51,6 +51,9 @@ Created 12/27/1996 Heikki Tuuri #include "pars0sym.h" #include "eval0eval.h" #include "buf0lru.h" +#ifdef WITH_WSREP +extern my_bool wsrep_debug; +#endif /* What kind of latch and lock can we assume when the control comes to @@ -170,6 +173,50 @@ func_exit: return(is_referenced); } +#ifdef WITH_WSREP +static +ibool +wsrep_row_upd_index_is_foreign( +/*========================*/ + dict_index_t* index, /*!< in: index */ + trx_t* trx) /*!< in: transaction */ +{ + dict_table_t* table = index->table; + dict_foreign_t* foreign; + ibool froze_data_dict = FALSE; + ibool is_referenced = FALSE; + + if (!UT_LIST_GET_FIRST(table->foreign_list)) { + + return(FALSE); + } + + if (trx->dict_operation_lock_mode == 0) { + row_mysql_freeze_data_dictionary(trx); + froze_data_dict = TRUE; + } + + foreign = UT_LIST_GET_FIRST(table->foreign_list); + + while (foreign) { + if (foreign->foreign_index == index) { + + is_referenced = TRUE; + goto func_exit; + } + + foreign = UT_LIST_GET_NEXT(foreign_list, foreign); + } + +func_exit: + if (froze_data_dict) { + row_mysql_unfreeze_data_dictionary(trx); + } + + return(is_referenced); +} +#endif /* WITH_WSREP */ + /*********************************************************************//** Checks if possible foreign key constraints hold after a delete of the record under pcur. @@ -287,7 +334,132 @@ run_again: } err = DB_SUCCESS; +func_exit: + if (got_s_lock) { + row_mysql_unfreeze_data_dictionary(trx); + } + mem_heap_free(heap); + + return(err); +} +#ifdef WITH_WSREP +static +dberr_t +wsrep_row_upd_check_foreign_constraints( +/*=================================*/ + upd_node_t* node, /*!< in: row update node */ + btr_pcur_t* pcur, /*!< in: cursor positioned on a record; NOTE: the + cursor position is lost in this function! */ + dict_table_t* table, /*!< in: table in question */ + dict_index_t* index, /*!< in: index of the cursor */ + ulint* offsets,/*!< in/out: rec_get_offsets(pcur.rec, index) */ + que_thr_t* thr, /*!< in: query thread */ + mtr_t* mtr) /*!< in: mtr */ +{ + dict_foreign_t* foreign; + mem_heap_t* heap; + dtuple_t* entry; + trx_t* trx; + const rec_t* rec; + ulint n_ext; + dberr_t err; + ibool got_s_lock = FALSE; + ibool opened = FALSE; + + if (UT_LIST_GET_FIRST(table->foreign_list) == NULL) { + + return(DB_SUCCESS); + } + + trx = thr_get_trx(thr); + + /* TODO: make native slave thread bail out here */ + + rec = btr_pcur_get_rec(pcur); + ut_ad(rec_offs_validate(rec, index, offsets)); + + heap = mem_heap_create(500); + + entry = row_rec_to_index_entry(rec, index, offsets, + &n_ext, heap); + + mtr_commit(mtr); + + mtr_start(mtr); + + if (trx->dict_operation_lock_mode == 0) { + got_s_lock = TRUE; + + row_mysql_freeze_data_dictionary(trx); + } + + foreign = UT_LIST_GET_FIRST(table->foreign_list); + + while (foreign) { + /* Note that we may have an update which updates the index + record, but does NOT update the first fields which are + referenced in a foreign key constraint. Then the update does + NOT break the constraint. */ + + if (foreign->foreign_index == index + && (node->is_delete + || row_upd_changes_first_fields_binary( + entry, index, node->update, + foreign->n_fields))) { + + if (foreign->referenced_table == NULL) { + foreign->referenced_table = + dict_table_open_on_name( + foreign->referenced_table_name_lookup, + FALSE, FALSE, DICT_ERR_IGNORE_NONE); + opened = TRUE; + } + + if (foreign->referenced_table) { + mutex_enter(&(dict_sys->mutex)); + + (foreign->referenced_table + ->n_foreign_key_checks_running)++; + + mutex_exit(&(dict_sys->mutex)); + } + + /* NOTE that if the thread ends up waiting for a lock + we will release dict_operation_lock temporarily! + But the counter on the table protects 'foreign' from + being dropped while the check is running. */ + + err = row_ins_check_foreign_constraint( + TRUE, foreign, table, entry, thr); + + if (foreign->referenced_table) { + mutex_enter(&(dict_sys->mutex)); + + ut_a(foreign->referenced_table + ->n_foreign_key_checks_running > 0); + + (foreign->referenced_table + ->n_foreign_key_checks_running)--; + + if (opened == TRUE) { + dict_table_close(foreign->referenced_table, TRUE, FALSE); + opened = FALSE; + } + + mutex_exit(&(dict_sys->mutex)); + } + + if (err != DB_SUCCESS) { + + goto func_exit; + } + } + + foreign = UT_LIST_GET_NEXT(foreign_list, foreign); + } + + err = DB_SUCCESS; func_exit: if (got_s_lock) { row_mysql_unfreeze_data_dictionary(trx); @@ -299,6 +471,7 @@ func_exit: return(err); } +#endif /* WITH_WSREP */ /*********************************************************************//** Creates an update node for a query graph. @@ -1673,6 +1846,9 @@ row_upd_sec_index_entry( index = node->index; referenced = row_upd_index_is_referenced(index, trx); +#ifdef WITH_WSREP + ibool foreign = wsrep_row_upd_index_is_foreign(index, trx); +#endif /* WITH_WSREP */ heap = mem_heap_create(1024); @@ -1800,6 +1976,9 @@ row_upd_sec_index_entry( row_ins_sec_index_entry() below */ if (!rec_get_deleted_flag( rec, dict_table_is_comp(index->table))) { +#ifdef WITH_WSREP + que_node_t *parent = que_node_get_parent(node); +#endif /* WITH_WSREP */ err = btr_cur_del_mark_set_sec_rec( 0, btr_cur, TRUE, thr, &mtr); @@ -1817,6 +1996,37 @@ row_upd_sec_index_entry( node, &pcur, index->table, index, offsets, thr, &mtr); } +#ifdef WITH_WSREP + if (err == DB_SUCCESS && !referenced && + !(parent && que_node_get_type(parent) == + QUE_NODE_UPDATE && + ((upd_node_t*)parent)->cascade_node == node) && + foreign + ) { + ulint* offsets = + rec_get_offsets( + rec, index, NULL, ULINT_UNDEFINED, + &heap); + err = wsrep_row_upd_check_foreign_constraints( + node, &pcur, index->table, + index, offsets, thr, &mtr); + switch (err) { + case DB_SUCCESS: + case DB_NO_REFERENCED_ROW: + err = DB_SUCCESS; + break; + case DB_DEADLOCK: + if (wsrep_debug) fprintf (stderr, + "WSREP: sec index FK check fail for deadlock"); + break; + default: + fprintf (stderr, + "WSREP: referenced FK check fail: %d", + (int)err); + break; + } + } +#endif /* WITH_WSREP */ } break; } @@ -1971,6 +2181,9 @@ row_upd_clust_rec_by_insert( que_thr_t* thr, /*!< in: query thread */ ibool referenced,/*!< in: TRUE if index may be referenced in a foreign key constraint */ +#ifdef WITH_WSREP + ibool foreign, /*!< in: TRUE if index is foreign key index */ +#endif /* WITH_WSREP */ mtr_t* mtr) /*!< in/out: mtr; gets committed here */ { mem_heap_t* heap; @@ -1984,6 +2197,9 @@ row_upd_clust_rec_by_insert( rec_t* rec; ulint* offsets = NULL; +#ifdef WITH_WSREP + que_node_t *parent = que_node_get_parent(node); +#endif /* WITH_WSREP */ ut_ad(node); ut_ad(dict_index_is_clust(index)); @@ -2066,6 +2282,34 @@ err_exit: goto err_exit; } } +#ifdef WITH_WSREP + if (!referenced && + !(parent && que_node_get_type(parent) == QUE_NODE_UPDATE && + ((upd_node_t*)parent)->cascade_node == node) && + foreign + ) { + err = wsrep_row_upd_check_foreign_constraints( + node, pcur, table, index, offsets, thr, mtr); + switch (err) { + case DB_SUCCESS: + case DB_NO_REFERENCED_ROW: + err = DB_SUCCESS; + break; + case DB_DEADLOCK: + if (wsrep_debug) fprintf (stderr, + "WSREP: insert FK check fail for deadlock"); + break; + default: + fprintf (stderr, + "WSREP: referenced FK check fail: %d", + (int)err); + break; + } + if (err != DB_SUCCESS) { + goto err_exit; + } + } +#endif /* WITH_WSREP */ } mtr_commit(mtr); @@ -2258,11 +2502,18 @@ row_upd_del_mark_clust_rec( ibool referenced, /*!< in: TRUE if index may be referenced in a foreign key constraint */ +#ifdef WITH_WSREP + ibool foreign,/*!< in: TRUE if index is foreign key index */ +#endif /* WITH_WSREP */ mtr_t* mtr) /*!< in: mtr; gets committed here */ { btr_pcur_t* pcur; btr_cur_t* btr_cur; dberr_t err; +#ifdef WITH_WSREP + rec_t* rec; + que_node_t *parent = que_node_get_parent(node); +#endif /* WITH_WSREP */ ut_ad(node); ut_ad(dict_index_is_clust(index)); @@ -2279,8 +2530,16 @@ row_upd_del_mark_clust_rec( /* Mark the clustered index record deleted; we do not have to check locks, because we assume that we have an x-lock on the record */ +#ifdef WITH_WSREP + rec = btr_cur_get_rec(btr_cur); +#endif /* WITH_WSREP */ + err = btr_cur_del_mark_set_clust_rec( +#ifdef WITH_WSREP + btr_cur_get_block(btr_cur), rec, +#else btr_cur_get_block(btr_cur), btr_cur_get_rec(btr_cur), +#endif /* WITH_WSREP */ index, offsets, thr, mtr); if (err == DB_SUCCESS && referenced) { /* NOTE that the following call loses the position of pcur ! */ @@ -2288,6 +2547,32 @@ row_upd_del_mark_clust_rec( err = row_upd_check_references_constraints( node, pcur, index->table, index, offsets, thr, mtr); } +#ifdef WITH_WSREP + if (err == DB_SUCCESS && !referenced && + !(parent && que_node_get_type(parent) == QUE_NODE_UPDATE && + ((upd_node_t*)parent)->cascade_node == node) && + thr_get_trx(thr) && + foreign + ) { + err = wsrep_row_upd_check_foreign_constraints( + node, pcur, index->table, index, offsets, thr, mtr); + switch (err) { + case DB_SUCCESS: + case DB_NO_REFERENCED_ROW: + err = DB_SUCCESS; + break; + case DB_DEADLOCK: + if (wsrep_debug) fprintf (stderr, + "WSREP: clust rec FK check fail for deadlock"); + break; + default: + fprintf (stderr, + "WSREP: clust rec referenced FK check fail: %d", + (int)err); + break; + } + } +#endif /* WITH_WSREP */ mtr_commit(mtr); @@ -2320,6 +2605,10 @@ row_upd_clust_step( index = dict_table_get_first_index(node->table); referenced = row_upd_index_is_referenced(index, thr_get_trx(thr)); +#ifdef WITH_WSREP + ibool foreign = wsrep_row_upd_index_is_foreign( + index, thr_get_trx(thr)); +#endif /* WITH_WSREP */ pcur = node->pcur; @@ -2414,7 +2703,11 @@ row_upd_clust_step( if (node->is_delete) { err = row_upd_del_mark_clust_rec( +#ifdef WITH_WSREP + node, index, offsets, thr, referenced, foreign, &mtr); +#else node, index, offsets, thr, referenced, &mtr); +#endif /* WITH_WSREP */ if (err == DB_SUCCESS) { node->state = UPD_NODE_UPDATE_ALL_SEC; @@ -2459,7 +2752,11 @@ row_upd_clust_step( externally! */ err = row_upd_clust_rec_by_insert( +#ifdef WITH_WSREP + node, index, thr, referenced, foreign, &mtr); +#else node, index, thr, referenced, &mtr); +#endif /* WITH_WSREP */ if (err != DB_SUCCESS) { diff --git a/storage/innobase/srv/srv0conc.cc b/storage/innobase/srv/srv0conc.cc index dc3c0b1dd88..cbf81f8e8f7 100644 --- a/storage/innobase/srv/srv0conc.cc +++ b/storage/innobase/srv/srv0conc.cc @@ -42,6 +42,10 @@ Created 2011/04/18 Sunny Bains #include "trx0trx.h" #include "mysql/plugin.h" +#ifdef WITH_WSREP +extern "C" int wsrep_trx_is_aborting(void *thd_ptr); +extern my_bool wsrep_debug; +#endif /** Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket. */ @@ -86,6 +90,9 @@ struct srv_conc_slot_t{ reserved may still be TRUE at that point */ srv_conc_node_t srv_conc_queue; /*!< queue node */ +#ifdef WITH_WSREP + void *thd; /*!< to see priority */ +#endif }; /** Queue of threads waiting to get in */ @@ -145,6 +152,9 @@ srv_conc_init(void) conc_slot->event = os_event_create(); ut_a(conc_slot->event); +#ifdef WITH_WSREP + conc_slot->thd = NULL; +#endif /* WITH_WSREP */ } #endif /* !HAVE_ATOMIC_BUILTINS */ } @@ -202,6 +212,16 @@ srv_conc_enter_innodb_with_atomics( for (;;) { ulint sleep_in_us; +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd) && + wsrep_trx_is_aborting(trx->mysql_thd)) { + if (wsrep_debug) + fprintf(stderr, + "srv_conc_enter due to MUST_ABORT"); + srv_conc_force_enter_innodb(trx); + return; + } +#endif /* WITH_WSREP */ if (srv_conc.n_active < (lint) srv_thread_concurrency) { ulint n_active; @@ -319,6 +339,9 @@ srv_conc_exit_innodb_without_atomics( slot = NULL; if (srv_conc.n_active < (lint) srv_thread_concurrency) { +#ifdef WITH_WSREP + srv_conc_slot_t* wsrep_slot; +#endif /* Look for a slot where a thread is waiting and no other thread has yet released the thread */ @@ -329,6 +352,19 @@ srv_conc_exit_innodb_without_atomics( /* No op */ } +#ifdef WITH_WSREP + /* look for aborting trx, they must be released asap */ + wsrep_slot= slot; + while (wsrep_slot && (wsrep_slot->wait_ended == TRUE || + !wsrep_trx_is_aborting(wsrep_slot->thd))) { + wsrep_slot = UT_LIST_GET_NEXT(srv_conc_queue, wsrep_slot); + } + if (wsrep_slot) { + slot = wsrep_slot; + if (wsrep_debug) + fprintf(stderr, "WSREP: releasing aborting thd\n"); + } +#endif if (slot != NULL) { slot->wait_ended = TRUE; @@ -384,6 +420,13 @@ retry: return; } +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd) && + wsrep_thd_is_brute_force(trx->mysql_thd)) { + srv_conc_force_enter_innodb(trx); + return; + } +#endif /* If the transaction is not holding resources, let it sleep for srv_thread_sleep_delay microseconds, and try again then */ @@ -450,6 +493,9 @@ retry: /* Add to the queue */ slot->reserved = TRUE; slot->wait_ended = FALSE; +#ifdef WITH_WSREP + slot->thd = trx->mysql_thd; +#endif UT_LIST_ADD_LAST(srv_conc_queue, srv_conc_queue, slot); @@ -457,6 +503,18 @@ retry: srv_conc.n_waiting++; +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd) && + wsrep_trx_is_aborting(trx->mysql_thd)) { + os_fast_mutex_unlock(&srv_conc_mutex); + if (wsrep_debug) + fprintf(stderr, "srv_conc_enter due to MUST_ABORT"); + trx->declared_to_be_inside_innodb = TRUE; + trx->n_tickets_to_enter_innodb = srv_n_free_tickets_to_enter; + return; + } + trx->wsrep_event = slot->event; +#endif /* WITH_WSREP */ os_fast_mutex_unlock(&srv_conc_mutex); /* Go to wait for the event; when a thread leaves InnoDB it will @@ -472,6 +530,9 @@ retry: os_event_wait(slot->event); thd_wait_end(trx->mysql_thd); +#ifdef WITH_WSREP + trx->wsrep_event = NULL; +#endif /* WITH_WSREP */ trx->op_info = ""; @@ -483,6 +544,9 @@ retry: incremented the thread counter on behalf of this thread */ slot->reserved = FALSE; +#ifdef WITH_WSREP + slot->thd = NULL; +#endif UT_LIST_REMOVE(srv_conc_queue, srv_conc_queue, slot); @@ -593,5 +657,32 @@ srv_conc_get_active_threads(void) /*==============================*/ { return(srv_conc.n_active); - } +} + +#ifdef WITH_WSREP +UNIV_INTERN +void +wsrep_srv_conc_cancel_wait( +/*==================*/ + trx_t* trx) /*!< in: transaction object associated with the + thread */ +{ +#ifdef HAVE_ATOMIC_BUILTINS + /* aborting transactions will enter innodb by force in + srv_conc_enter_innodb_with_atomics(). No need to cancel here, + thr will wake up after os_sleep and let to enter innodb + */ + if (wsrep_debug) + fprintf(stderr, "WSREP: conc slot cancel, no atomics\n"); +#else + os_fast_mutex_lock(&srv_conc_mutex); + if (trx->wsrep_event) { + if (wsrep_debug) + fprintf(stderr, "WSREP: conc slot cancel\n"); + os_event_set(trx->wsrep_event); + } + os_fast_mutex_unlock(&srv_conc_mutex); +#endif +} +#endif /* WITH_WSREP */ diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index b9cfb3544b9..ba742c7238c 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -73,6 +73,10 @@ Created 10/8/1995 Heikki Tuuri #include "mysql/service_thd_wait.h" #include "fil0pagecompress.h" +#ifdef WITH_WSREP +extern int wsrep_debug; +extern int wsrep_trx_is_aborting(void *thd_ptr); +#endif /* The following is the maximum allowed duration of a lock wait. */ UNIV_INTERN ulint srv_fatal_semaphore_wait_threshold = 600; @@ -223,6 +227,10 @@ srv_printf_innodb_monitor() will request mutex acquisition with mutex_enter(), which will wait until it gets the mutex. */ #define MUTEX_NOWAIT(mutex_skipped) ((mutex_skipped) < MAX_MUTEX_NOWAIT) +#ifdef WITH_INNODB_DISALLOW_WRITES +UNIV_INTERN os_event_t srv_allow_writes_event; +#endif /* WITH_INNODB_DISALLOW_WRITES */ + /** The sort order table of the MySQL latin1_swedish_ci character set collation */ UNIV_INTERN const byte* srv_latin1_ordering; @@ -1004,6 +1012,14 @@ srv_init(void) dict_ind_init(); srv_conc_init(); +#ifdef WITH_INNODB_DISALLOW_WRITES + /* Writes have to be enabled on init or else we hang. Thus, we + always set the event here regardless of innobase_disallow_writes. + That flag will always be 0 at this point because it isn't settable + via my.cnf or command line arg. */ + srv_allow_writes_event = os_event_create(); + os_event_set(srv_allow_writes_event); +#endif /* WITH_INNODB_DISALLOW_WRITES */ /* Initialize some INFORMATION SCHEMA internal structures */ trx_i_s_cache_init(trx_i_s_cache); @@ -1774,7 +1790,20 @@ loop: if (sync_array_print_long_waits(&waiter, &sema) && sema == old_sema && os_thread_eq(waiter, old_waiter)) { +#if defined(WITH_WSREP) && defined(WITH_INNODB_DISALLOW_WRITES) + if (srv_allow_writes_event->is_set) { +#endif /* WITH_WSREP */ fatal_cnt++; +#if defined(WITH_WSREP) && defined(WITH_INNODB_DISALLOW_WRITES) + } else { + fprintf(stderr, + "WSREP: avoiding InnoDB self crash due to long " + "semaphore wait of > %lu seconds\n" + "Server is processing SST donor operation, " + "fatal_cnt now: %lu", + (ulong) srv_fatal_semaphore_wait_threshold, fatal_cnt); + } +#endif /* WITH_WSREP */ if (fatal_cnt > 10) { fprintf(stderr, diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc index fcf1c1cedf4..4af61d4869b 100644 --- a/storage/innobase/trx/trx0sys.cc +++ b/storage/innobase/trx/trx0sys.cc @@ -44,6 +44,10 @@ Created 3/26/1996 Heikki Tuuri #include "os0file.h" #include "read0read.h" +#ifdef WITH_WSREP +#include "ha_prototypes.h" /* wsrep_is_wsrep_xid() */ +#endif /* */ + /** The file format tag structure with id and name. */ struct file_format_t { ulint id; /*!< id of the file format */ @@ -174,7 +178,12 @@ trx_sys_flush_max_trx_id(void) mtr_t mtr; trx_sysf_t* sys_header; +#ifndef WITH_WSREP + /* wsrep_fake_trx_id violates this assert + * Copied from trx_sys_get_new_trx_id + */ ut_ad(mutex_own(&trx_sys->mutex)); +#endif /* WITH_WSREP */ if (!srv_read_only_mode) { mtr_start(&mtr); @@ -202,9 +211,14 @@ trx_sys_update_mysql_binlog_offset( ib_int64_t offset, /*!< in: position in that log file */ ulint field, /*!< in: offset of the MySQL log info field in the trx sys header */ +#ifdef WITH_WSREP + trx_sysf_t* sys_header, /*!< in: trx sys header */ +#endif /* WITH_WSREP */ mtr_t* mtr) /*!< in: mtr */ { +#ifndef WITH_WSREP trx_sysf_t* sys_header; +#endif /* !WITH_WSREP */ if (ut_strlen(file_name) >= TRX_SYS_MYSQL_LOG_NAME_LEN) { @@ -213,7 +227,9 @@ trx_sys_update_mysql_binlog_offset( return; } +#ifndef WITH_WSREP sys_header = trx_sysf_get(mtr); +#endif /* !WITH_WSREP */ if (mach_read_from_4(sys_header + field + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD) @@ -300,6 +316,124 @@ trx_sys_print_mysql_binlog_offset(void) mtr_commit(&mtr); } +#ifdef WITH_WSREP + +#ifdef UNIV_DEBUG +static long long trx_sys_cur_xid_seqno = -1; +static unsigned char trx_sys_cur_xid_uuid[16]; + +long long read_wsrep_xid_seqno(const XID* xid) +{ + long long seqno; + memcpy(&seqno, xid->data + 24, sizeof(long long)); + return seqno; +} + +void read_wsrep_xid_uuid(const XID* xid, unsigned char* buf) +{ + memcpy(buf, xid->data + 8, 16); +} + +#endif /* UNIV_DEBUG */ + +void +trx_sys_update_wsrep_checkpoint( + const XID* xid, /*!< in: transaction XID */ + trx_sysf_t* sys_header, /*!< in: sys_header */ + mtr_t* mtr) /*!< in: mtr */ +{ +#ifdef UNIV_DEBUG + { + /* Check that seqno is monotonically increasing */ + unsigned char xid_uuid[16]; + long long xid_seqno = read_wsrep_xid_seqno(xid); + read_wsrep_xid_uuid(xid, xid_uuid); + if (!memcmp(xid_uuid, trx_sys_cur_xid_uuid, 8)) + { + ut_ad(xid_seqno > trx_sys_cur_xid_seqno); + trx_sys_cur_xid_seqno = xid_seqno; + } + else + { + memcpy(trx_sys_cur_xid_uuid, xid_uuid, 16); + } + trx_sys_cur_xid_seqno = xid_seqno; + } +#endif /* UNIV_DEBUG */ + + ut_ad(xid && mtr); + ut_a(xid->formatID == -1 || wsrep_is_wsrep_xid(xid)); + + if (mach_read_from_4(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_MAGIC_N_FLD) + != TRX_SYS_WSREP_XID_MAGIC_N) { + mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_MAGIC_N_FLD, + TRX_SYS_WSREP_XID_MAGIC_N, + MLOG_4BYTES, mtr); + } + + mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_FORMAT, + (int)xid->formatID, + MLOG_4BYTES, mtr); + mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_GTRID_LEN, + (int)xid->gtrid_length, + MLOG_4BYTES, mtr); + mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_BQUAL_LEN, + (int)xid->bqual_length, + MLOG_4BYTES, mtr); + mlog_write_string(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_DATA, + (const unsigned char*) xid->data, + XIDDATASIZE, mtr); + +} + +void +trx_sys_read_wsrep_checkpoint(XID* xid) +/*===================================*/ +{ + trx_sysf_t* sys_header; + mtr_t mtr; + ulint magic; + + ut_ad(xid); + + mtr_start(&mtr); + + sys_header = trx_sysf_get(&mtr); + + if ((magic = mach_read_from_4(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_MAGIC_N_FLD)) + != TRX_SYS_WSREP_XID_MAGIC_N) { + memset(xid, 0, sizeof(*xid)); + xid->formatID = -1; + trx_sys_update_wsrep_checkpoint(xid, sys_header, &mtr); + mtr_commit(&mtr); + return; + } + + xid->formatID = (int)mach_read_from_4( + sys_header + + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_FORMAT); + xid->gtrid_length = (int)mach_read_from_4( + sys_header + + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_GTRID_LEN); + xid->bqual_length = (int)mach_read_from_4( + sys_header + + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_BQUAL_LEN); + ut_memcpy(xid->data, + sys_header + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_DATA, + XIDDATASIZE); + + mtr_commit(&mtr); +} + +#endif /* WITH_WSREP */ + /*****************************************************************//** Prints to stderr the MySQL master log offset info in the trx system header if the magic number shows it valid. */ diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index a07167168fc..48073667b2f 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -159,6 +159,9 @@ trx_create(void) trx->lock.table_locks = ib_vector_create( heap_alloc, sizeof(void**), 32); +#ifdef WITH_WSREP + trx->wsrep_event = NULL; +#endif /* WITH_WSREP */ return(trx); } @@ -854,6 +857,11 @@ trx_start_low( srv_undo_logs, srv_undo_tablespaces); } +#ifdef WITH_WSREP + memset(&trx->xid, 0, sizeof(trx->xid)); + trx->xid.formatID = -1; +#endif /* WITH_WSREP */ + /* The initial value for trx->no: TRX_ID_MAX is used in read_view_open_now: */ @@ -968,6 +976,9 @@ trx_write_serialisation_history( trx_t* trx, /*!< in/out: transaction */ mtr_t* mtr) /*!< in/out: mini-transaction */ { +#ifdef WITH_WSREP + trx_sysf_t* sys_header; +#endif /* WITH_WSREP */ trx_rseg_t* rseg; rseg = trx->rseg; @@ -1014,6 +1025,15 @@ trx_write_serialisation_history( MONITOR_INC(MONITOR_TRX_COMMIT_UNDO); +#ifdef WITH_WSREP + sys_header = trx_sysf_get(mtr); + /* Update latest MySQL wsrep XID in trx sys header. */ + if (wsrep_is_wsrep_xid((const void *)&trx->xid)) + { + trx_sys_update_wsrep_checkpoint(&trx->xid, sys_header, mtr); + } +#endif /* WITH_WSREP */ + /* Update the latest MySQL binlog name and offset info in trx sys header if MySQL binlogging is on or the database server is a MySQL replication slave */ @@ -1024,7 +1044,11 @@ trx_write_serialisation_history( trx_sys_update_mysql_binlog_offset( trx->mysql_log_file_name, trx->mysql_log_offset, - TRX_SYS_MYSQL_LOG_INFO, mtr); + TRX_SYS_MYSQL_LOG_INFO, +#ifdef WITH_WSREP + sys_header, +#endif /* WITH_WSREP */ + mtr); trx->mysql_log_file_name = NULL; } @@ -1312,6 +1336,11 @@ trx_commit_in_memory( ut_ad(!trx->in_ro_trx_list); ut_ad(!trx->in_rw_trx_list); +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd)) { + trx->lock.was_chosen_as_deadlock_victim = FALSE; + } +#endif trx->dict_operation = TRX_DICT_OP_NONE; trx->error_state = DB_SUCCESS; @@ -1496,6 +1525,10 @@ trx_commit_or_rollback_prepare( switch (trx->state) { case TRX_STATE_NOT_STARTED: +#ifdef WITH_WSREP + ut_d(trx->start_file = __FILE__); + ut_d(trx->start_line = __LINE__); +#endif /* WITH_WSREP */ trx_start_low(trx); /* fall through */ case TRX_STATE_ACTIVE: diff --git a/storage/innobase/wsrep/md5.cc b/storage/innobase/wsrep/md5.cc new file mode 100644 index 00000000000..30be6ab7dd3 --- /dev/null +++ b/storage/innobase/wsrep/md5.cc @@ -0,0 +1,74 @@ +/* + Copyright (c) 2014 SkySQL AB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifdef WITH_WSREP + +#if defined(HAVE_YASSL) +#include "my_config.h" +#include "md5.hpp" +#elif defined(HAVE_OPENSSL) +#include +#endif /* HAVE_YASSL */ + +/* Initialize md5 object. */ +void *wsrep_md5_init() +{ +#if defined(HAVE_YASSL) + TaoCrypt::MD5 *hasher= new TaoCrypt::MD5; + return (void*)hasher; +#elif defined(HAVE_OPENSSL) + MD5_CTX *ctx = new MD5_CTX(); + MD5_Init (ctx); + return (void *)ctx; +#endif /* HAVE_YASSL */ +} + +/** + Supply message to be hashed. + + @param ctx [IN] Pointer to MD5 context + @param buf [IN] Message to be computed. + @param len [IN] Length of the message. +*/ +void wsrep_md5_update(void *ctx, char* buf, int len) +{ +#if defined(HAVE_YASSL) + ((TaoCrypt::MD5 *)ctx)->Update((TaoCrypt::byte *) buf, len); +#elif defined(HAVE_OPENSSL) + MD5_Update((MD5_CTX*)(ctx), buf, len); +#endif /* HAVE_YASSL */ +} + +/** + Place computed MD5 digest into the given buffer. + + @param digest [OUT] Computed MD5 digest + @param ctx [IN] Pointer to MD5 context +*/ +void wsrep_compute_md5_hash(char *digest, void *ctx) +{ +#if defined(HAVE_YASSL) + ((TaoCrypt::MD5*)ctx)->Final((TaoCrypt::byte *) digest); + delete (TaoCrypt::MD5*)ctx; +#elif defined(HAVE_OPENSSL) + MD5_Final ((unsigned char*)digest, (MD5_CTX*)ctx); + delete (MD5_CTX*)ctx; +#endif /* HAVE_YASSL */ +} + +#endif /* WITH_WSREP */ + diff --git a/storage/innobase/wsrep/wsrep_md5.h b/storage/innobase/wsrep/wsrep_md5.h new file mode 100644 index 00000000000..1339f7f4b86 --- /dev/null +++ b/storage/innobase/wsrep/wsrep_md5.h @@ -0,0 +1,26 @@ +#ifndef WSREP_MD5_INCLUDED +#define WSREP_MD5_INCLUDED + +/* Copyright (c) 2014 SkySQL AB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +*/ + +#ifdef WITH_WSREP +void *wsrep_md5_init(); +void wsrep_md5_update(void *ctx, char* buf, int len); +void wsrep_compute_md5_hash(char *digest, void *ctx); +#endif /* WITH_WSREP */ + +#endif /* WSREP_MD5_INCLUDED */ diff --git a/storage/perfschema/CMakeLists.txt b/storage/perfschema/CMakeLists.txt index 718baa8296b..aaa1142a180 100644 --- a/storage/perfschema/CMakeLists.txt +++ b/storage/perfschema/CMakeLists.txt @@ -13,6 +13,10 @@ # along with this program; if not, write to the Free Software Foundation, # 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA +IF (WITH_WSREP) + BUILD_WITH_WSREP() +ENDIF() + INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/sql diff --git a/storage/xtradb/CMakeLists.txt b/storage/xtradb/CMakeLists.txt index 528c6f87fcc..6d9bd1a500a 100644 --- a/storage/xtradb/CMakeLists.txt +++ b/storage/xtradb/CMakeLists.txt @@ -268,6 +268,27 @@ ENDIF() INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/storage/xtradb/include ${CMAKE_SOURCE_DIR}/storage/xtradb/handler) +IF(WITH_WSREP) + # ssl include directory + INCLUDE_DIRECTORIES(${SSL_INCLUDE_DIRS} + ${CMAKE_SOURCE_DIR}/storage/xtradb/wsrep) + + IF(SSL_DEFINES) + ADD_DEFINITIONS(${SSL_DEFINES}) + ENDIF() + + LINK_LIBRARIES(${SSL_LIBRARIES}) + + # We do RESTRICT_SYMBOL_EXPORTS(yassl) elsewhere. + # In order to get correct symbol visibility, these files + # must be compiled with "-fvisibility=hidden" + IF(WITH_SSL STREQUAL "bundled" AND HAVE_VISIBILITY_HIDDEN) + SET_SOURCE_FILES_PROPERTIES( + {CMAKE_CURRENT_SOURCE_DIR}/wsrep/md5.cc + PROPERTIES COMPILE_FLAGS "-fvisibility=hidden") + ENDIF() +ENDIF() + # Sun Studio bug with -xO2 IF(CMAKE_CXX_COMPILER_ID MATCHES "SunPro" AND CMAKE_CXX_FLAGS_RELEASE MATCHES "O2" @@ -407,6 +428,10 @@ SET(INNOBASE_SOURCES ut/ut0vec.cc ut/ut0wqueue.cc) +IF(WITH_WSREP) + SET(INNOBASE_SOURCES ${INNOBASE_SOURCES} wsrep/md5.cc) +ENDIF() + IF(NOT XTRADB_OK) MESSAGE(FATAL_ERROR "Percona XtraDB is not supported on this platform") ENDIF() diff --git a/storage/xtradb/dict/dict0dict.cc b/storage/xtradb/dict/dict0dict.cc index af3518337d4..c340590b4bb 100644 --- a/storage/xtradb/dict/dict0dict.cc +++ b/storage/xtradb/dict/dict0dict.cc @@ -3241,7 +3241,29 @@ dict_foreign_find_index( return(NULL); } - +#ifdef WITH_WSREP +dict_index_t* +wsrep_dict_foreign_find_index( +/*====================*/ + dict_table_t* table, /*!< in: table */ + const char** col_names, /*!< in: column names, or NULL + to use table->col_names */ + const char** columns,/*!< in: array of column names */ + ulint n_cols, /*!< in: number of columns */ + dict_index_t* types_idx, /*!< in: NULL or an index to whose types the + column types must match */ + ibool check_charsets, + /*!< in: whether to check charsets. + only has an effect if types_idx != NULL */ + ulint check_null) + /*!< in: nonzero if none of the columns must + be declared NOT NULL */ +{ + return dict_foreign_find_index( + table, col_names, columns, n_cols, types_idx, check_charsets, + check_null); +} +#endif /* WITH_WSREP */ /**********************************************************************//** Report an error in a foreign key definition. */ static diff --git a/storage/xtradb/fil/fil0fil.cc b/storage/xtradb/fil/fil0fil.cc index d40cfa57bd5..343cc0f47c4 100644 --- a/storage/xtradb/fil/fil0fil.cc +++ b/storage/xtradb/fil/fil0fil.cc @@ -6833,36 +6833,36 @@ fil_get_page_type_name( { switch(page_type) { case FIL_PAGE_PAGE_COMPRESSED: - return "PAGE_COMPRESSED"; + return (char *)"PAGE_COMPRESSED"; case FIL_PAGE_INDEX: - return "INDEX"; + return (char *)"INDEX"; case FIL_PAGE_UNDO_LOG: - return "UNDO LOG"; + return (char *)"UNDO LOG"; case FIL_PAGE_INODE: - return "INODE"; + return (char *)"INODE"; case FIL_PAGE_IBUF_FREE_LIST: - return "IBUF_FREE_LIST"; + return (char *)"IBUF_FREE_LIST"; case FIL_PAGE_TYPE_ALLOCATED: - return "ALLOCATED"; + return (char *)"ALLOCATED"; case FIL_PAGE_IBUF_BITMAP: - return "IBUF_BITMAP"; + return (char *)"IBUF_BITMAP"; case FIL_PAGE_TYPE_SYS: - return "SYS"; + return (char *)"SYS"; case FIL_PAGE_TYPE_TRX_SYS: - return "TRX_SYS"; + return (char *)"TRX_SYS"; case FIL_PAGE_TYPE_FSP_HDR: - return "FSP_HDR"; + return (char *)"FSP_HDR"; case FIL_PAGE_TYPE_XDES: - return "XDES"; + return (char *)"XDES"; case FIL_PAGE_TYPE_BLOB: - return "BLOB"; + return (char *)"BLOB"; case FIL_PAGE_TYPE_ZBLOB: - return "ZBLOB"; + return (char *)"ZBLOB"; case FIL_PAGE_TYPE_ZBLOB2: - return "ZBLOB2"; + return (char *)"ZBLOB2"; case FIL_PAGE_TYPE_COMPRESSED: - return "ORACLE PAGE COMPRESSED"; + return (char *)"ORACLE PAGE COMPRESSED"; default: - return "PAGE TYPE CORRUPTED"; + return (char *)"PAGE TYPE CORRUPTED"; } } diff --git a/storage/xtradb/fil/fil0pagecompress.cc b/storage/xtradb/fil/fil0pagecompress.cc index 854b094ea81..ec19a4ef4b7 100644 --- a/storage/xtradb/fil/fil0pagecompress.cc +++ b/storage/xtradb/fil/fil0pagecompress.cc @@ -487,7 +487,9 @@ fil_decompress_page( ulint actual_size = 0; ulint compression_alg = 0; byte *in_buf; +#ifdef HAVE_LZO ulint olen=0; +#endif ulint ptype; ut_ad(buf); diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index fb3e097491d..73834705232 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -120,6 +120,44 @@ this program; if not, write to the Free Software Foundation, Inc., # define MYSQL_PLUGIN_IMPORT /* nothing */ # endif /* MYSQL_PLUGIN_IMPORT */ +#ifdef WITH_WSREP +#include "dict0priv.h" +#include "../storage/innobase/include/ut0byte.h" +#include +#include + +extern my_bool wsrep_certify_nonPK; +class binlog_trx_data; +extern handlerton *binlog_hton; + +extern MYSQL_PLUGIN_IMPORT mysql_mutex_t LOCK_wsrep_rollback; +extern MYSQL_PLUGIN_IMPORT mysql_cond_t COND_wsrep_rollback; +extern MYSQL_PLUGIN_IMPORT wsrep_aborting_thd_t wsrep_aborting_thd; + +static inline wsrep_ws_handle_t* +wsrep_ws_handle(THD* thd, const trx_t* trx) { + return wsrep_ws_handle_for_trx(wsrep_thd_ws_handle(thd), + (wsrep_trx_id_t)trx->id); +} + +extern bool wsrep_prepare_key_for_innodb(const uchar *cache_key, + size_t cache_key_len, + const uchar* row_id, + size_t row_id_len, + wsrep_buf_t* key, + size_t* key_len); + +extern handlerton * wsrep_hton; +extern TC_LOG* tc_log; +extern void wsrep_cleanup_transaction(THD *thd); +static int +wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd, + my_bool signal); +static void +wsrep_fake_trx_id(handlerton* hton, THD *thd); +static int innobase_wsrep_set_checkpoint(handlerton* hton, const XID* xid); +static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid); +#endif /* WITH_WSREP */ /** to protect innobase_open_files */ static mysql_mutex_t innobase_share_mutex; /** to force correct commit order in binlog */ @@ -1483,6 +1521,10 @@ innobase_srv_conc_enter_innodb( /*===========================*/ trx_t* trx) /*!< in: transaction handle */ { +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd) && + wsrep_thd_is_BF(trx->mysql_thd, FALSE)) return; +#endif /* WITH_WSREP */ if (srv_thread_concurrency) { if (trx->n_tickets_to_enter_innodb > 0) { @@ -1517,6 +1559,10 @@ innobase_srv_conc_exit_innodb( #ifdef UNIV_SYNC_DEBUG ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch)); #endif /* UNIV_SYNC_DEBUG */ +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd) && + wsrep_thd_is_BF(trx->mysql_thd, FALSE)) return; +#endif /* WITH_WSREP */ /* This is to avoid making an unnecessary function call. */ if (trx->declared_to_be_inside_innodb @@ -1649,6 +1695,16 @@ thd_to_trx( return(*(trx_t**) thd_ha_data(thd, innodb_hton_ptr)); } +#ifdef WITH_WSREP +ulonglong +thd_to_trx_id( +/*=======*/ + THD* thd) /*!< in: MySQL thread */ +{ + return(thd_to_trx(thd)->id); +} +#endif /* WITH_WSREP */ + my_bool ha_innobase::is_fake_change_enabled(THD* thd) { @@ -2149,6 +2205,9 @@ int innobase_mysql_tmpfile(void) /*========================*/ { +#ifdef WITH_INNODB_DISALLOW_WRITES + os_event_wait(srv_allow_writes_event); +#endif /* WITH_INNODB_DISALLOW_WRITES */ int fd2 = -1; File fd; @@ -3313,6 +3372,12 @@ innobase_init( innobase_hton->tablefile_extensions = ha_innobase_exts; innobase_hton->table_options = innodb_table_option_list; +#ifdef WITH_WSREP + innobase_hton->wsrep_abort_transaction=wsrep_abort_transaction; + innobase_hton->wsrep_set_checkpoint=innobase_wsrep_set_checkpoint; + innobase_hton->wsrep_get_checkpoint=innobase_wsrep_get_checkpoint; + innobase_hton->wsrep_fake_trx_id=wsrep_fake_trx_id; +#endif /* WITH_WSREP */ ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR); @@ -4050,10 +4115,30 @@ innobase_commit_low( /*================*/ trx_t* trx) /*!< in: transaction handle */ { +#ifdef WITH_WSREP + THD* thd = (THD*)trx->mysql_thd; + const char* tmp = 0; + if (wsrep_on((void*)thd)) { +#ifdef WSREP_PROC_INFO + char info[64]; + info[sizeof(info) - 1] = '\0'; + snprintf(info, sizeof(info) - 1, + "innobase_commit_low():trx_commit_for_mysql(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); + tmp = thd_proc_info(thd, info); + +#else + tmp = thd_proc_info(thd, "innobase_commit_low()"); +#endif /* WSREP_PROC_INFO */ + } +#endif /* WITH_WSREP */ if (trx_is_started(trx)) { trx_commit_for_mysql(trx); } +#ifdef WITH_WSREP + if (wsrep_on((void*)thd)) { thd_proc_info(thd, tmp); } +#endif /* WITH_WSREP */ } /*****************************************************************//** @@ -4828,22 +4913,32 @@ innobase_kill_connection( DBUG_ENTER("innobase_kill_connection"); DBUG_ASSERT(hton == innodb_hton_ptr); - lock_mutex_enter(); - +#ifdef WITH_WSREP + wsrep_thd_LOCK(thd); + if (wsrep_thd_conflict_state(thd) != NO_CONFLICT) { + /* if victim has been signaled by BF thread and/or aborting + is already progressing, following query aborting is not necessary + any more. + Also, BF thread should own trx mutex for the victim, which would + conflict with trx_mutex_enter() below + */ + wsrep_thd_UNLOCK(thd); + DBUG_VOID_RETURN; + } + wsrep_thd_UNLOCK(thd); +#endif /* WITH_WSREP */ trx = thd_to_trx(thd); if (trx) { - trx_mutex_enter(trx); - - /* Cancel a pending lock request. */ - if (trx->lock.wait_lock) - lock_cancel_waiting_and_release(trx->lock.wait_lock); - - trx_mutex_exit(trx); - } - - lock_mutex_exit(); + /* Cancel a pending lock request. */ + lock_mutex_enter(); + trx_mutex_enter(trx); + if (trx->lock.wait_lock) + lock_cancel_waiting_and_release(trx->lock.wait_lock); + trx_mutex_exit(trx); + lock_mutex_exit(); + } DBUG_VOID_RETURN; } @@ -4956,7 +5051,11 @@ ha_innobase::max_supported_key_length() const case 8192: return(1536); default: +#ifdef WITH_WSREP return(3500); +#else + return(3500); +#endif } } @@ -6072,6 +6171,117 @@ get_field_offset( return((uint) (field->ptr - table->record[0])); } +#ifdef WITH_WSREP +UNIV_INTERN +int +wsrep_innobase_mysql_sort( +/*===============*/ + /* out: str contains sort string */ + int mysql_type, /* in: MySQL type */ + uint charset_number, /* in: number of the charset */ + unsigned char* str, /* in: data field */ + unsigned int str_length, /* in: data field length, + not UNIV_SQL_NULL */ + unsigned int buf_length) /* in: total str buffer length */ + +{ + CHARSET_INFO* charset; + enum_field_types mysql_tp; + int ret_length = str_length; + + DBUG_ASSERT(str_length != UNIV_SQL_NULL); + + mysql_tp = (enum_field_types) mysql_type; + + switch (mysql_tp) { + + case MYSQL_TYPE_BIT: + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_VARCHAR: + { + uchar tmp_str[REC_VERSION_56_MAX_INDEX_COL_LEN]; + uint tmp_length = REC_VERSION_56_MAX_INDEX_COL_LEN; + + /* Use the charset number to pick the right charset struct for + the comparison. Since the MySQL function get_charset may be + slow before Bar removes the mutex operation there, we first + look at 2 common charsets directly. */ + + if (charset_number == default_charset_info->number) { + charset = default_charset_info; + } else if (charset_number == my_charset_latin1.number) { + charset = &my_charset_latin1; + } else { + charset = get_charset(charset_number, MYF(MY_WME)); + + if (charset == NULL) { + sql_print_error("InnoDB needs charset %lu for doing " + "a comparison, but MySQL cannot " + "find that charset.", + (ulong) charset_number); + ut_a(0); + } + } + + ut_a(str_length <= tmp_length); + memcpy(tmp_str, str, str_length); + + tmp_length = charset->coll->strnxfrm(charset, str, str_length, + str_length, tmp_str, + tmp_length, 0); + DBUG_ASSERT(tmp_length <= str_length); + if (wsrep_protocol_version < 3) { + tmp_length = charset->coll->strnxfrm( + charset, str, str_length, + str_length, tmp_str, tmp_length, 0); + DBUG_ASSERT(tmp_length <= str_length); + } else { + /* strnxfrm will expand the destination string, + protocols < 3 truncated the sorted sring + protocols > 3 gets full sorted sring + */ + tmp_length = charset->coll->strnxfrm( + charset, str, buf_length, + str_length, tmp_str, tmp_length, 0); + DBUG_ASSERT(tmp_length <= buf_length); + ret_length = tmp_length; + } + + break; + } + case MYSQL_TYPE_DECIMAL : + case MYSQL_TYPE_TINY : + case MYSQL_TYPE_SHORT : + case MYSQL_TYPE_LONG : + case MYSQL_TYPE_FLOAT : + case MYSQL_TYPE_DOUBLE : + case MYSQL_TYPE_NULL : + case MYSQL_TYPE_TIMESTAMP : + case MYSQL_TYPE_LONGLONG : + case MYSQL_TYPE_INT24 : + case MYSQL_TYPE_DATE : + case MYSQL_TYPE_TIME : + case MYSQL_TYPE_DATETIME : + case MYSQL_TYPE_YEAR : + case MYSQL_TYPE_NEWDATE : + case MYSQL_TYPE_NEWDECIMAL : + case MYSQL_TYPE_ENUM : + case MYSQL_TYPE_SET : + case MYSQL_TYPE_GEOMETRY : + break; + default: + break; + } + + return ret_length; +} +#endif /* WITH_WSREP */ + /*************************************************************//** InnoDB uses this function to compare two data fields for which the data type is such that we must use MySQL code to compare them. NOTE that the prototype @@ -6572,6 +6782,260 @@ innobase_read_from_2_little_endian( return((uint) ((ulint)(buf[0]) + 256 * ((ulint)(buf[1])))); } +/*******************************************************************//** +Stores a key value for a row to a buffer. +@return key value length as stored in buff */ +#ifdef WITH_WSREP +UNIV_INTERN +uint +wsrep_store_key_val_for_row( +/*===============================*/ + TABLE* table, + uint keynr, /*!< in: key number */ + char* buff, /*!< in/out: buffer for the key value (in MySQL + format) */ + uint buff_len,/*!< in: buffer length */ + const uchar* record, + ibool* key_is_null)/*!< out: full key was null */ +{ + KEY* key_info = table->key_info + keynr; + KEY_PART_INFO* key_part = key_info->key_part; + KEY_PART_INFO* end = key_part + key_info->user_defined_key_parts; + char* buff_start = buff; + enum_field_types mysql_type; + Field* field; + + DBUG_ENTER("wsrep_store_key_val_for_row"); + + memset(buff, 0, buff_len); + *key_is_null = TRUE; + + for (; key_part != end; key_part++) { + uchar sorted[REC_VERSION_56_MAX_INDEX_COL_LEN] = {'\0'}; + ibool part_is_null = FALSE; + + if (key_part->null_bit) { + if (record[key_part->null_offset] & + key_part->null_bit) { + *buff = 1; + part_is_null = TRUE; + } else { + *buff = 0; + } + buff++; + } + if (!part_is_null) *key_is_null = FALSE; + + field = key_part->field; + mysql_type = field->type(); + + if (mysql_type == MYSQL_TYPE_VARCHAR) { + /* >= 5.0.3 true VARCHAR */ + ulint lenlen; + ulint len; + const byte* data; + ulint key_len; + ulint true_len; + const CHARSET_INFO* cs; + int error=0; + + key_len = key_part->length; + + if (part_is_null) { + buff += key_len + 2; + + continue; + } + cs = field->charset(); + + lenlen = (ulint) + (((Field_varstring*)field)->length_bytes); + + data = row_mysql_read_true_varchar(&len, + (byte*) (record + + (ulint)get_field_offset(table, field)), + lenlen); + + true_len = len; + + /* For multi byte character sets we need to calculate + the true length of the key */ + + if (len > 0 && cs->mbmaxlen > 1) { + true_len = (ulint) cs->cset->well_formed_len(cs, + (const char *) data, + (const char *) data + len, + (uint) (key_len / + cs->mbmaxlen), + &error); + } + + /* In a column prefix index, we may need to truncate + the stored value: */ + + if (true_len > key_len) { + true_len = key_len; + } + + memcpy(sorted, data, true_len); + true_len = wsrep_innobase_mysql_sort( + mysql_type, cs->number, sorted, true_len, + REC_VERSION_56_MAX_INDEX_COL_LEN); + + if (wsrep_protocol_version > 1) { + memcpy(buff, sorted, true_len); + /* Note that we always reserve the maximum possible + length of the true VARCHAR in the key value, though + only len first bytes after the 2 length bytes contain + actual data. The rest of the space was reset to zero + in the bzero() call above. */ + buff += true_len; + } else { + buff += key_len; + } + } else if (mysql_type == MYSQL_TYPE_TINY_BLOB + || mysql_type == MYSQL_TYPE_MEDIUM_BLOB + || mysql_type == MYSQL_TYPE_BLOB + || mysql_type == MYSQL_TYPE_LONG_BLOB + /* MYSQL_TYPE_GEOMETRY data is treated + as BLOB data in innodb. */ + || mysql_type == MYSQL_TYPE_GEOMETRY) { + + const CHARSET_INFO* cs; + ulint key_len; + ulint true_len; + int error=0; + ulint blob_len; + const byte* blob_data; + + ut_a(key_part->key_part_flag & HA_PART_KEY_SEG); + + key_len = key_part->length; + + if (part_is_null) { + buff += key_len + 2; + + continue; + } + + cs = field->charset(); + + blob_data = row_mysql_read_blob_ref(&blob_len, + (byte*) (record + + (ulint)get_field_offset(table, field)), + (ulint) field->pack_length()); + + true_len = blob_len; + + ut_a(get_field_offset(table, field) + == key_part->offset); + + /* For multi byte character sets we need to calculate + the true length of the key */ + + if (blob_len > 0 && cs->mbmaxlen > 1) { + true_len = (ulint) cs->cset->well_formed_len(cs, + (const char *) blob_data, + (const char *) blob_data + + blob_len, + (uint) (key_len / + cs->mbmaxlen), + &error); + } + + /* All indexes on BLOB and TEXT are column prefix + indexes, and we may need to truncate the data to be + stored in the key value: */ + + if (true_len > key_len) { + true_len = key_len; + } + + memcpy(sorted, blob_data, true_len); + true_len = wsrep_innobase_mysql_sort( + mysql_type, cs->number, sorted, true_len, + REC_VERSION_56_MAX_INDEX_COL_LEN); + + memcpy(buff, sorted, true_len); + + /* Note that we always reserve the maximum possible + length of the BLOB prefix in the key value. */ + if (wsrep_protocol_version > 1) { + buff += true_len; + } else { + buff += key_len; + } + } else { + /* Here we handle all other data types except the + true VARCHAR, BLOB and TEXT. Note that the column + value we store may be also in a column prefix + index. */ + + const CHARSET_INFO* cs = NULL; + ulint true_len; + ulint key_len; + const uchar* src_start; + int error=0; + enum_field_types real_type; + + key_len = key_part->length; + + if (part_is_null) { + buff += key_len; + + continue; + } + + src_start = record + key_part->offset; + real_type = field->real_type(); + true_len = key_len; + + /* Character set for the field is defined only + to fields whose type is string and real field + type is not enum or set. For these fields check + if character set is multi byte. */ + + if (real_type != MYSQL_TYPE_ENUM + && real_type != MYSQL_TYPE_SET + && ( mysql_type == MYSQL_TYPE_VAR_STRING + || mysql_type == MYSQL_TYPE_STRING)) { + + cs = field->charset(); + + /* For multi byte character sets we need to + calculate the true length of the key */ + + if (key_len > 0 && cs->mbmaxlen > 1) { + + true_len = (ulint) + cs->cset->well_formed_len(cs, + (const char *)src_start, + (const char *)src_start + + key_len, + (uint) (key_len / + cs->mbmaxlen), + &error); + } + memcpy(sorted, src_start, true_len); + true_len = wsrep_innobase_mysql_sort( + mysql_type, cs->number, sorted, true_len, + REC_VERSION_56_MAX_INDEX_COL_LEN); + + memcpy(buff, sorted, true_len); + } else { + memcpy(buff, src_start, true_len); + } + buff += true_len; + + } + } + + ut_a(buff <= buff_start + buff_len); + + DBUG_RETURN((uint)(buff - buff_start)); +} +#endif /* WITH_WSREP */ + /*******************************************************************//** Stores a key value for a row to a buffer. @return key value length as stored in buff */ @@ -7419,6 +7883,9 @@ ha_innobase::write_row( ibool auto_inc_used= FALSE; ulint sql_command; trx_t* trx = thd_to_trx(user_thd); +#ifdef WITH_WSREP + ibool auto_inc_inserted= FALSE; /* if NULL was inserted */ +#endif DBUG_ENTER("ha_innobase::write_row"); @@ -7454,8 +7921,18 @@ ha_innobase::write_row( if ((sql_command == SQLCOM_ALTER_TABLE || sql_command == SQLCOM_OPTIMIZE || sql_command == SQLCOM_CREATE_INDEX +#ifdef WITH_WSREP + || (wsrep_on(user_thd) && wsrep_load_data_splitting && + sql_command == SQLCOM_LOAD) +#endif /* WITH_WSREP */ || sql_command == SQLCOM_DROP_INDEX) && num_write_row >= 10000) { +#ifdef WITH_WSREP + if (wsrep_on(user_thd) && sql_command == SQLCOM_LOAD) { + WSREP_DEBUG("forced trx split for LOAD: %s", + wsrep_thd_query(user_thd)); + } +#endif /* WITH_WSREP */ /* ALTER TABLE is COMMITted at every 10000 copied rows. The IX table lock for the original table has to be re-issued. As this method will be called on a temporary table where the @@ -7489,6 +7966,21 @@ no_commit: */ ; } else if (src_table == prebuilt->table) { +#ifdef WITH_WSREP + switch (wsrep_run_wsrep_commit(user_thd, wsrep_hton, 1)) + { + case WSREP_TRX_OK: + break; + case WSREP_TRX_SIZE_EXCEEDED: + case WSREP_TRX_CERT_FAIL: + case WSREP_TRX_ERROR: + DBUG_RETURN(1); + } + + if (binlog_hton->commit(binlog_hton, user_thd, 1)) + DBUG_RETURN(1); + wsrep_post_commit(user_thd, TRUE); +#endif /* WITH_WSREP */ /* Source table is not in InnoDB format: no need to re-acquire locks on it. */ @@ -7499,6 +7991,21 @@ no_commit: /* We will need an IX lock on the destination table. */ prebuilt->sql_stat_start = TRUE; } else { +#ifdef WITH_WSREP + switch (wsrep_run_wsrep_commit(user_thd, wsrep_hton, 1)) + { + case WSREP_TRX_OK: + break; + case WSREP_TRX_SIZE_EXCEEDED: + case WSREP_TRX_CERT_FAIL: + case WSREP_TRX_ERROR: + DBUG_RETURN(1); + } + + if (binlog_hton->commit(binlog_hton, user_thd, 1)) + DBUG_RETURN(1); + wsrep_post_commit(user_thd, TRUE); +#endif /* WITH_WSREP */ /* Ensure that there are no other table locks than LOCK_IX and LOCK_AUTO_INC on the destination table. */ @@ -7528,6 +8035,10 @@ no_commit: innobase_get_auto_increment(). */ prebuilt->autoinc_error = DB_SUCCESS; +#ifdef WITH_WSREP + auto_inc_inserted= (table->next_number_field->val_int() == 0); +#endif + if ((error_result = update_auto_increment())) { /* We don't want to mask autoinc overflow errors. */ @@ -7615,6 +8126,32 @@ no_commit: case SQLCOM_REPLACE_SELECT: goto set_max_autoinc; +#ifdef WITH_WSREP + /* workaround for LP bug #355000, retrying the insert */ + case SQLCOM_INSERT: + if (wsrep_on(current_thd) && + auto_inc_inserted && + wsrep_drupal_282555_workaround && + wsrep_thd_retry_counter(current_thd) == 0 && + !thd_test_options(current_thd, + OPTION_NOT_AUTOCOMMIT | + OPTION_BEGIN)) { + WSREP_DEBUG( + "retrying insert: %s", + (*wsrep_thd_query(current_thd)) ? + wsrep_thd_query(current_thd) : + (char *)"void"); + error= DB_SUCCESS; + wsrep_thd_set_conflict_state( + current_thd, MUST_ABORT); + innobase_srv_conc_exit_innodb(prebuilt->trx); + /* jump straight to func exit over + * later wsrep hooks */ + goto func_exit; + } + break; +#endif /* WITH_WSREP */ + default: break; } @@ -7674,6 +8211,21 @@ report_error: prebuilt->table->flags, user_thd); +#ifdef WITH_WSREP + if (!error_result && wsrep_thd_exec_mode(user_thd) == LOCAL_STATE && + wsrep_on(user_thd) && !wsrep_consistency_check(user_thd) && + (sql_command != SQLCOM_LOAD || + thd_binlog_format(user_thd) == BINLOG_FORMAT_ROW)) { + + if (wsrep_append_keys(user_thd, false, record, NULL)) { + DBUG_PRINT("wsrep", ("row key failed")); + error_result = HA_ERR_INTERNAL_ERROR; + goto wsrep_error; + } + } +wsrep_error: +#endif /* WITH_WSREP */ + if (error_result == HA_FTS_INVALID_DOCID) { my_error(HA_FTS_INVALID_DOCID, MYF(0)); } @@ -7963,6 +8515,87 @@ calc_row_difference( return(DB_SUCCESS); } +#ifdef WITH_WSREP +static +int +wsrep_calc_row_hash( +/*================*/ + byte* digest, /*!< in/out: md5 sum */ + const uchar* row, /*!< in: row in MySQL format */ + TABLE* table, /*!< in: table in MySQL data + dictionary */ + row_prebuilt_t* prebuilt, /*!< in: InnoDB prebuilt struct */ + THD* thd) /*!< in: user thread */ +{ + Field* field; + enum_field_types field_mysql_type; + uint n_fields; + ulint len; + const byte* ptr; + ulint col_type; + uint i; + + void *ctx = wsrep_md5_init(); + + n_fields = table->s->fields; + + for (i = 0; i < n_fields; i++) { + byte null_byte=0; + byte true_byte=1; + + field = table->field[i]; + + ptr = (const byte*) row + get_field_offset(table, field); + len = field->pack_length(); + + field_mysql_type = field->type(); + + col_type = prebuilt->table->cols[i].mtype; + + switch (col_type) { + + case DATA_BLOB: + ptr = row_mysql_read_blob_ref(&len, ptr, len); + + break; + + case DATA_VARCHAR: + case DATA_BINARY: + case DATA_VARMYSQL: + if (field_mysql_type == MYSQL_TYPE_VARCHAR) { + /* This is a >= 5.0.3 type true VARCHAR where + the real payload data length is stored in + 1 or 2 bytes */ + + ptr = row_mysql_read_true_varchar( + &len, ptr, + (ulint) + (((Field_varstring*)field)->length_bytes)); + + } + + break; + default: + ; + } + /* + if (field->null_ptr && + field_in_record_is_null(table, field, (char*) row)) { + */ + + if (field->is_null_in_record(row)) { + wsrep_md5_update(ctx, (char*)&null_byte, 1); + } else { + wsrep_md5_update(ctx, (char*)&true_byte, 1); + wsrep_md5_update(ctx, (char*)ptr, len); + } + } + + wsrep_compute_md5_hash((char*)digest, ctx); + + return(0); +} +#endif /* WITH_WSREP */ /**********************************************************************//** Updates a row given as a parameter to a new value. Note that we are given whole rows, not just the fields which are updated: this incurs some @@ -8109,6 +8742,23 @@ func_exit: innobase_active_small(); +#ifdef WITH_WSREP + if (error == DB_SUCCESS && + wsrep_thd_exec_mode(user_thd) == LOCAL_STATE && + wsrep_on(user_thd)) { + + DBUG_PRINT("wsrep", ("update row key")); + + if (wsrep_append_keys(user_thd, false, old_row, new_row)) { + WSREP_DEBUG("WSREP: UPDATE_ROW_KEY FAILED"); + DBUG_PRINT("wsrep", ("row key failed")); + err = HA_ERR_INTERNAL_ERROR; + goto wsrep_error; + } + } +wsrep_error: +#endif /* WITH_WSREP */ + if (UNIV_UNLIKELY(share->ib_table->is_corrupt)) { DBUG_RETURN(HA_ERR_CRASHED); } @@ -8171,6 +8821,19 @@ ha_innobase::delete_row( innobase_active_small(); +#ifdef WITH_WSREP + if (error == DB_SUCCESS && wsrep_thd_exec_mode(user_thd) == LOCAL_STATE && + wsrep_on(user_thd)) { + + if (wsrep_append_keys(user_thd, false, record, NULL)) { + DBUG_PRINT("wsrep", ("delete fail")); + error = DB_ERROR; + goto wsrep_error; + } + } +wsrep_error: +#endif /* WITH_WSREP */ + if (UNIV_UNLIKELY(share && share->ib_table && share->ib_table->is_corrupt)) { DBUG_RETURN(HA_ERR_CRASHED); @@ -9360,6 +10023,396 @@ ha_innobase::ft_end() rnd_end(); } +#ifdef WITH_WSREP +extern dict_index_t* +wsrep_dict_foreign_find_index( + dict_table_t* table, + const char** col_names, + const char** columns, + ulint n_cols, + dict_index_t* types_idx, + ibool check_charsets, + ulint check_null); + + +extern dberr_t +wsrep_append_foreign_key( +/*===========================*/ + trx_t* trx, /*!< in: trx */ + dict_foreign_t* foreign, /*!< in: foreign key constraint */ + const rec_t* rec, /*!mysql_thd; + ulint rcode = DB_SUCCESS; + char cache_key[513] = {'\0'}; + int cache_key_len; + bool const copy = true; + + if (!wsrep_on(trx->mysql_thd) || + wsrep_thd_exec_mode(thd) != LOCAL_STATE) + return DB_SUCCESS; + + if (!thd || !foreign || + (!foreign->referenced_table && !foreign->foreign_table)) + { + WSREP_INFO("FK: %s missing in: %s", + (!thd) ? "thread" : + ((!foreign) ? "constraint" : + ((!foreign->referenced_table) ? + "referenced table" : "foreign table")), + (thd && wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + return DB_ERROR; + } + + if ( !((referenced) ? + foreign->referenced_table : foreign->foreign_table)) + { + WSREP_DEBUG("pulling %s table into cache", + (referenced) ? "referenced" : "foreign"); + mutex_enter(&(dict_sys->mutex)); + if (referenced) + { + foreign->referenced_table = + dict_table_get_low( + foreign->referenced_table_name_lookup); + if (foreign->referenced_table) + { + foreign->referenced_index = + wsrep_dict_foreign_find_index( + foreign->referenced_table, NULL, + foreign->referenced_col_names, + foreign->n_fields, + foreign->foreign_index, + TRUE, FALSE); + } + } + else + { + foreign->foreign_table = + dict_table_get_low( + foreign->foreign_table_name_lookup); + if (foreign->foreign_table) + { + foreign->foreign_index = + wsrep_dict_foreign_find_index( + foreign->foreign_table, NULL, + foreign->foreign_col_names, + foreign->n_fields, + foreign->referenced_index, + TRUE, FALSE); + } + } + mutex_exit(&(dict_sys->mutex)); + } + + if ( !((referenced) ? + foreign->referenced_table : foreign->foreign_table)) + { + WSREP_WARN("FK: %s missing in query: %s", + (!foreign->referenced_table) ? + "referenced table" : "foreign table", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + return DB_ERROR; + } + byte key[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + ulint len = WSREP_MAX_SUPPORTED_KEY_LENGTH; + + dict_index_t *idx_target = (referenced) ? + foreign->referenced_index : index; + dict_index_t *idx = (referenced) ? + UT_LIST_GET_FIRST(foreign->referenced_table->indexes) : + UT_LIST_GET_FIRST(foreign->foreign_table->indexes); + int i = 0; + while (idx != NULL && idx != idx_target) { + if (innobase_strcasecmp (idx->name, innobase_index_reserve_name) != 0) { + i++; + } + idx = UT_LIST_GET_NEXT(indexes, idx); + } + ut_a(idx); + key[0] = (char)i; + + rcode = wsrep_rec_get_foreign_key( + &key[1], &len, rec, index, idx, + wsrep_protocol_version > 1); + if (rcode != DB_SUCCESS) { + WSREP_ERROR( + "FK key set failed: %lu (%lu %lu), index: %s %s, %s", + rcode, referenced, shared, + (index && index->name) ? index->name : + "void index", + (index && index->table_name) ? index->table_name : + "void table", + wsrep_thd_query(thd)); + return DB_ERROR; + } + strncpy(cache_key, + (wsrep_protocol_version > 1) ? + ((referenced) ? + foreign->referenced_table->name : + foreign->foreign_table->name) : + foreign->foreign_table->name, sizeof(cache_key) - 1); + cache_key_len = strlen(cache_key); +#ifdef WSREP_DEBUG_PRINT + ulint j; + fprintf(stderr, "FK parent key, table: %s %s len: %lu ", + cache_key, (shared) ? "shared" : "exclusive", len+1); + for (j=0; jreferenced_table->name, + foreign->foreign_table->name); + } + + wsrep_buf_t wkey_part[3]; + wsrep_key_t wkey = {wkey_part, 3}; + if (!wsrep_prepare_key_for_innodb( + (const uchar*)cache_key, + cache_key_len + 1, + (const uchar*)key, len+1, + wkey_part, + (size_t*)&wkey.key_parts_num)) { + WSREP_WARN("key prepare failed for cascaded FK: %s", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + return DB_ERROR; + } + rcode = (int)wsrep->append_key( + wsrep, + wsrep_ws_handle(thd, trx), + &wkey, + 1, + shared ? WSREP_KEY_SHARED : WSREP_KEY_EXCLUSIVE, + copy); + if (rcode) { + DBUG_PRINT("wsrep", ("row key failed: %lu", rcode)); + WSREP_ERROR("Appending cascaded fk row key failed: %s, %lu", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void", rcode); + return DB_ERROR; + } + + return DB_SUCCESS; +} + +static int +wsrep_append_key( +/*==================*/ + THD *thd, + trx_t *trx, + TABLE_SHARE *table_share, + TABLE *table, + const char* key, + uint16_t key_len, + bool shared +) +{ + DBUG_ENTER("wsrep_append_key"); + bool const copy = true; +#ifdef WSREP_DEBUG_PRINT + fprintf(stderr, "%s conn %ld, trx %llu, keylen %d, table %s ", + (shared) ? "Shared" : "Exclusive", + wsrep_thd_thread_id(thd), (long long)trx->id, key_len, + table_share->table_name.str); + for (int i=0; itable_cache_key.str, + table_share->table_cache_key.length, + (const uchar*)key, key_len, + wkey_part, + (size_t*)&wkey.key_parts_num)) { + WSREP_WARN("key prepare failed for: %s", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + } + + int rcode = (int)wsrep->append_key( + wsrep, + wsrep_ws_handle(thd, trx), + &wkey, + 1, + shared ? WSREP_KEY_SHARED : WSREP_KEY_EXCLUSIVE, + copy); + if (rcode) { + DBUG_PRINT("wsrep", ("row key failed: %d", rcode)); + WSREP_WARN("Appending row key failed: %s, %d", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void", rcode); + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + } + DBUG_RETURN(0); +} + +extern void compute_md5_hash(char *digest, const char *buf, int len); +#define MD5_HASH compute_md5_hash + +int +ha_innobase::wsrep_append_keys( +/*==================*/ + THD *thd, + bool shared, + const uchar* record0, /* in: row in MySQL format */ + const uchar* record1) /* in: row in MySQL format */ +{ + int rcode; + DBUG_ENTER("wsrep_append_keys"); + + bool key_appended = false; + trx_t *trx = thd_to_trx(thd); + + if (table_share && table_share->tmp_table != NO_TMP_TABLE) { + WSREP_DEBUG("skipping tmp table DML: THD: %lu tmp: %d SQL: %s", + wsrep_thd_thread_id(thd), + table_share->tmp_table, + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + DBUG_RETURN(0); + } + + if (wsrep_protocol_version == 0) { + uint len; + char keyval[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + char *key = &keyval[0]; + KEY *key_info = table->key_info; + ibool is_null; + + len = wsrep_store_key_val_for_row( + table, 0, key, key_info->key_length, record0, &is_null); + + if (!is_null) { + rcode = wsrep_append_key( + thd, trx, table_share, table, keyval, + len, shared); + if (rcode) DBUG_RETURN(rcode); + } + else + { + WSREP_DEBUG("NULL key skipped (proto 0): %s", + wsrep_thd_query(thd)); + } + } else { + ut_a(table->s->keys <= 256); + uint i; + bool hasPK= false; + + for (i=0; is->keys; ++i) { + KEY* key_info = table->key_info + i; + if (key_info->flags & HA_NOSAME) { + hasPK = true; + if (i != table->s->primary_key) { + wsrep_thd_set_PA_safe(thd, FALSE); + } + } + } + + for (i=0; is->keys; ++i) { + uint len; + char keyval0[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + char keyval1[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + char* key0 = &keyval0[1]; + char* key1 = &keyval1[1]; + KEY* key_info = table->key_info + i; + ibool is_null; + + dict_index_t* idx = innobase_get_index(i); + dict_table_t* tab = (idx) ? idx->table : NULL; + + keyval0[0] = (char)i; + keyval1[0] = (char)i; + + if (!tab) { + WSREP_WARN("MySQL-InnoDB key mismatch %s %s", + table->s->table_name.str, + key_info->name); + } + /* !hasPK == table with no PK, must append all non-unique keys */ + if (!hasPK || key_info->flags & HA_NOSAME || + ((tab && + dict_table_get_referenced_constraint(tab, idx)) || + (!tab && referenced_by_foreign_key()))) { + + len = wsrep_store_key_val_for_row( + table, i, key0, key_info->key_length, + record0, &is_null); + if (!is_null) { + rcode = wsrep_append_key( + thd, trx, table_share, table, + keyval0, len+1, shared); + if (rcode) DBUG_RETURN(rcode); + + if (key_info->flags & HA_NOSAME || shared) + key_appended = true; + + } + else + { + WSREP_DEBUG("NULL key skipped: %s", + wsrep_thd_query(thd)); + } + if (record1) { + len = wsrep_store_key_val_for_row( + table, i, key1, key_info->key_length, + record1, &is_null); + if (!is_null && memcmp(key0, key1, len)) { + rcode = wsrep_append_key( + thd, trx, table_share, + table, + keyval1, len+1, shared); + if (rcode) DBUG_RETURN(rcode); + } + } + } + } + } + + /* if no PK, calculate hash of full row, to be the key value */ + if (!key_appended && wsrep_certify_nonPK) { + uchar digest[16]; + int rcode; + + wsrep_calc_row_hash(digest, record0, table, prebuilt, thd); + if ((rcode = wsrep_append_key(thd, trx, table_share, table, + (const char*) digest, 16, + shared))) { + DBUG_RETURN(rcode); + } + + if (record1) { + wsrep_calc_row_hash( + digest, record1, table, prebuilt, thd); + if ((rcode = wsrep_append_key(thd, trx, table_share, + table, + (const char*) digest, + 16, shared))) { + DBUG_RETURN(rcode); + } + } + DBUG_RETURN(0); + } + + DBUG_RETURN(0); +} +#endif /* WITH_WSREP */ /*********************************************************************//** Stores a reference to the current row to 'ref' field of the handle. Note @@ -13276,11 +14329,18 @@ ha_innobase::external_lock( /* used by test case */ DBUG_EXECUTE_IF("no_innodb_binlog_errors", skip = true;); if (!skip) { - my_error(ER_BINLOG_STMT_MODE_AND_ROW_ENGINE, MYF(0), - " InnoDB is limited to row-logging when " - "transaction isolation level is " - "READ COMMITTED or READ UNCOMMITTED."); - DBUG_RETURN(HA_ERR_LOGGING_IMPOSSIBLE); +#ifdef WITH_WSREP + if (!wsrep_on(thd) + || wsrep_thd_exec_mode(thd) == LOCAL_STATE) { +#endif /* WITH_WSREP */ + my_error(ER_BINLOG_STMT_MODE_AND_ROW_ENGINE, MYF(0), + " InnoDB is limited to row-logging when " + "transaction isolation level is " + "READ COMMITTED or READ UNCOMMITTED."); + DBUG_RETURN(HA_ERR_LOGGING_IMPOSSIBLE); +#ifdef WITH_WSREP + } +#endif /* WITH_WSREP */ } } @@ -14754,6 +15814,9 @@ innobase_xa_prepare( time, not the current session variable value. Any possible changes to the session variable take effect only in the next transaction */ if (!trx->support_xa) { +#ifdef WITH_WSREP + thd_get_xid(thd, (MYSQL_XID*) &trx->xid); +#endif // WITH_WSREP return(0); } @@ -17155,6 +18218,303 @@ static SHOW_VAR innodb_status_variables_export[]= { static struct st_mysql_storage_engine innobase_storage_engine= { MYSQL_HANDLERTON_INTERFACE_VERSION }; +#ifdef WITH_WSREP +void +wsrep_abort_slave_trx(wsrep_seqno_t bf_seqno, wsrep_seqno_t victim_seqno) +{ + WSREP_ERROR("Trx %lld tries to abort slave trx %lld. This could be " + "caused by:\n\t" + "1) unsupported configuration options combination, please check documentation.\n\t" + "2) a bug in the code.\n\t" + "3) a database corruption.\n Node consistency compromized, " + "need to abort. Restart the node to resync with cluster.", + (long long)bf_seqno, (long long)victim_seqno); + abort(); +} +/*******************************************************************//** +This function is used to kill one transaction in BF. */ + +int +wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, + const trx_t * const bf_trx, + trx_t *victim_trx, ibool signal) +{ + ut_ad(lock_mutex_own()); + ut_ad(trx_mutex_own(victim_trx)); + ut_ad(bf_thd_ptr); + ut_ad(victim_trx); + + DBUG_ENTER("wsrep_innobase_kill_one_trx"); + THD *bf_thd = bf_thd_ptr ? (THD*) bf_thd_ptr : NULL; + THD *thd = (THD *) victim_trx->mysql_thd; + int64_t bf_seqno = (bf_thd) ? wsrep_thd_trx_seqno(bf_thd) : 0; + + if (!thd) { + DBUG_PRINT("wsrep", ("no thd for conflicting lock")); + WSREP_WARN("no THD for trx: %lu", victim_trx->id); + DBUG_RETURN(1); + } + if (!bf_thd) { + DBUG_PRINT("wsrep", ("no BF thd for conflicting lock")); + WSREP_WARN("no BF THD for trx: %lu", (bf_trx) ? bf_trx->id : 0); + DBUG_RETURN(1); + } + + WSREP_LOG_CONFLICT(bf_thd, thd, TRUE); + + WSREP_DEBUG("BF kill (%lu, seqno: %lld), victim: (%lu) trx: %lu", + signal, (long long)bf_seqno, + wsrep_thd_thread_id(thd), + victim_trx->id); + + WSREP_DEBUG("Aborting query: %s", + (thd && wsrep_thd_query(thd)) ? wsrep_thd_query(thd) : "void"); + + wsrep_thd_LOCK(thd); + + if (wsrep_thd_query_state(thd) == QUERY_EXITING) { + WSREP_DEBUG("kill trx EXITING for %lu", victim_trx->id); + wsrep_thd_UNLOCK(thd); + DBUG_RETURN(0); + } + if(wsrep_thd_exec_mode(thd) != LOCAL_STATE) { + WSREP_DEBUG("withdraw for BF trx: %lu, state: %d", + victim_trx->id, + wsrep_thd_conflict_state(thd)); + } + + switch (wsrep_thd_conflict_state(thd)) { + case NO_CONFLICT: + wsrep_thd_set_conflict_state(thd, MUST_ABORT); + break; + case MUST_ABORT: + WSREP_DEBUG("victim %lu in MUST ABORT state", + victim_trx->id); + wsrep_thd_UNLOCK(thd); + wsrep_thd_awake(thd, signal); + DBUG_RETURN(0); + break; + case ABORTED: + case ABORTING: // fall through + default: + WSREP_DEBUG("victim %lu in state %d", + victim_trx->id, wsrep_thd_conflict_state(thd)); + wsrep_thd_UNLOCK(thd); + DBUG_RETURN(0); + break; + } + + switch (wsrep_thd_query_state(thd)) { + case QUERY_COMMITTING: + enum wsrep_status rcode; + + WSREP_DEBUG("kill query for: %ld", + wsrep_thd_thread_id(thd)); + WSREP_DEBUG("kill trx QUERY_COMMITTING for %lu", + victim_trx->id); + + if (wsrep_thd_exec_mode(thd) == REPL_RECV) { + wsrep_abort_slave_trx(bf_seqno, + wsrep_thd_trx_seqno(thd)); + } else { + rcode = wsrep->abort_pre_commit( + wsrep, bf_seqno, + (wsrep_trx_id_t)victim_trx->id + ); + + switch (rcode) { + case WSREP_WARNING: + WSREP_DEBUG("cancel commit warning: %lu", + victim_trx->id); + wsrep_thd_UNLOCK(thd); + wsrep_thd_awake(thd, signal); + DBUG_RETURN(1); + break; + case WSREP_OK: + break; + default: + WSREP_ERROR( + "cancel commit bad exit: %d %lu", + rcode, + victim_trx->id); + /* unable to interrupt, must abort */ + /* note: kill_mysql() will block, if we cannot. + * kill the lock holder first. + */ + abort(); + break; + } + } + wsrep_thd_UNLOCK(thd); + wsrep_thd_awake(thd, signal); + break; + case QUERY_EXEC: + /* it is possible that victim trx is itself waiting for some + * other lock. We need to cancel this waiting + */ + WSREP_DEBUG("kill trx QUERY_EXEC for %lu", victim_trx->id); + + victim_trx->lock.was_chosen_as_deadlock_victim= TRUE; + if (victim_trx->lock.wait_lock) { + WSREP_DEBUG("victim has wait flag: %ld", + wsrep_thd_thread_id(thd)); + lock_t* wait_lock = victim_trx->lock.wait_lock; + if (wait_lock) { + WSREP_DEBUG("canceling wait lock"); + victim_trx->lock.was_chosen_as_deadlock_victim= TRUE; + lock_cancel_waiting_and_release(wait_lock); + } + + wsrep_thd_UNLOCK(thd); + wsrep_thd_awake(thd, signal); + } else { + /* abort currently executing query */ + DBUG_PRINT("wsrep",("sending KILL_QUERY to: %ld", + wsrep_thd_thread_id(thd))); + WSREP_DEBUG("kill query for: %ld", + wsrep_thd_thread_id(thd)); + /* Note that innobase_kill_connection will take lock_mutex + and trx_mutex */ + wsrep_thd_UNLOCK(thd); + wsrep_thd_awake(thd, signal); + + /* for BF thd, we need to prevent him from committing */ + if (wsrep_thd_exec_mode(thd) == REPL_RECV) { + wsrep_abort_slave_trx(bf_seqno, + wsrep_thd_trx_seqno(thd)); + } + } + break; + case QUERY_IDLE: + { + bool skip_abort= false; + wsrep_aborting_thd_t abortees; + + WSREP_DEBUG("kill IDLE for %lu", victim_trx->id); + + if (wsrep_thd_exec_mode(thd) == REPL_RECV) { + WSREP_DEBUG("kill BF IDLE, seqno: %lld", + (long long)wsrep_thd_trx_seqno(thd)); + wsrep_thd_UNLOCK(thd); + wsrep_abort_slave_trx(bf_seqno, + wsrep_thd_trx_seqno(thd)); + DBUG_RETURN(0); + } + /* This will lock thd from proceeding after net_read() */ + wsrep_thd_set_conflict_state(thd, ABORTING); + + mysql_mutex_lock(&LOCK_wsrep_rollback); + + abortees = wsrep_aborting_thd; + while (abortees && !skip_abort) { + /* check if we have a kill message for this already */ + if (abortees->aborting_thd == thd) { + skip_abort = true; + WSREP_WARN("duplicate thd aborter %lu", + wsrep_thd_thread_id(thd)); + } + abortees = abortees->next; + } + if (!skip_abort) { + wsrep_aborting_thd_t aborting = (wsrep_aborting_thd_t) + my_malloc(sizeof(struct wsrep_aborting_thd), + MYF(0)); + aborting->aborting_thd = thd; + aborting->next = wsrep_aborting_thd; + wsrep_aborting_thd = aborting; + DBUG_PRINT("wsrep",("enqueuing trx abort for %lu", + wsrep_thd_thread_id(thd))); + WSREP_DEBUG("enqueuing trx abort for (%lu)", + wsrep_thd_thread_id(thd)); + } + + DBUG_PRINT("wsrep",("signalling wsrep rollbacker")); + WSREP_DEBUG("signaling aborter"); + mysql_cond_signal(&COND_wsrep_rollback); + mysql_mutex_unlock(&LOCK_wsrep_rollback); + wsrep_thd_UNLOCK(thd); + + break; + } + default: + WSREP_WARN("bad wsrep query state: %d", + wsrep_thd_query_state(thd)); + wsrep_thd_UNLOCK(thd); + break; + } + + DBUG_RETURN(0); +} +static int +wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd, + my_bool signal) +{ + DBUG_ENTER("wsrep_innobase_abort_thd"); + trx_t* victim_trx = thd_to_trx(victim_thd); + trx_t* bf_trx = (bf_thd) ? thd_to_trx(bf_thd) : NULL; + WSREP_DEBUG("abort transaction: BF: %s victim: %s", + wsrep_thd_query(bf_thd), + wsrep_thd_query(victim_thd)); + + if (victim_trx) + { + lock_mutex_enter(); + trx_mutex_enter(victim_trx); + int rcode = wsrep_innobase_kill_one_trx(bf_thd, bf_trx, + victim_trx, signal); + trx_mutex_exit(victim_trx); + lock_mutex_exit(); + wsrep_srv_conc_cancel_wait(victim_trx); + + DBUG_RETURN(rcode); + } else { + WSREP_DEBUG("victim does not have transaction"); + wsrep_thd_LOCK(victim_thd); + wsrep_thd_set_conflict_state(victim_thd, MUST_ABORT); + wsrep_thd_UNLOCK(victim_thd); + wsrep_thd_awake(victim_thd, signal); + } + DBUG_RETURN(-1); +} + +static int innobase_wsrep_set_checkpoint(handlerton* hton, const XID* xid) +{ + DBUG_ASSERT(hton == innodb_hton_ptr); + if (wsrep_is_wsrep_xid((const void *)xid)) { + mtr_t mtr; + mtr_start(&mtr); + trx_sysf_t* sys_header = trx_sysf_get(&mtr); + trx_sys_update_wsrep_checkpoint(xid, sys_header, &mtr); + mtr_commit(&mtr); + innobase_flush_logs(hton); + return 0; + } else { + return 1; + } +} + +static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid) +{ + DBUG_ASSERT(hton == innodb_hton_ptr); + trx_sys_read_wsrep_checkpoint(xid); + return 0; +} + +static void +wsrep_fake_trx_id( +/*==================*/ + handlerton *hton, + THD *thd) /*!< in: user thread handle */ +{ + mutex_enter(&trx_sys->mutex); + trx_id_t trx_id = trx_sys_get_new_trx_id(); + mutex_exit(&trx_sys->mutex); + + (void *)wsrep_ws_handle_for_trx(wsrep_thd_ws_handle(thd), trx_id); +} + +#endif /* WITH_WSREP */ + /* plugin options */ static MYSQL_SYSVAR_ENUM(checksum_algorithm, srv_checksum_algorithm, @@ -18092,6 +19452,40 @@ static MYSQL_SYSVAR_BOOL(disable_background_merge, NULL, NULL, FALSE); #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ +#ifdef WITH_INNODB_DISALLOW_WRITES +/******************************************************* + * innobase_disallow_writes variable definition * + *******************************************************/ + +/* Must always init to FALSE. */ +static my_bool innobase_disallow_writes = FALSE; + +/************************************************************************** +An "update" method for innobase_disallow_writes variable. */ +static +void +innobase_disallow_writes_update( +/*============================*/ + THD* thd, /* in: thread handle */ + st_mysql_sys_var* var, /* in: pointer to system + variable */ + void* var_ptr, /* out: pointer to dynamic + variable */ + const void* save) /* in: temporary storage */ +{ + *(my_bool*)var_ptr = *(my_bool*)save; + ut_a(srv_allow_writes_event); + if (*(my_bool*)var_ptr) + os_event_reset(srv_allow_writes_event); + else + os_event_set(srv_allow_writes_event); +} + +static MYSQL_SYSVAR_BOOL(disallow_writes, innobase_disallow_writes, + PLUGIN_VAR_NOCMDOPT, + "Tell InnoDB to stop any writes to disk", + NULL, innobase_disallow_writes_update, FALSE); +#endif /* WITH_INNODB_DISALLOW_WRITES */ static MYSQL_SYSVAR_BOOL(random_read_ahead, srv_random_read_ahead, PLUGIN_VAR_NOCMDARG, "Whether to use read ahead for random access within an extent.", @@ -18403,6 +19797,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(change_buffering_debug), MYSQL_SYSVAR(disable_background_merge), #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ +#ifdef WITH_INNODB_DISALLOW_WRITES + MYSQL_SYSVAR(disallow_writes), +#endif /* WITH_INNODB_DISALLOW_WRITES */ MYSQL_SYSVAR(random_read_ahead), MYSQL_SYSVAR(read_ahead_threshold), MYSQL_SYSVAR(read_only), diff --git a/storage/xtradb/handler/ha_innodb.h b/storage/xtradb/handler/ha_innodb.h index b4df711356c..ff4ab88335a 100644 --- a/storage/xtradb/handler/ha_innodb.h +++ b/storage/xtradb/handler/ha_innodb.h @@ -119,6 +119,10 @@ class ha_innobase: public handler void innobase_initialize_autoinc(); dict_index_t* innobase_get_index(uint keynr); +#ifdef WITH_WSREP + int wsrep_append_keys(THD *thd, bool shared, + const uchar* record0, const uchar* record1); +#endif /* Init values for the class: */ public: ha_innobase(handlerton *hton, TABLE_SHARE *table_arg); @@ -472,6 +476,40 @@ __attribute__((nonnull)); extern void mysql_bin_log_commit_pos(THD *thd, ulonglong *out_pos, const char **out_file); struct trx_t; +#ifdef WITH_WSREP +#include +//extern "C" int wsrep_trx_order_before(void *thd1, void *thd2); + +extern "C" bool wsrep_thd_is_wsrep_on(THD *thd); + +extern "C" enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd); +extern "C" enum wsrep_conflict_state wsrep_thd_conflict_state(THD *thd); +extern "C" enum wsrep_query_state wsrep_thd_query_state(THD *thd); +extern "C" const char * wsrep_thd_exec_mode_str(THD *thd); +extern "C" const char * wsrep_thd_conflict_state_str(THD *thd); +extern "C" const char * wsrep_thd_query_state_str(THD *thd); +extern "C" wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd); + +extern "C" void wsrep_thd_set_exec_mode(THD *thd, enum wsrep_exec_mode mode); +extern "C" void wsrep_thd_set_query_state( + THD *thd, enum wsrep_query_state state); +extern "C" void wsrep_thd_set_conflict_state( + THD *thd, enum wsrep_conflict_state state); + +extern "C" void wsrep_thd_set_trx_to_replay(THD *thd, uint64 trx_id); + +extern "C"void wsrep_thd_LOCK(THD *thd); +extern "C"void wsrep_thd_UNLOCK(THD *thd); +extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd); +extern "C" time_t wsrep_thd_query_start(THD *thd); +extern "C" my_thread_id wsrep_thd_thread_id(THD *thd); +extern "C" int64_t wsrep_thd_trx_seqno(THD *thd); +extern "C" query_id_t wsrep_thd_query_id(THD *thd); +extern "C" char * wsrep_thd_query(THD *thd); +extern "C" query_id_t wsrep_thd_wsrep_last_query_id(THD *thd); +extern "C" void wsrep_thd_set_wsrep_last_query_id(THD *thd, query_id_t id); +extern "C" void wsrep_thd_awake(THD* thd, my_bool signal); +#endif extern const struct _ft_vft ft_vft_result; @@ -509,6 +547,9 @@ innobase_index_name_is_reserved( __attribute__((nonnull, warn_unused_result)); /*****************************************************************//** +#ifdef WITH_WSREP +extern "C" int wsrep_trx_is_aborting(void *thd_ptr); +#endif Determines InnoDB table flags. @retval true if successful, false if error */ UNIV_INTERN diff --git a/storage/xtradb/handler/handler0alter.cc b/storage/xtradb/handler/handler0alter.cc index 34048e7c987..2cd0500007a 100644 --- a/storage/xtradb/handler/handler0alter.cc +++ b/storage/xtradb/handler/handler0alter.cc @@ -49,6 +49,10 @@ Smart ALTER TABLE #include "pars0pars.h" #include "row0sel.h" #include "ha_innodb.h" +#ifdef WITH_WSREP +//#include "wsrep_api.h" +#include // PROCESS_ACL +#endif /** Operations for creating secondary indexes (no rebuild needed) */ static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_ONLINE_CREATE diff --git a/storage/xtradb/include/dict0mem.h b/storage/xtradb/include/dict0mem.h index a347a75ea42..93fe2efa830 100644 --- a/storage/xtradb/include/dict0mem.h +++ b/storage/xtradb/include/dict0mem.h @@ -527,6 +527,9 @@ be REC_VERSION_56_MAX_INDEX_COL_LEN (3072) bytes */ /** Defines the maximum fixed length column size */ #define DICT_MAX_FIXED_COL_LEN DICT_ANTELOPE_MAX_INDEX_COL_LEN +#ifdef WITH_WSREP +#define WSREP_MAX_SUPPORTED_KEY_LENGTH 3500 +#endif /* WITH_WSREP */ /** Data structure for a field in an index */ struct dict_field_t{ diff --git a/storage/xtradb/include/ha_prototypes.h b/storage/xtradb/include/ha_prototypes.h index 66a96282b69..1dd109eb940 100644 --- a/storage/xtradb/include/ha_prototypes.h +++ b/storage/xtradb/include/ha_prototypes.h @@ -285,6 +285,22 @@ innobase_casedn_str( /*================*/ char* a); /*!< in/out: string to put in lower case */ +#ifdef WITH_WSREP +UNIV_INTERN +int +wsrep_innobase_kill_one_trx(void *thd_ptr, + const trx_t *bf_trx, trx_t *victim_trx, ibool signal); +my_bool wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe); +int wsrep_thd_conflict_state(void *thd_ptr, my_bool sync); +my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync); +int wsrep_trx_order_before(void *thd1, void *thd2); +int wsrep_innobase_mysql_sort(int mysql_type, uint charset_number, + unsigned char* str, unsigned int str_length, + unsigned int buf_length); +int +wsrep_on(void *thd_ptr); +extern "C" int wsrep_is_wsrep_xid(const void*); +#endif /* WITH_WSREP */ /**********************************************************************//** Determines the connection character set. @return connection character set */ diff --git a/storage/xtradb/include/rem0rec.h b/storage/xtradb/include/rem0rec.h index 8e7d5ff2d48..238cb04e1f8 100644 --- a/storage/xtradb/include/rem0rec.h +++ b/storage/xtradb/include/rem0rec.h @@ -981,6 +981,15 @@ are given in one byte (resp. two byte) format. */ two upmost bits in a two byte offset for special purposes */ #define REC_MAX_DATA_SIZE (16 * 1024) +#ifdef WITH_WSREP +int wsrep_rec_get_foreign_key( + byte *buf, /* out: extracted key */ + ulint *buf_len, /* in/out: length of buf */ + const rec_t* rec, /* in: physical record */ + dict_index_t* index_for, /* in: index for foreign table */ + dict_index_t* index_ref, /* in: index for referenced table */ + ibool new_protocol); /* in: protocol > 1 */ +#endif /* WITH_WSREP */ #ifndef UNIV_NONINL #include "rem0rec.ic" #endif diff --git a/storage/xtradb/include/srv0srv.h b/storage/xtradb/include/srv0srv.h index a02c8a96e1a..a54198f4e00 100644 --- a/storage/xtradb/include/srv0srv.h +++ b/storage/xtradb/include/srv0srv.h @@ -323,6 +323,10 @@ extern uint srv_flush_log_at_timeout; extern char srv_use_global_flush_log_at_trx_commit; extern char srv_adaptive_flushing; +#ifdef WITH_INNODB_DISALLOW_WRITES +/* When this event is reset we do not allow any file writes to take place. */ +extern os_event_t srv_allow_writes_event; +#endif /* WITH_INNODB_DISALLOW_WRITES */ /* If this flag is TRUE, then we will load the indexes' (and tables') metadata even if they are marked as "corrupted". Mostly it is for DBA to process corrupted index and table */ @@ -1167,4 +1171,13 @@ struct srv_slot_t{ # define srv_file_per_table 1 #endif /* !UNIV_HOTBACKUP */ +#ifdef WITH_WSREP +UNIV_INTERN +void +wsrep_srv_conc_cancel_wait( +/*==================*/ + trx_t* trx); /*!< in: transaction object associated with the + thread */ +#endif /* WITH_WSREP */ + #endif diff --git a/storage/xtradb/include/sync0sync.ic b/storage/xtradb/include/sync0sync.ic index c3529af5262..a302e1473a5 100644 --- a/storage/xtradb/include/sync0sync.ic +++ b/storage/xtradb/include/sync0sync.ic @@ -255,7 +255,10 @@ mutex_enter_func( ulint line) /*!< in: line where locked */ { ut_ad(mutex_validate(mutex)); +#ifndef WITH_WSREP + /* this cannot be be granted when BF trx kills a trx in lock wait state */ ut_ad(!mutex_own(mutex)); +#endif /* WITH_WSREP */ /* Note that we do not peek at the value of lock_word before trying the atomic test_and_set; we could peek, and possibly save time. */ diff --git a/storage/xtradb/include/trx0sys.h b/storage/xtradb/include/trx0sys.h index 7b97c6e99cd..7892fdd0bf1 100644 --- a/storage/xtradb/include/trx0sys.h +++ b/storage/xtradb/include/trx0sys.h @@ -42,6 +42,9 @@ Created 3/26/1996 Heikki Tuuri #include "read0types.h" #include "page0types.h" #include "ut0bh.h" +#ifdef WITH_WSREP +#include "trx0xa.h" +#endif /* WITH_WSREP */ typedef UT_LIST_BASE_NODE_T(trx_t) trx_list_t; @@ -314,6 +317,9 @@ trx_sys_update_mysql_binlog_offset( ib_int64_t offset, /*!< in: position in that log file */ ulint field, /*!< in: offset of the MySQL log info field in the trx sys header */ +#ifdef WITH_WSREP + trx_sysf_t* sys_header, /*!< in: trx sys header */ +#endif /* WITH_WSREP */ mtr_t* mtr); /*!< in: mtr */ /*****************************************************************//** Prints to stderr the MySQL binlog offset info in the trx system header if @@ -322,6 +328,19 @@ UNIV_INTERN void trx_sys_print_mysql_binlog_offset(void); /*===================================*/ +#ifdef WITH_WSREP +/** Update WSREP checkpoint XID in sys header. */ +void +trx_sys_update_wsrep_checkpoint( + const XID* xid, /*!< in: WSREP XID */ + trx_sysf_t* sys_header, /*!< in: sys_header */ + mtr_t* mtr); /*!< in: mtr */ + +void +/** Read WSREP checkpoint XID from sys header. */ +trx_sys_read_wsrep_checkpoint( + XID* xid); /*!< out: WSREP XID */ +#endif /* WITH_WSREP */ /*****************************************************************//** Prints to stderr the MySQL master log offset info in the trx system header if the magic number shows it valid. */ @@ -550,6 +569,20 @@ this contains the same fields as TRX_SYS_MYSQL_LOG_INFO below */ within that file */ #define TRX_SYS_MYSQL_LOG_NAME 12 /*!< MySQL log file name */ +#ifdef WITH_WSREP +/* The offset to WSREP XID headers */ +#define TRX_SYS_WSREP_XID_INFO (UNIV_PAGE_SIZE - 3500) +#define TRX_SYS_WSREP_XID_MAGIC_N_FLD 0 +#define TRX_SYS_WSREP_XID_MAGIC_N 0x77737265 + +/* XID field: formatID, gtrid_len, bqual_len, xid_data */ +#define TRX_SYS_WSREP_XID_LEN (4 + 4 + 4 + XIDDATASIZE) +#define TRX_SYS_WSREP_XID_FORMAT 4 +#define TRX_SYS_WSREP_XID_GTRID_LEN 8 +#define TRX_SYS_WSREP_XID_BQUAL_LEN 12 +#define TRX_SYS_WSREP_XID_DATA 16 +#endif /* WITH_WSREP*/ + /** Doublewrite buffer */ /* @{ */ /** The offset of the doublewrite buffer header on the trx system header page */ diff --git a/storage/xtradb/include/trx0sys.ic b/storage/xtradb/include/trx0sys.ic index 699148cff6d..6024c1dc94e 100644 --- a/storage/xtradb/include/trx0sys.ic +++ b/storage/xtradb/include/trx0sys.ic @@ -474,7 +474,10 @@ trx_id_t trx_sys_get_new_trx_id(void) /*========================*/ { +#ifndef WITH_WSREP + /* wsrep_fake_trx_id violates this assert */ ut_ad(mutex_own(&trx_sys->mutex)); +#endif /* WITH_WSREP */ /* VERY important: after the database is started, max_trx_id value is divisible by TRX_SYS_TRX_ID_WRITE_MARGIN, and the following if diff --git a/storage/xtradb/include/trx0trx.h b/storage/xtradb/include/trx0trx.h index aaa74724a14..be13c48fdfc 100644 --- a/storage/xtradb/include/trx0trx.h +++ b/storage/xtradb/include/trx0trx.h @@ -1031,6 +1031,9 @@ struct trx_t{ /*------------------------------*/ char detailed_error[256]; /*!< detailed error message for last error, or empty. */ +#ifdef WITH_WSREP + os_event_t wsrep_event; /* event waited for in srv_conc_slot */ +#endif /* WITH_WSREP */ /*------------------------------*/ ulint io_reads; ib_uint64_t io_read; diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc index 4f9395e27d8..0a9f4780c2e 100644 --- a/storage/xtradb/lock/lock0lock.cc +++ b/storage/xtradb/lock/lock0lock.cc @@ -50,6 +50,11 @@ Created 5/7/1996 Heikki Tuuri #include "dict0boot.h" #include +#ifdef WITH_WSREP +extern my_bool wsrep_debug; +extern my_bool wsrep_log_conflicts; +#include "ha_prototypes.h" +#endif /* Restricts the length of search we will do in the waits-for graph of transactions */ #define LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK 1000000 @@ -946,6 +951,9 @@ UNIV_INLINE ibool lock_rec_has_to_wait( /*=================*/ +#ifdef WITH_WSREP + ibool for_locking, /*!< is caller locking or releasing */ +#endif /* WITH_WSREP */ const trx_t* trx, /*!< in: trx of new lock */ ulint type_mode,/*!< in: precise mode of the new lock to set: LOCK_S or LOCK_X, possibly @@ -1016,6 +1024,49 @@ lock_rec_has_to_wait( return(FALSE); } +#ifdef WITH_WSREP + /* if BF thread is locking and has conflict with another BF + thread, we need to look at trx ordering and lock types */ + if (for_locking && + wsrep_thd_is_BF(trx->mysql_thd, FALSE) && + wsrep_thd_is_BF(lock2->trx->mysql_thd, TRUE)) { + + if (wsrep_debug) { + fprintf(stderr, "\n BF-BF lock conflict \n"); + lock_rec_print(stderr, lock2); + } + + if (wsrep_trx_order_before(trx->mysql_thd, + lock2->trx->mysql_thd) && + (type_mode & LOCK_MODE_MASK) == LOCK_X && + (lock2->type_mode & LOCK_MODE_MASK) == LOCK_X) + { + /* exclusive lock conflicts are not accepted */ + fprintf(stderr, "BF-BF X lock conflict," + "type_mode: %lu supremum: %lu\n", + type_mode, lock_is_on_supremum); + fprintf(stderr, "conflicts states: my %d locked %d\n", + wsrep_thd_conflict_state(trx->mysql_thd, FALSE), + wsrep_thd_conflict_state(lock2->trx->mysql_thd, FALSE) ); + lock_rec_print(stderr, lock2); + abort(); + } else { + /* if lock2->index->n_uniq <= + lock2->index->n_user_defined_cols + operation is on uniq index + */ + if (wsrep_debug) fprintf(stderr, + "BF conflict, modes: %lu %lu, " + "idx: %s-%s n_uniq %u n_user %u\n", + type_mode, lock2->type_mode, + lock2->index->name, + lock2->index->table_name, + lock2->index->n_uniq, + lock2->index->n_user_defined_cols); + return FALSE; + } + } +#endif /* WITH_WSREP */ return(TRUE); } @@ -1046,7 +1097,11 @@ lock_has_to_wait( /* If this lock request is for a supremum record then the second bit on the lock bitmap is set */ +#ifdef WITH_WSREP + return(lock_rec_has_to_wait(FALSE, lock1->trx, +#else return(lock_rec_has_to_wait(lock1->trx, +#endif /* WITH_WSREP */ lock1->type_mode, lock2, lock_rec_get_nth_bit( lock1, 1))); @@ -1515,6 +1570,11 @@ lock_rec_has_expl( return(NULL); } +#ifdef WITH_WSREP +static +void +lock_rec_discard(lock_t* in_lock); +#endif #ifdef UNIV_DEBUG /*********************************************************************//** Checks if some other transaction has a lock request in the queue. @@ -1561,6 +1621,58 @@ lock_rec_other_has_expl_req( } #endif /* UNIV_DEBUG */ +#ifdef WITH_WSREP +static void +wsrep_kill_victim(const trx_t * const trx, const lock_t *lock) { + ut_ad(lock_mutex_own()); + ut_ad(trx_mutex_own(lock->trx)); + my_bool bf_this = wsrep_thd_is_BF(trx->mysql_thd, FALSE); + my_bool bf_other = wsrep_thd_is_BF(lock->trx->mysql_thd, TRUE); + + if ((bf_this && !bf_other) || + (bf_this && bf_other && wsrep_trx_order_before( + trx->mysql_thd, lock->trx->mysql_thd))) { + + if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { + if (wsrep_debug) + fprintf(stderr, "WSREP: BF victim waiting\n"); + /* cannot release lock, until our lock + is in the queue*/ + } else if (lock->trx != trx) { + if (wsrep_log_conflicts) { + mutex_enter(&trx_sys->mutex); + if (bf_this) + fputs("\n*** Priority TRANSACTION:\n", + stderr); + else + fputs("\n*** Victim TRANSACTION:\n", + stderr); + trx_print_latched(stderr, trx, 3000); + + if (bf_other) + fputs("\n*** Priority TRANSACTION:\n", + stderr); + else + fputs("\n*** Victim TRANSACTION:\n", + stderr); + trx_print_latched(stderr, lock->trx, 3000); + + mutex_exit(&trx_sys->mutex); + fputs("*** WAITING FOR THIS LOCK TO BE GRANTED:\n", + stderr); + + if (lock_get_type(lock) == LOCK_REC) { + lock_rec_print(stderr, lock); + } else { + lock_table_print(stderr, lock); + } + } + wsrep_innobase_kill_one_trx(trx->mysql_thd, + (const trx_t*) trx, lock->trx, TRUE); + } + } +} +#endif /*********************************************************************//** Checks if some other transaction has a conflicting explicit lock request in the queue, so that we have to wait. @@ -1589,7 +1701,15 @@ lock_rec_other_has_conflicting( lock != NULL; lock = lock_rec_get_next_const(heap_no, lock)) { - if (lock_rec_has_to_wait(trx, mode, lock, is_supremum)) { +#ifdef WITH_WSREP + if (lock_rec_has_to_wait(TRUE, trx, mode, lock, is_supremum)) { + trx_mutex_enter(lock->trx); + wsrep_kill_victim((trx_t *)trx, (lock_t *)lock); + trx_mutex_exit(lock->trx); +#else + if (lock_rec_has_to_wait(trx, mode, lock, is_supremum)) { +#endif /* WITH_WSREP */ + return(lock); } } @@ -1782,6 +1902,28 @@ lock_number_of_rows_locked( /*============== RECORD LOCK CREATION AND QUEUE MANAGEMENT =============*/ +#ifdef WITH_WSREP +static +void +wsrep_print_wait_locks( +/*============*/ + lock_t* c_lock) /* conflicting lock to print */ +{ + if (wsrep_debug && c_lock->trx->lock.wait_lock != c_lock) { + fprintf(stderr, "WSREP: c_lock != wait lock\n"); + if (lock_get_type_low(c_lock) & LOCK_TABLE) + lock_table_print(stderr, c_lock); + else + lock_rec_print(stderr, c_lock); + + if (lock_get_type_low(c_lock->trx->lock.wait_lock) & LOCK_TABLE) + lock_table_print(stderr, c_lock->trx->lock.wait_lock); + else + lock_rec_print(stderr, c_lock->trx->lock.wait_lock); + } +} +#endif /* WITH_WSREP */ + /*********************************************************************//** Creates a new record lock and inserts it to the lock queue. Does NOT check for deadlocks or lock compatibility! @@ -1790,6 +1932,10 @@ static lock_t* lock_rec_create( /*============*/ +#ifdef WITH_WSREP + lock_t* const c_lock, /* conflicting lock */ + que_thr_t* thr, +#endif ulint type_mode,/*!< in: lock mode and wait flag, type is ignored and replaced by LOCK_REC */ @@ -1861,8 +2007,78 @@ lock_rec_create( ut_ad(index->table->n_ref_count > 0 || !index->table->can_be_evicted); +#ifdef WITH_WSREP + if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + lock_t *hash = (lock_t *)c_lock->hash; + lock_t *prev = NULL; + + while (hash && + wsrep_thd_is_BF(((lock_t *)hash)->trx->mysql_thd, TRUE) && + wsrep_trx_order_before( + ((lock_t *)hash)->trx->mysql_thd, + trx->mysql_thd)) { + prev = hash; + hash = (lock_t *)hash->hash; + } + lock->hash = hash; + if (prev) { + prev->hash = lock; + } else { + c_lock->hash = lock; + } + /* + * delayed conflict resolution '...kill_one_trx' was not called, + * if victim was waiting for some other lock + */ + trx_mutex_enter(c_lock->trx); + if (c_lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { + + c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE; + + if (wsrep_debug) wsrep_print_wait_locks(c_lock); + + trx->lock.que_state = TRX_QUE_LOCK_WAIT; + lock_set_lock_and_trx_wait(lock, trx); + UT_LIST_ADD_LAST(trx_locks, trx->lock.trx_locks, lock); + + ut_ad(thr != NULL); + trx->lock.wait_thr = thr; + thr->state = QUE_THR_LOCK_WAIT; + + /* have to release trx mutex for the duration of + victim lock release. This will eventually call + lock_grant, which wants to grant trx mutex again + */ + if (caller_owns_trx_mutex) trx_mutex_exit(trx); + lock_cancel_waiting_and_release( + c_lock->trx->lock.wait_lock); + if (caller_owns_trx_mutex) trx_mutex_enter(trx); + + /* trx might not wait for c_lock, but some other lock + does not matter if wait_lock was released above + */ + if (c_lock->trx->lock.wait_lock == c_lock) { + lock_reset_lock_and_trx_wait(lock); + } + trx_mutex_exit(c_lock->trx); + + if (wsrep_debug) fprintf( + stderr, + "WSREP: c_lock canceled %llu\n", + (ulonglong) c_lock->trx->id); + + /* have to bail out here to avoid lock_set_lock... */ + return(lock); + } + trx_mutex_exit(c_lock->trx); + } else { + HASH_INSERT(lock_t, hash, lock_sys->rec_hash, + lock_rec_fold(space, page_no), lock); + } +#else HASH_INSERT(lock_t, hash, lock_sys->rec_hash, lock_rec_fold(space, page_no), lock); +#endif /* WITH_WSREP */ lock_sys->rec_num++; @@ -1899,6 +2115,9 @@ static dberr_t lock_rec_enqueue_waiting( /*=====================*/ +#ifdef WITH_WSREP + lock_t* c_lock, /* conflicting lock */ +#endif ulint type_mode,/*!< in: lock mode this transaction is requesting: LOCK_S or LOCK_X, possibly @@ -1959,7 +2178,10 @@ lock_rec_enqueue_waiting( /* Enqueue the lock request that will wait to be granted, note that we already own the trx mutex. */ lock = lock_rec_create( - type_mode | LOCK_WAIT, block, heap_no, index, trx, TRUE); +#ifdef WITH_WSREP + c_lock, thr, +#endif /* WITH_WSREP */ + type_mode | LOCK_WAIT, block, heap_no, index, trx, TRUE); /* Release the mutex to obey the latching order. This is safe, because lock_deadlock_check_and_resolve() @@ -2064,7 +2286,19 @@ lock_rec_add_to_queue( const lock_t* other_lock = lock_rec_other_has_expl_req(mode, 0, LOCK_WAIT, block, heap_no, trx->id); +#ifdef WITH_WSREP + /* this can potentionally assert with wsrep */ + if (wsrep_on(trx->mysql_thd)) { + if (wsrep_debug && other_lock) { + fprintf(stderr, + "WSREP: InnoDB assert ignored\n"); + } + } else { + ut_a(!other_lock); + } +#else ut_a(!other_lock); +#endif /* WITH_WSREP */ } #endif /* UNIV_DEBUG */ @@ -2115,9 +2349,15 @@ lock_rec_add_to_queue( } somebody_waits: +#ifdef WITH_WSREP + return(lock_rec_create(NULL, NULL, + type_mode, block, heap_no, index, trx, + caller_owns_trx_mutex)); +#else return(lock_rec_create( type_mode, block, heap_no, index, trx, caller_owns_trx_mutex)); +#endif /* WITH_WSREP */ } /** Record locking request status */ @@ -2180,8 +2420,13 @@ lock_rec_lock_fast( if (lock == NULL) { if (!impl) { /* Note that we don't own the trx mutex. */ +#ifdef WITH_WSREP + lock = lock_rec_create(NULL, thr, + mode, block, heap_no, index, trx, FALSE); +#else lock = lock_rec_create( mode, block, heap_no, index, trx, FALSE); +#endif } status = LOCK_REC_SUCCESS_CREATED; @@ -2235,6 +2480,9 @@ lock_rec_lock_slow( que_thr_t* thr) /*!< in: query thread */ { trx_t* trx; +#ifdef WITH_WSREP + lock_t* c_lock(NULL); +#endif dberr_t err = DB_SUCCESS; ut_ad(lock_mutex_own()); @@ -2259,17 +2507,31 @@ lock_rec_lock_slow( /* The trx already has a strong enough lock on rec: do nothing */ +#ifdef WITH_WSREP + } else if ((c_lock = (lock_t *)lock_rec_other_has_conflicting( + static_cast(mode), + block, heap_no, trx))) { +#else } else if (lock_rec_other_has_conflicting( static_cast(mode), block, heap_no, trx)) { +#endif /* WITH_WSREP */ /* If another transaction has a non-gap conflicting request in the queue, as this transaction does not have a lock strong enough already granted on the record, we have to wait. */ +#ifdef WITH_WSREP + /* c_lock is NULL here if jump to enqueue_waiting happened + but it's ok because lock is not NULL in that case and c_lock + is not used. */ + err= + lock_rec_enqueue_waiting(c_lock, mode, block, heap_no, index, thr); +#else err = lock_rec_enqueue_waiting( mode, block, heap_no, index, thr); +#endif /* WITH_WSREP */ } else if (!impl) { /* Set the requested lock on the record, note that @@ -2321,6 +2583,7 @@ lock_rec_lock( ut_ad(mode - (LOCK_MODE_MASK & mode) == LOCK_GAP || mode - (LOCK_MODE_MASK & mode) == LOCK_REC_NOT_GAP || mode - (LOCK_MODE_MASK & mode) == 0); + ut_ad(dict_index_is_clust(index) || !dict_index_is_online_ddl(index)); /* We try a simplified and faster subroutine for the most @@ -3761,9 +4024,19 @@ lock_deadlock_select_victim( /* The joining transaction is 'smaller', choose it as the victim and roll it back. */ +#ifdef WITH_WSREP + if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) + return(ctx->wait_lock->trx); + else +#endif /* WITH_WSREP */ return(ctx->start); } +#ifdef WITH_WSREP + if (wsrep_thd_is_BF(ctx->wait_lock->trx->mysql_thd, TRUE)) + return(ctx->start); + else +#endif /* WITH_WSREP */ return(ctx->wait_lock->trx); } @@ -3893,6 +4166,11 @@ lock_deadlock_search( ctx->too_deep = TRUE; +#ifdef WITH_WSREP + if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) + return(ctx->wait_lock->trx->id); + else +#endif /* WITH_WSREP */ /* Select the joining transaction as the victim. */ return(ctx->start->id); @@ -3911,7 +4189,12 @@ lock_deadlock_search( ctx->too_deep = TRUE; - return(ctx->start->id); +#ifdef WITH_WSREP + if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) + return(lock->trx->id); + else +#endif /* WITH_WSREP */ + return(ctx->start->id); } ctx->wait_lock = lock->trx->lock.wait_lock; @@ -4029,9 +4312,18 @@ lock_deadlock_check_and_resolve( ut_a(trx == ctx.start); ut_a(victim_trx_id == trx->id); - if (!srv_read_only_mode) { - lock_deadlock_joining_trx_print(trx, lock); +#ifdef WITH_WSREP + if (!wsrep_thd_is_BF(ctx.start->mysql_thd, TRUE)) + { +#endif /* WITH_WSREP */ + if (!srv_read_only_mode) { + lock_deadlock_joining_trx_print(trx, lock); + } +#ifdef WITH_WSREP + } else { + /* BF processor */; } +#endif /* WITH_WSREP */ MONITOR_INC(MONITOR_DEADLOCK); @@ -4071,6 +4363,9 @@ UNIV_INLINE lock_t* lock_table_create( /*==============*/ +#ifdef WITH_WSREP + lock_t* c_lock, /*!< in: conflicting lock */ +#endif dict_table_t* table, /*!< in/out: database table in dictionary cache */ ulint type_mode,/*!< in: lock mode possibly ORed with @@ -4114,7 +4409,47 @@ lock_table_create( ut_ad(table->n_ref_count > 0 || !table->can_be_evicted); UT_LIST_ADD_LAST(trx_locks, trx->lock.trx_locks, lock); + +#ifdef WITH_WSREP + if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + UT_LIST_INSERT_AFTER( + un_member.tab_lock.locks, table->locks, c_lock, lock); + } else { + UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); + } + + if (c_lock) trx_mutex_enter(c_lock->trx); + if (c_lock && c_lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { + + c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE; + + if (wsrep_debug) wsrep_print_wait_locks(c_lock); + + /* have to release trx mutex for the duration of + victim lock release. This will eventually call + lock_grant, which wants to grant trx mutex again + */ + /* caller has trx_mutex, have to release for lock cancel */ + trx_mutex_exit(trx); + lock_cancel_waiting_and_release(c_lock->trx->lock.wait_lock); + trx_mutex_enter(trx); + + /* trx might not wait for c_lock, but some other lock + does not matter if wait_lock was released above + */ + if (c_lock->trx->lock.wait_lock == c_lock) { + lock_reset_lock_and_trx_wait(lock); + } + + if (wsrep_debug) { + fprintf(stderr, "WSREP: c_lock canceled %llu\n", + (ulonglong) c_lock->trx->id); + } + } + if (c_lock) trx_mutex_exit(c_lock->trx); +#else UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); +#endif /* WITH_WSREP */ if (UNIV_UNLIKELY(type_mode & LOCK_WAIT)) { @@ -4271,6 +4606,9 @@ static dberr_t lock_table_enqueue_waiting( /*=======================*/ +#ifdef WITH_WSREP + lock_t* c_lock, /*!< in: conflicting lock */ +#endif ulint mode, /*!< in: lock mode this transaction is requesting */ dict_table_t* table, /*!< in/out: table */ @@ -4317,7 +4655,14 @@ lock_table_enqueue_waiting( /* Enqueue the lock request that will wait to be granted */ +#ifdef WITH_WSREP + if (trx->lock.was_chosen_as_deadlock_victim) { + return(DB_DEADLOCK); + } + lock = lock_table_create(c_lock, table, mode | LOCK_WAIT, trx); +#else lock = lock_table_create(table, mode | LOCK_WAIT, trx); +#endif /* WITH_WSREP */ /* Release the mutex to obey the latching order. This is safe, because lock_deadlock_check_and_resolve() @@ -4394,6 +4739,14 @@ lock_table_other_has_incompatible( && !lock_mode_compatible(lock_get_mode(lock), mode) && (wait || !lock_get_wait(lock))) { +#ifdef WITH_WSREP + if (wsrep_debug) + fprintf(stderr, "WSREP: table lock abort"); + trx_mutex_enter(lock->trx); + wsrep_kill_victim((trx_t *)trx, (lock_t *)lock); + trx_mutex_exit(lock->trx); +#endif + return(lock); } } @@ -4416,6 +4769,9 @@ lock_table( enum lock_mode mode, /*!< in: lock mode */ que_thr_t* thr) /*!< in: query thread */ { +#ifdef WITH_WSREP + lock_t *c_lock = NULL; +#endif trx_t* trx; dberr_t err; const lock_t* wait_for; @@ -4450,8 +4806,13 @@ lock_table( /* We have to check if the new lock is compatible with any locks other transactions have in the table lock queue. */ +#ifdef WITH_WSREP + wait_for = lock_table_other_has_incompatible( + trx, LOCK_WAIT, table, mode); +#else wait_for = lock_table_other_has_incompatible( trx, LOCK_WAIT, table, mode); +#endif trx_mutex_enter(trx); @@ -4459,9 +4820,17 @@ lock_table( mode: this trx may have to wait */ if (wait_for != NULL) { +#ifdef WITH_WSREP + err = lock_table_enqueue_waiting((ib_lock_t*)wait_for, mode | flags, table, thr); +#else err = lock_table_enqueue_waiting(mode | flags, table, thr); +#endif } else { +#ifdef WITH_WSREP + lock_table_create(c_lock, table, mode | flags, trx); +#else lock_table_create(table, mode | flags, trx); +#endif ut_a(!flags || mode == LOCK_S || mode == LOCK_X); @@ -4499,7 +4868,11 @@ lock_table_ix_resurrect( trx, LOCK_WAIT, table, LOCK_IX)); trx_mutex_enter(trx); +#ifdef WITH_WSREP + lock_table_create(NULL, table, LOCK_IX, trx); +#else lock_table_create(table, LOCK_IX, trx); +#endif lock_mutex_exit(); trx_mutex_exit(trx); } @@ -5640,6 +6013,7 @@ lock_rec_queue_validate( if (!lock_rec_get_gap(lock) && !lock_get_wait(lock)) { +#ifndef WITH_WSREP enum lock_mode mode; if (lock_get_mode(lock) == LOCK_S) { @@ -5648,8 +6022,8 @@ lock_rec_queue_validate( mode = LOCK_S; } ut_a(!lock_rec_other_has_expl_req( - mode, 0, 0, block, heap_no, - lock->trx->id)); + mode, 0, 0, block, heap_no, lock->trx->id)); +#endif /* WITH_WSREP */ } else if (lock_get_wait(lock) && !lock_rec_get_gap(lock)) { @@ -5953,6 +6327,9 @@ lock_rec_insert_check_and_lock( lock_t* lock; dberr_t err; ulint next_rec_heap_no; +#ifdef WITH_WSREP + lock_t* c_lock=NULL; +#endif ut_ad(block->frame == page_align(rec)); ut_ad(!dict_index_is_online_ddl(index) @@ -6014,17 +6391,30 @@ lock_rec_insert_check_and_lock( had to wait for their insert. Both had waiting gap type lock requests on the successor, which produced an unnecessary deadlock. */ +#ifdef WITH_WSREP + if ((c_lock = (ib_lock_t*)lock_rec_other_has_conflicting( + static_cast( + LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION), + block, next_rec_heap_no, trx))) { +#else if (lock_rec_other_has_conflicting( static_cast( LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION), block, next_rec_heap_no, trx)) { +#endif /* WITH_WSREP */ /* Note that we may get DB_SUCCESS also here! */ trx_mutex_enter(trx); +#ifdef WITH_WSREP + err = lock_rec_enqueue_waiting(c_lock, + LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION, + block, next_rec_heap_no, index, thr); +#else err = lock_rec_enqueue_waiting( LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION, block, next_rec_heap_no, index, thr); +#endif /* WITH_WSREP */ trx_mutex_exit(trx); } else { diff --git a/storage/xtradb/lock/lock0wait.cc b/storage/xtradb/lock/lock0wait.cc index a1c35e20ead..388c847f580 100644 --- a/storage/xtradb/lock/lock0wait.cc +++ b/storage/xtradb/lock/lock0wait.cc @@ -184,6 +184,28 @@ lock_wait_table_reserve_slot( return(NULL); } +#ifdef WITH_WSREP +/*********************************************************************//** +check if lock timeout was for priority thread, +as a side effect trigger lock monitor +@return false for regular lock timeout */ +static ibool +wsrep_is_BF_lock_timeout( +/*====================*/ + trx_t* trx) /* in: trx to check for lock priority */ +{ + if (wsrep_on(trx->mysql_thd) && + wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + fprintf(stderr, "WSREP: BF lock wait long\n"); + srv_print_innodb_monitor = TRUE; + srv_print_innodb_lock_monitor = TRUE; + os_event_set(srv_monitor_event); + return TRUE; + } + return FALSE; + } +#endif /* WITH_WSREP */ + /***************************************************************//** Puts a user OS thread to wait for a lock to be released. If an error occurs during the wait trx->error_state associated with thr is @@ -375,9 +397,15 @@ lock_wait_suspend_thread( if (lock_wait_timeout < 100000000 && wait_time > (double) lock_wait_timeout) { +#ifdef WITH_WSREP + if (!wsrep_is_BF_lock_timeout(trx)) { +#endif /* WITH_WSREP */ trx->error_state = DB_LOCK_WAIT_TIMEOUT; +#ifdef WITH_WSREP + } +#endif /* WITH_WSREP */ MONITOR_INC(MONITOR_TIMEOUT); } @@ -461,8 +489,13 @@ lock_wait_check_and_cancel( if (trx->lock.wait_lock) { ut_a(trx->lock.que_state == TRX_QUE_LOCK_WAIT); - +#ifdef WITH_WSREP + if (!wsrep_is_BF_lock_timeout(trx)) { +#endif /* WITH_WSREP */ lock_cancel_waiting_and_release(trx->lock.wait_lock); +#ifdef WITH_WSREP + } +#endif /* WITH_WSREP */ } lock_mutex_exit(); diff --git a/storage/xtradb/os/os0file.cc b/storage/xtradb/os/os0file.cc index 394c3199f76..edcb6662fe9 100644 --- a/storage/xtradb/os/os0file.cc +++ b/storage/xtradb/os/os0file.cc @@ -110,6 +110,12 @@ UNIV_INTERN os_ib_mutex_t os_file_seek_mutexes[OS_FILE_N_SEEK_MUTEXES]; /* In simulated aio, merge at most this many consecutive i/os */ #define OS_AIO_MERGE_N_CONSECUTIVE 64 +#ifdef WITH_INNODB_DISALLOW_WRITES +#define WAIT_ALLOW_WRITES() os_event_wait(srv_allow_writes_event) +#else +#define WAIT_ALLOW_WRITES() do { } while (0) +#endif /* WITH_INNODB_DISALLOW_WRITES */ + /********************************************************************** InnoDB AIO Implementation: @@ -999,7 +1005,9 @@ os_file_create_tmpfile(void) /*========================*/ { FILE* file = NULL; - int fd = innobase_mysql_tmpfile(); + int fd; + WAIT_ALLOW_WRITES(); + fd = innobase_mysql_tmpfile(); ut_ad(!srv_read_only_mode); @@ -1325,6 +1333,7 @@ os_file_create_directory( return(TRUE); #else int rcode; + WAIT_ALLOW_WRITES(); rcode = mkdir(pathname, 0770); @@ -1451,6 +1460,8 @@ os_file_create_simple_func( #else /* __WIN__ */ int create_flag; + if (create_mode != OS_FILE_OPEN && create_mode != OS_FILE_OPEN_RAW) + WAIT_ALLOW_WRITES(); ut_a(!(create_mode & OS_FILE_ON_ERROR_SILENT)); ut_a(!(create_mode & OS_FILE_ON_ERROR_NO_EXIT)); @@ -1638,6 +1649,8 @@ os_file_create_simple_no_error_handling_func( int create_flag; ut_a(name); + if (create_mode != OS_FILE_OPEN && create_mode != OS_FILE_OPEN_RAW) + WAIT_ALLOW_WRITES(); ut_a(!(create_mode & OS_FILE_ON_ERROR_SILENT)); ut_a(!(create_mode & OS_FILE_ON_ERROR_NO_EXIT)); @@ -2013,6 +2026,8 @@ os_file_create_func( #else /* __WIN__ */ int create_flag; const char* mode_str = NULL; + if (create_mode != OS_FILE_OPEN && create_mode != OS_FILE_OPEN_RAW) + WAIT_ALLOW_WRITES(); on_error_no_exit = create_mode & OS_FILE_ON_ERROR_NO_EXIT ? TRUE : FALSE; @@ -2212,6 +2227,7 @@ loop: goto loop; #else int ret; + WAIT_ALLOW_WRITES(); ret = unlink(name); @@ -2276,6 +2292,7 @@ loop: goto loop; #else int ret; + WAIT_ALLOW_WRITES(); ret = unlink(name); @@ -2329,6 +2346,7 @@ os_file_rename_func( return(FALSE); #else int ret; + WAIT_ALLOW_WRITES(); ret = rename(oldpath, newpath); @@ -2562,6 +2580,7 @@ os_file_set_eof( HANDLE h = (HANDLE) _get_osfhandle(fileno(file)); return(SetEndOfFile(h)); #else /* __WIN__ */ + WAIT_ALLOW_WRITES(); return(!ftruncate(fileno(file), ftell(file))); #endif /* __WIN__ */ } @@ -2581,6 +2600,7 @@ os_file_set_eof_at( return(SetFilePointerEx(file, li, &li2,FILE_BEGIN) && SetEndOfFile(file)); #else + WAIT_ALLOW_WRITES(); /* TODO: works only with -D_FILE_OFFSET_BITS=64 ? */ return(!ftruncate(file, new_len)); #endif @@ -2680,6 +2700,7 @@ os_file_flush_func( return(FALSE); #else int ret; + WAIT_ALLOW_WRITES(); #if defined(HAVE_DARWIN_THREADS) # ifndef F_FULLFSYNC @@ -3382,6 +3403,7 @@ retry: return(FALSE); #else ssize_t ret; + WAIT_ALLOW_WRITES(); ret = os_file_pwrite(file, buf, n, offset); diff --git a/storage/xtradb/rem/rem0rec.cc b/storage/xtradb/rem/rem0rec.cc index 0d7b7c16785..ca9b0a6b841 100644 --- a/storage/xtradb/rem/rem0rec.cc +++ b/storage/xtradb/rem/rem0rec.cc @@ -33,6 +33,9 @@ Created 5/30/1994 Heikki Tuuri #include "mtr0mtr.h" #include "mtr0log.h" #include "fts0fts.h" +#ifdef WITH_WSREP +#include +#endif /* WITH_WSREP */ /* PHYSICAL RECORD (OLD STYLE) =========================== @@ -1917,6 +1920,138 @@ rec_print( } } } +#endif /* !UNIV_HOTBACKUP */ + +#ifdef WITH_WSREP +int +wsrep_rec_get_foreign_key( + byte *buf, /* out: extracted key */ + ulint *buf_len, /* in/out: length of buf */ + const rec_t* rec, /* in: physical record */ + dict_index_t* index_for, /* in: index in foreign table */ + dict_index_t* index_ref, /* in: index in referenced table */ + ibool new_protocol) /* in: protocol > 1 */ +{ + const byte* data; + ulint len; + ulint key_len = 0; + ulint i; + uint key_parts; + mem_heap_t* heap = NULL; + ulint offsets_[REC_OFFS_NORMAL_SIZE]; + const ulint* offsets; + + ut_ad(index_for); + ut_ad(index_ref); + + rec_offs_init(offsets_); + offsets = rec_get_offsets(rec, index_for, offsets_, + ULINT_UNDEFINED, &heap); + + ut_ad(rec_offs_validate(rec, NULL, offsets)); + + ut_ad(rec); + + key_parts = dict_index_get_n_unique_in_tree(index_for); + for (i = 0; + i < key_parts && + (index_for->type & DICT_CLUSTERED || i < key_parts - 1); + i++) { + dict_field_t* field_f = + dict_index_get_nth_field(index_for, i); + const dict_col_t* col_f = dict_field_get_col(field_f); + dict_field_t* field_r = + dict_index_get_nth_field(index_ref, i); + const dict_col_t* col_r = dict_field_get_col(field_r); + + data = rec_get_nth_field(rec, offsets, i, &len); + if (key_len + ((len != UNIV_SQL_NULL) ? len + 1 : 1) > + *buf_len) { + fprintf (stderr, + "WSREP: FK key len exceeded %lu %lu %lu\n", + key_len, len, *buf_len); + goto err_out; + } + + if (len == UNIV_SQL_NULL) { + ut_a(!(col_f->prtype & DATA_NOT_NULL)); + *buf++ = 1; + key_len++; + } else if (!new_protocol) { + if (!(col_r->prtype & DATA_NOT_NULL)) { + *buf++ = 0; + key_len++; + } + memcpy(buf, data, len); + *buf_len = wsrep_innobase_mysql_sort( + (int)(col_f->prtype & DATA_MYSQL_TYPE_MASK), + (uint)dtype_get_charset_coll(col_f->prtype), + buf, len, *buf_len); + } else { /* new protocol */ + if (!(col_r->prtype & DATA_NOT_NULL)) { + *buf++ = 0; + key_len++; + } + switch (col_f->mtype) { + case DATA_INT: { + byte* ptr = buf+len; + for (;;) { + ptr--; + *ptr = *data; + if (ptr == buf) { + break; + } + data++; + } + + if (!(col_f->prtype & DATA_UNSIGNED)) { + buf[len-1] = (byte) (buf[len-1] ^ 128); + } + + break; + } + case DATA_VARCHAR: + case DATA_VARMYSQL: + case DATA_CHAR: + case DATA_MYSQL: + /* Copy the actual data */ + ut_memcpy(buf, data, len); + len = wsrep_innobase_mysql_sort( + (int) + (col_f->prtype & DATA_MYSQL_TYPE_MASK), + (uint) + dtype_get_charset_coll(col_f->prtype), + buf, len, *buf_len); + break; + case DATA_BLOB: + case DATA_BINARY: + memcpy(buf, data, len); + break; + default: + break; + } + + key_len += len; + buf += len; + } + } + + rec_validate(rec, offsets); + + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); + } + + *buf_len = key_len; + return DB_SUCCESS; + + err_out: + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); + } + return DB_ERROR; +} +#endif /* WITH_WSREP */ # ifdef UNIV_DEBUG /************************************************************//** @@ -1959,5 +2094,5 @@ rec_get_trx_id( return(trx_read_trx_id(trx_id)); } -# endif /* UNIV_DEBUG */ -#endif /* !UNIV_HOTBACKUP */ +#endif /* UNIV_DEBUG */ + diff --git a/storage/xtradb/row/row0ins.cc b/storage/xtradb/row/row0ins.cc index f8ca40fac12..444fac87842 100644 --- a/storage/xtradb/row/row0ins.cc +++ b/storage/xtradb/row/row0ins.cc @@ -918,6 +918,14 @@ row_ins_invalidate_query_cache( innobase_invalidate_query_cache(thr_get_trx(thr), buf, len); mem_free(buf); } +#ifdef WITH_WSREP +dberr_t wsrep_append_foreign_key(trx_t *trx, + dict_foreign_t* foreign, + const rec_t* clust_rec, + dict_index_t* clust_index, + ibool referenced, + ibool shared); +#endif /* WITH_WSREP */ /*********************************************************************//** Perform referential actions or checks when a parent row is deleted or updated @@ -1269,7 +1277,19 @@ row_ins_foreign_check_on_constraint( cascade->state = UPD_NODE_UPDATE_CLUSTERED; - err = row_update_cascade_for_mysql(thr, cascade, +#ifdef WITH_WSREP + err = wsrep_append_foreign_key( + thr_get_trx(thr), + foreign, + clust_rec, + clust_index, + FALSE, FALSE); + if (err != DB_SUCCESS) { + fprintf(stderr, + "WSREP: foreign key append failed: %d\n", err); + } else +#endif /* WITH_WSREP */ + err = row_update_cascade_for_mysql(thr, cascade, foreign->foreign_table); if (foreign->foreign_table->n_foreign_key_checks_running == 0) { @@ -1607,7 +1627,14 @@ run_again: if (check_ref) { err = DB_SUCCESS; - +#ifdef WITH_WSREP + err = wsrep_append_foreign_key( + thr_get_trx(thr), + foreign, + rec, + check_index, + check_ref, TRUE); +#endif /* WITH_WSREP */ goto end_scan; } else if (foreign->type != 0) { /* There is an ON UPDATE or ON DELETE diff --git a/storage/xtradb/row/row0upd.cc b/storage/xtradb/row/row0upd.cc index 3ead385c2cd..4b8dff7b47f 100644 --- a/storage/xtradb/row/row0upd.cc +++ b/storage/xtradb/row/row0upd.cc @@ -53,6 +53,9 @@ Created 12/27/1996 Heikki Tuuri #include "pars0sym.h" #include "eval0eval.h" #include "buf0lru.h" +#ifdef WITH_WSREP +extern my_bool wsrep_debug; +#endif /* What kind of latch and lock can we assume when the control comes to @@ -172,6 +175,50 @@ func_exit: return(is_referenced); } +#ifdef WITH_WSREP +static +ibool +wsrep_row_upd_index_is_foreign( +/*========================*/ + dict_index_t* index, /*!< in: index */ + trx_t* trx) /*!< in: transaction */ +{ + dict_table_t* table = index->table; + dict_foreign_t* foreign; + ibool froze_data_dict = FALSE; + ibool is_referenced = FALSE; + + if (!UT_LIST_GET_FIRST(table->foreign_list)) { + + return(FALSE); + } + + if (trx->dict_operation_lock_mode == 0) { + row_mysql_freeze_data_dictionary(trx); + froze_data_dict = TRUE; + } + + foreign = UT_LIST_GET_FIRST(table->foreign_list); + + while (foreign) { + if (foreign->foreign_index == index) { + + is_referenced = TRUE; + goto func_exit; + } + + foreign = UT_LIST_GET_NEXT(foreign_list, foreign); + } + +func_exit: + if (froze_data_dict) { + row_mysql_unfreeze_data_dictionary(trx); + } + + return(is_referenced); +} +#endif /* WITH_WSREP */ + /*********************************************************************//** Checks if possible foreign key constraints hold after a delete of the record under pcur. @@ -289,7 +336,132 @@ run_again: } err = DB_SUCCESS; +func_exit: + if (got_s_lock) { + row_mysql_unfreeze_data_dictionary(trx); + } + mem_heap_free(heap); + + return(err); +} +#ifdef WITH_WSREP +static +dberr_t +wsrep_row_upd_check_foreign_constraints( +/*=================================*/ + upd_node_t* node, /*!< in: row update node */ + btr_pcur_t* pcur, /*!< in: cursor positioned on a record; NOTE: the + cursor position is lost in this function! */ + dict_table_t* table, /*!< in: table in question */ + dict_index_t* index, /*!< in: index of the cursor */ + ulint* offsets,/*!< in/out: rec_get_offsets(pcur.rec, index) */ + que_thr_t* thr, /*!< in: query thread */ + mtr_t* mtr) /*!< in: mtr */ +{ + dict_foreign_t* foreign; + mem_heap_t* heap; + dtuple_t* entry; + trx_t* trx; + const rec_t* rec; + ulint n_ext; + dberr_t err; + ibool got_s_lock = FALSE; + ibool opened = FALSE; + + if (UT_LIST_GET_FIRST(table->foreign_list) == NULL) { + + return(DB_SUCCESS); + } + + trx = thr_get_trx(thr); + + /* TODO: make native slave thread bail out here */ + + rec = btr_pcur_get_rec(pcur); + ut_ad(rec_offs_validate(rec, index, offsets)); + + heap = mem_heap_create(500); + + entry = row_rec_to_index_entry(rec, index, offsets, + &n_ext, heap); + + mtr_commit(mtr); + + mtr_start(mtr); + + if (trx->dict_operation_lock_mode == 0) { + got_s_lock = TRUE; + + row_mysql_freeze_data_dictionary(trx); + } + + foreign = UT_LIST_GET_FIRST(table->foreign_list); + + while (foreign) { + /* Note that we may have an update which updates the index + record, but does NOT update the first fields which are + referenced in a foreign key constraint. Then the update does + NOT break the constraint. */ + + if (foreign->foreign_index == index + && (node->is_delete + || row_upd_changes_first_fields_binary( + entry, index, node->update, + foreign->n_fields))) { + + if (foreign->referenced_table == NULL) { + foreign->referenced_table = + dict_table_open_on_name( + foreign->referenced_table_name_lookup, + FALSE, FALSE, DICT_ERR_IGNORE_NONE); + opened = TRUE; + } + + if (foreign->referenced_table) { + mutex_enter(&(dict_sys->mutex)); + + (foreign->referenced_table + ->n_foreign_key_checks_running)++; + + mutex_exit(&(dict_sys->mutex)); + } + + /* NOTE that if the thread ends up waiting for a lock + we will release dict_operation_lock temporarily! + But the counter on the table protects 'foreign' from + being dropped while the check is running. */ + + err = row_ins_check_foreign_constraint( + TRUE, foreign, table, entry, thr); + + if (foreign->referenced_table) { + mutex_enter(&(dict_sys->mutex)); + + ut_a(foreign->referenced_table + ->n_foreign_key_checks_running > 0); + + (foreign->referenced_table + ->n_foreign_key_checks_running)--; + + if (opened == TRUE) { + dict_table_close(foreign->referenced_table, TRUE, FALSE); + opened = FALSE; + } + + mutex_exit(&(dict_sys->mutex)); + } + + if (err != DB_SUCCESS) { + + goto func_exit; + } + } + + foreign = UT_LIST_GET_NEXT(foreign_list, foreign); + } + + err = DB_SUCCESS; func_exit: if (got_s_lock) { row_mysql_unfreeze_data_dictionary(trx); @@ -301,6 +473,7 @@ func_exit: return(err); } +#endif /* WITH_WSREP */ /*********************************************************************//** Creates an update node for a query graph. @@ -1675,6 +1848,9 @@ row_upd_sec_index_entry( index = node->index; referenced = row_upd_index_is_referenced(index, trx); +#ifdef WITH_WSREP + ibool foreign = wsrep_row_upd_index_is_foreign(index, trx); +#endif /* WITH_WSREP */ heap = mem_heap_create(1024); @@ -1805,6 +1981,9 @@ row_upd_sec_index_entry( row_ins_sec_index_entry() below */ if (!rec_get_deleted_flag( rec, dict_table_is_comp(index->table))) { +#ifdef WITH_WSREP + que_node_t *parent = que_node_get_parent(node); +#endif /* WITH_WSREP */ err = btr_cur_del_mark_set_sec_rec( 0, btr_cur, TRUE, thr, &mtr); @@ -1822,6 +2001,37 @@ row_upd_sec_index_entry( node, &pcur, index->table, index, offsets, thr, &mtr); } +#ifdef WITH_WSREP + if (err == DB_SUCCESS && !referenced && + !(parent && que_node_get_type(parent) == + QUE_NODE_UPDATE && + ((upd_node_t*)parent)->cascade_node == node) && + foreign + ) { + ulint* offsets = + rec_get_offsets( + rec, index, NULL, ULINT_UNDEFINED, + &heap); + err = wsrep_row_upd_check_foreign_constraints( + node, &pcur, index->table, + index, offsets, thr, &mtr); + switch (err) { + case DB_SUCCESS: + case DB_NO_REFERENCED_ROW: + err = DB_SUCCESS; + break; + case DB_DEADLOCK: + if (wsrep_debug) fprintf (stderr, + "WSREP: sec index FK check fail for deadlock"); + break; + default: + fprintf (stderr, + "WSREP: referenced FK check fail: %d", + (int)err); + break; + } + } +#endif /* WITH_WSREP */ } break; } @@ -1976,6 +2186,9 @@ row_upd_clust_rec_by_insert( que_thr_t* thr, /*!< in: query thread */ ibool referenced,/*!< in: TRUE if index may be referenced in a foreign key constraint */ +#ifdef WITH_WSREP + ibool foreign, /*!< in: TRUE if index is foreign key index */ +#endif /* WITH_WSREP */ mtr_t* mtr) /*!< in/out: mtr; gets committed here */ { mem_heap_t* heap; @@ -1989,6 +2202,9 @@ row_upd_clust_rec_by_insert( rec_t* rec; ulint* offsets = NULL; +#ifdef WITH_WSREP + que_node_t *parent = que_node_get_parent(node); +#endif /* WITH_WSREP */ ut_ad(node); ut_ad(dict_index_is_clust(index)); @@ -2074,6 +2290,34 @@ err_exit: goto err_exit; } } +#ifdef WITH_WSREP + if (!referenced && + !(parent && que_node_get_type(parent) == QUE_NODE_UPDATE && + ((upd_node_t*)parent)->cascade_node == node) && + foreign + ) { + err = wsrep_row_upd_check_foreign_constraints( + node, pcur, table, index, offsets, thr, mtr); + switch (err) { + case DB_SUCCESS: + case DB_NO_REFERENCED_ROW: + err = DB_SUCCESS; + break; + case DB_DEADLOCK: + if (wsrep_debug) fprintf (stderr, + "WSREP: insert FK check fail for deadlock"); + break; + default: + fprintf (stderr, + "WSREP: referenced FK check fail: %d", + (int)err); + break; + } + if (err != DB_SUCCESS) { + goto err_exit; + } + } +#endif /* WITH_WSREP */ } mtr_commit(mtr); @@ -2269,11 +2513,18 @@ row_upd_del_mark_clust_rec( ibool referenced, /*!< in: TRUE if index may be referenced in a foreign key constraint */ +#ifdef WITH_WSREP + ibool foreign,/*!< in: TRUE if index is foreign key index */ +#endif /* WITH_WSREP */ mtr_t* mtr) /*!< in: mtr; gets committed here */ { btr_pcur_t* pcur; btr_cur_t* btr_cur; dberr_t err; +#ifdef WITH_WSREP + rec_t* rec; + que_node_t *parent = que_node_get_parent(node); +#endif /* WITH_WSREP */ ut_ad(node); ut_ad(dict_index_is_clust(index)); @@ -2290,8 +2541,16 @@ row_upd_del_mark_clust_rec( /* Mark the clustered index record deleted; we do not have to check locks, because we assume that we have an x-lock on the record */ +#ifdef WITH_WSREP + rec = btr_cur_get_rec(btr_cur); +#endif /* WITH_WSREP */ + err = btr_cur_del_mark_set_clust_rec( +#ifdef WITH_WSREP + btr_cur_get_block(btr_cur), rec, +#else btr_cur_get_block(btr_cur), btr_cur_get_rec(btr_cur), +#endif /* WITH_WSREP */ index, offsets, thr, mtr); if (err == DB_SUCCESS && referenced) { /* NOTE that the following call loses the position of pcur ! */ @@ -2299,6 +2558,32 @@ row_upd_del_mark_clust_rec( err = row_upd_check_references_constraints( node, pcur, index->table, index, offsets, thr, mtr); } +#ifdef WITH_WSREP + if (err == DB_SUCCESS && !referenced && + !(parent && que_node_get_type(parent) == QUE_NODE_UPDATE && + ((upd_node_t*)parent)->cascade_node == node) && + thr_get_trx(thr) && + foreign + ) { + err = wsrep_row_upd_check_foreign_constraints( + node, pcur, index->table, index, offsets, thr, mtr); + switch (err) { + case DB_SUCCESS: + case DB_NO_REFERENCED_ROW: + err = DB_SUCCESS; + break; + case DB_DEADLOCK: + if (wsrep_debug) fprintf (stderr, + "WSREP: clust rec FK check fail for deadlock"); + break; + default: + fprintf (stderr, + "WSREP: clust rec referenced FK check fail: %d", + (int)err); + break; + } + } +#endif /* WITH_WSREP */ mtr_commit(mtr); @@ -2331,6 +2616,10 @@ row_upd_clust_step( index = dict_table_get_first_index(node->table); referenced = row_upd_index_is_referenced(index, thr_get_trx(thr)); +#ifdef WITH_WSREP + ibool foreign = wsrep_row_upd_index_is_foreign( + index, thr_get_trx(thr)); +#endif /* WITH_WSREP */ pcur = node->pcur; @@ -2427,7 +2716,11 @@ row_upd_clust_step( if (node->is_delete) { err = row_upd_del_mark_clust_rec( +#ifdef WITH_WSREP + node, index, offsets, thr, referenced, foreign, &mtr); +#else node, index, offsets, thr, referenced, &mtr); +#endif /* WITH_WSREP */ if (err == DB_SUCCESS) { node->state = UPD_NODE_UPDATE_ALL_SEC; @@ -2472,7 +2765,11 @@ row_upd_clust_step( externally! */ err = row_upd_clust_rec_by_insert( +#ifdef WITH_WSREP + node, index, thr, referenced, foreign, &mtr); +#else node, index, thr, referenced, &mtr); +#endif /* WITH_WSREP */ if (err != DB_SUCCESS) { diff --git a/storage/xtradb/srv/srv0conc.cc b/storage/xtradb/srv/srv0conc.cc index 6c15753246a..5868e4e012b 100644 --- a/storage/xtradb/srv/srv0conc.cc +++ b/storage/xtradb/srv/srv0conc.cc @@ -43,6 +43,10 @@ Created 2011/04/18 Sunny Bains #include "trx0trx.h" #include "mysql/plugin.h" +#ifdef WITH_WSREP +extern "C" int wsrep_trx_is_aborting(void *thd_ptr); +extern my_bool wsrep_debug; +#endif /** Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket. */ @@ -87,6 +91,9 @@ struct srv_conc_slot_t{ reserved may still be TRUE at that point */ srv_conc_node_t srv_conc_queue; /*!< queue node */ +#ifdef WITH_WSREP + void *thd; /*!< to see priority */ +#endif }; /** Queue of threads waiting to get in */ @@ -146,6 +153,9 @@ srv_conc_init(void) conc_slot->event = os_event_create(); ut_a(conc_slot->event); +#ifdef WITH_WSREP + conc_slot->thd = NULL; +#endif /* WITH_WSREP */ } #endif /* !HAVE_ATOMIC_BUILTINS */ } @@ -203,6 +213,16 @@ srv_conc_enter_innodb_with_atomics( for (;;) { ulint sleep_in_us; +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd) && + wsrep_trx_is_aborting(trx->mysql_thd)) { + if (wsrep_debug) + fprintf(stderr, + "srv_conc_enter due to MUST_ABORT"); + srv_conc_force_enter_innodb(trx); + return; + } +#endif /* WITH_WSREP */ if (srv_conc.n_active < (lint) srv_thread_concurrency) { ulint n_active; @@ -321,6 +341,9 @@ srv_conc_exit_innodb_without_atomics( slot = NULL; if (srv_conc.n_active < (lint) srv_thread_concurrency) { +#ifdef WITH_WSREP + srv_conc_slot_t* wsrep_slot; +#endif /* Look for a slot where a thread is waiting and no other thread has yet released the thread */ @@ -331,6 +354,19 @@ srv_conc_exit_innodb_without_atomics( /* No op */ } +#ifdef WITH_WSREP + /* look for aborting trx, they must be released asap */ + wsrep_slot= slot; + while (wsrep_slot && (wsrep_slot->wait_ended == TRUE || + !wsrep_trx_is_aborting(wsrep_slot->thd))) { + wsrep_slot = UT_LIST_GET_NEXT(srv_conc_queue, wsrep_slot); + } + if (wsrep_slot) { + slot = wsrep_slot; + if (wsrep_debug) + fprintf(stderr, "WSREP: releasing aborting thd\n"); + } +#endif if (slot != NULL) { slot->wait_ended = TRUE; @@ -390,6 +426,13 @@ retry: return; } +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd) && + wsrep_thd_is_brute_force(trx->mysql_thd)) { + srv_conc_force_enter_innodb(trx); + return; + } +#endif /* If the transaction is not holding resources, let it sleep for srv_thread_sleep_delay microseconds, and try again then */ @@ -457,6 +500,9 @@ retry: /* Add to the queue */ slot->reserved = TRUE; slot->wait_ended = FALSE; +#ifdef WITH_WSREP + slot->thd = trx->mysql_thd; +#endif UT_LIST_ADD_LAST(srv_conc_queue, srv_conc_queue, slot); @@ -464,6 +510,18 @@ retry: srv_conc.n_waiting++; +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd) && + wsrep_trx_is_aborting(trx->mysql_thd)) { + os_fast_mutex_unlock(&srv_conc_mutex); + if (wsrep_debug) + fprintf(stderr, "srv_conc_enter due to MUST_ABORT"); + trx->declared_to_be_inside_innodb = TRUE; + trx->n_tickets_to_enter_innodb = srv_n_free_tickets_to_enter; + return; + } + trx->wsrep_event = slot->event; +#endif /* WITH_WSREP */ os_fast_mutex_unlock(&srv_conc_mutex); /* Go to wait for the event; when a thread leaves InnoDB it will @@ -487,6 +545,9 @@ retry: os_event_wait(slot->event); thd_wait_end(trx->mysql_thd); +#ifdef WITH_WSREP + trx->wsrep_event = NULL; +#endif /* WITH_WSREP */ trx->op_info = ""; @@ -504,6 +565,9 @@ retry: incremented the thread counter on behalf of this thread */ slot->reserved = FALSE; +#ifdef WITH_WSREP + slot->thd = NULL; +#endif UT_LIST_REMOVE(srv_conc_queue, srv_conc_queue, slot); @@ -614,5 +678,32 @@ srv_conc_get_active_threads(void) /*==============================*/ { return(srv_conc.n_active); - } +} + +#ifdef WITH_WSREP +UNIV_INTERN +void +wsrep_srv_conc_cancel_wait( +/*==================*/ + trx_t* trx) /*!< in: transaction object associated with the + thread */ +{ +#ifdef HAVE_ATOMIC_BUILTINS + /* aborting transactions will enter innodb by force in + srv_conc_enter_innodb_with_atomics(). No need to cancel here, + thr will wake up after os_sleep and let to enter innodb + */ + if (wsrep_debug) + fprintf(stderr, "WSREP: conc slot cancel, no atomics\n"); +#else + os_fast_mutex_lock(&srv_conc_mutex); + if (trx->wsrep_event) { + if (wsrep_debug) + fprintf(stderr, "WSREP: conc slot cancel\n"); + os_event_set(trx->wsrep_event); + } + os_fast_mutex_unlock(&srv_conc_mutex); +#endif +} +#endif /* WITH_WSREP */ diff --git a/storage/xtradb/srv/srv0srv.cc b/storage/xtradb/srv/srv0srv.cc index 8e01ea7402e..d421980d41a 100644 --- a/storage/xtradb/srv/srv0srv.cc +++ b/storage/xtradb/srv/srv0srv.cc @@ -84,6 +84,14 @@ ulong innobase_thd_get_thread_id(const void* thd); /* prototypes for new functions added to ha_innodb.cc */ ibool innobase_get_slow_log(); +#ifdef WITH_WSREP +extern int wsrep_debug; +extern int wsrep_trx_is_aborting(void *thd_ptr); +#endif +/* The following counter is incremented whenever there is some user activity +in the server */ +UNIV_INTERN ulint srv_activity_count = 0; + /* The following is the maximum allowed duration of a lock wait. */ UNIV_INTERN ulint srv_fatal_semaphore_wait_threshold = 600; @@ -254,6 +262,10 @@ srv_printf_innodb_monitor() will request mutex acquisition with mutex_enter(), which will wait until it gets the mutex. */ #define MUTEX_NOWAIT(mutex_skipped) ((mutex_skipped) < MAX_MUTEX_NOWAIT) +#ifdef WITH_INNODB_DISALLOW_WRITES +UNIV_INTERN os_event_t srv_allow_writes_event; +#endif /* WITH_INNODB_DISALLOW_WRITES */ + /** The sort order table of the MySQL latin1_swedish_ci character set collation */ UNIV_INTERN const byte* srv_latin1_ordering; @@ -1150,6 +1162,14 @@ srv_init(void) dict_ind_init(); srv_conc_init(); +#ifdef WITH_INNODB_DISALLOW_WRITES + /* Writes have to be enabled on init or else we hang. Thus, we + always set the event here regardless of innobase_disallow_writes. + That flag will always be 0 at this point because it isn't settable + via my.cnf or command line arg. */ + srv_allow_writes_event = os_event_create(); + os_event_set(srv_allow_writes_event); +#endif /* WITH_INNODB_DISALLOW_WRITES */ /* Initialize some INFORMATION SCHEMA internal structures */ trx_i_s_cache_init(trx_i_s_cache); @@ -2158,7 +2178,20 @@ loop: if (sync_array_print_long_waits(&waiter, &sema) && sema == old_sema && os_thread_eq(waiter, old_waiter)) { +#if defined(WITH_WSREP) && defined(WITH_INNODB_DISALLOW_WRITES) + if (srv_allow_writes_event->is_set) { +#endif /* WITH_WSREP */ fatal_cnt++; +#if defined(WITH_WSREP) && defined(WITH_INNODB_DISALLOW_WRITES) + } else { + fprintf(stderr, + "WSREP: avoiding InnoDB self crash due to long " + "semaphore wait of > %lu seconds\n" + "Server is processing SST donor operation, " + "fatal_cnt now: %lu", + (ulong) srv_fatal_semaphore_wait_threshold, fatal_cnt); + } +#endif /* WITH_WSREP */ if (fatal_cnt > 10) { fprintf(stderr, diff --git a/storage/xtradb/trx/trx0roll.cc b/storage/xtradb/trx/trx0roll.cc index 1089607c6d1..eb2af877a6d 100644 --- a/storage/xtradb/trx/trx0roll.cc +++ b/storage/xtradb/trx/trx0roll.cc @@ -45,6 +45,9 @@ Created 3/26/1996 Heikki Tuuri #include "pars0pars.h" #include "srv0mon.h" #include "trx0sys.h" +#ifdef WITH_WSREP +#include "ha_prototypes.h" +#endif /* WITH_WSREP */ /** This many pages must be undone before a truncate is tried within rollback */ @@ -382,6 +385,13 @@ trx_rollback_to_savepoint_for_mysql_low( trx->op_info = ""; +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd) && + trx->lock.was_chosen_as_deadlock_victim) { + trx->lock.was_chosen_as_deadlock_victim = FALSE; + } +#endif + return(err); } @@ -1020,6 +1030,12 @@ trx_roll_try_truncate( if (trx->update_undo) { trx_undo_truncate_end(trx, trx->update_undo, limit); } + +#ifdef WITH_WSREP_OUT + if (wsrep_on(trx->mysql_thd)) { + trx->lock.was_chosen_as_deadlock_victim = FALSE; + } +#endif /* WITH_WSREP */ } /***********************************************************************//** diff --git a/storage/xtradb/trx/trx0sys.cc b/storage/xtradb/trx/trx0sys.cc index aab99a793f6..19d14bf6f38 100644 --- a/storage/xtradb/trx/trx0sys.cc +++ b/storage/xtradb/trx/trx0sys.cc @@ -44,6 +44,10 @@ Created 3/26/1996 Heikki Tuuri #include "os0file.h" #include "read0read.h" +#ifdef WITH_WSREP +#include "ha_prototypes.h" /* wsrep_is_wsrep_xid() */ +#endif /* */ + /** The file format tag structure with id and name. */ struct file_format_t { ulint id; /*!< id of the file format */ @@ -174,7 +178,12 @@ trx_sys_flush_max_trx_id(void) mtr_t mtr; trx_sysf_t* sys_header; +#ifndef WITH_WSREP + /* wsrep_fake_trx_id violates this assert + * Copied from trx_sys_get_new_trx_id + */ ut_ad(mutex_own(&trx_sys->mutex)); +#endif /* WITH_WSREP */ if (!srv_read_only_mode) { mtr_start(&mtr); @@ -202,9 +211,14 @@ trx_sys_update_mysql_binlog_offset( ib_int64_t offset, /*!< in: position in that log file */ ulint field, /*!< in: offset of the MySQL log info field in the trx sys header */ +#ifdef WITH_WSREP + trx_sysf_t* sys_header, /*!< in: trx sys header */ +#endif /* WITH_WSREP */ mtr_t* mtr) /*!< in: mtr */ { +#ifndef WITH_WSREP trx_sysf_t* sys_header; +#endif /* !WITH_WSREP */ if (ut_strlen(file_name) >= TRX_SYS_MYSQL_LOG_NAME_LEN) { @@ -213,7 +227,9 @@ trx_sys_update_mysql_binlog_offset( return; } +#ifndef WITH_WSREP sys_header = trx_sysf_get(mtr); +#endif /* !WITH_WSREP */ if (mach_read_from_4(sys_header + field + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD) @@ -300,6 +316,124 @@ trx_sys_print_mysql_binlog_offset(void) mtr_commit(&mtr); } +#ifdef WITH_WSREP + +#ifdef UNIV_DEBUG +static long long trx_sys_cur_xid_seqno = -1; +static unsigned char trx_sys_cur_xid_uuid[16]; + +long long read_wsrep_xid_seqno(const XID* xid) +{ + long long seqno; + memcpy(&seqno, xid->data + 24, sizeof(long long)); + return seqno; +} + +void read_wsrep_xid_uuid(const XID* xid, unsigned char* buf) +{ + memcpy(buf, xid->data + 8, 16); +} + +#endif /* UNIV_DEBUG */ + +void +trx_sys_update_wsrep_checkpoint( + const XID* xid, /*!< in: transaction XID */ + trx_sysf_t* sys_header, /*!< in: sys_header */ + mtr_t* mtr) /*!< in: mtr */ +{ +#ifdef UNIV_DEBUG + { + /* Check that seqno is monotonically increasing */ + unsigned char xid_uuid[16]; + long long xid_seqno = read_wsrep_xid_seqno(xid); + read_wsrep_xid_uuid(xid, xid_uuid); + if (!memcmp(xid_uuid, trx_sys_cur_xid_uuid, 8)) + { + ut_ad(xid_seqno > trx_sys_cur_xid_seqno); + trx_sys_cur_xid_seqno = xid_seqno; + } + else + { + memcpy(trx_sys_cur_xid_uuid, xid_uuid, 16); + } + trx_sys_cur_xid_seqno = xid_seqno; + } +#endif /* UNIV_DEBUG */ + + ut_ad(xid && mtr); + ut_a(xid->formatID == -1 || wsrep_is_wsrep_xid((const void *)xid)); + + if (mach_read_from_4(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_MAGIC_N_FLD) + != TRX_SYS_WSREP_XID_MAGIC_N) { + mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_MAGIC_N_FLD, + TRX_SYS_WSREP_XID_MAGIC_N, + MLOG_4BYTES, mtr); + } + + mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_FORMAT, + (int)xid->formatID, + MLOG_4BYTES, mtr); + mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_GTRID_LEN, + (int)xid->gtrid_length, + MLOG_4BYTES, mtr); + mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_BQUAL_LEN, + (int)xid->bqual_length, + MLOG_4BYTES, mtr); + mlog_write_string(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_DATA, + (const unsigned char*) xid->data, + XIDDATASIZE, mtr); + +} + +void +trx_sys_read_wsrep_checkpoint(XID* xid) +/*===================================*/ +{ + trx_sysf_t* sys_header; + mtr_t mtr; + ulint magic; + + ut_ad(xid); + + mtr_start(&mtr); + + sys_header = trx_sysf_get(&mtr); + + if ((magic = mach_read_from_4(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_MAGIC_N_FLD)) + != TRX_SYS_WSREP_XID_MAGIC_N) { + memset(xid, 0, sizeof(*xid)); + xid->formatID = -1; + trx_sys_update_wsrep_checkpoint(xid, sys_header, &mtr); + mtr_commit(&mtr); + return; + } + + xid->formatID = (int)mach_read_from_4( + sys_header + + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_FORMAT); + xid->gtrid_length = (int)mach_read_from_4( + sys_header + + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_GTRID_LEN); + xid->bqual_length = (int)mach_read_from_4( + sys_header + + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_BQUAL_LEN); + ut_memcpy(xid->data, + sys_header + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_DATA, + XIDDATASIZE); + + mtr_commit(&mtr); +} + +#endif /* WITH_WSREP */ + /*****************************************************************//** Prints to stderr the MySQL master log offset info in the trx system header if the magic number shows it valid. */ diff --git a/storage/xtradb/trx/trx0trx.cc b/storage/xtradb/trx/trx0trx.cc index f2c78bafd86..d26517637cd 100644 --- a/storage/xtradb/trx/trx0trx.cc +++ b/storage/xtradb/trx/trx0trx.cc @@ -294,6 +294,9 @@ trx_create(void) trx->lock.table_locks = ib_vector_create( heap_alloc, sizeof(void**), 32); +#ifdef WITH_WSREP + trx->wsrep_event = NULL; +#endif /* WITH_WSREP */ return(trx); } @@ -1041,6 +1044,11 @@ trx_start_low( srv_undo_logs, srv_undo_tablespaces); } +#ifdef WITH_WSREP + memset(&trx->xid, 0, sizeof(trx->xid)); + trx->xid.formatID = -1; +#endif /* WITH_WSREP */ + /* The initial value for trx->no: TRX_ID_MAX is used in read_view_open_now: */ @@ -1166,6 +1174,9 @@ trx_write_serialisation_history( trx_t* trx, /*!< in/out: transaction */ mtr_t* mtr) /*!< in/out: mini-transaction */ { +#ifdef WITH_WSREP + trx_sysf_t* sys_header; +#endif /* WITH_WSREP */ trx_rseg_t* rseg; rseg = trx->rseg; @@ -1212,6 +1223,15 @@ trx_write_serialisation_history( MONITOR_INC(MONITOR_TRX_COMMIT_UNDO); +#ifdef WITH_WSREP + sys_header = trx_sysf_get(mtr); + /* Update latest MySQL wsrep XID in trx sys header. */ + if (wsrep_is_wsrep_xid((const void *)&trx->xid)) + { + trx_sys_update_wsrep_checkpoint(&trx->xid, sys_header, mtr); + } +#endif /* WITH_WSREP */ + /* Update the latest MySQL binlog name and offset info in trx sys header if MySQL binlogging is on or the database server is a MySQL replication slave */ @@ -1222,7 +1242,11 @@ trx_write_serialisation_history( trx_sys_update_mysql_binlog_offset( trx->mysql_log_file_name, trx->mysql_log_offset, - TRX_SYS_MYSQL_LOG_INFO, mtr); + TRX_SYS_MYSQL_LOG_INFO, +#ifdef WITH_WSREP + sys_header, +#endif /* WITH_WSREP */ + mtr); trx->mysql_log_file_name = NULL; } @@ -1527,6 +1551,11 @@ trx_commit_in_memory( ut_ad(!trx->in_ro_trx_list); ut_ad(!trx->in_rw_trx_list); +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd)) { + trx->lock.was_chosen_as_deadlock_victim = FALSE; + } +#endif trx->dict_operation = TRX_DICT_OP_NONE; trx->error_state = DB_SUCCESS; @@ -1709,6 +1738,10 @@ trx_commit_or_rollback_prepare( switch (trx->state) { case TRX_STATE_NOT_STARTED: +#ifdef WITH_WSREP + ut_d(trx->start_file = __FILE__); + ut_d(trx->start_line = __LINE__); +#endif /* WITH_WSREP */ trx_start_low(trx); /* fall through */ case TRX_STATE_ACTIVE: @@ -2480,6 +2513,10 @@ trx_start_if_not_started_low( { switch (trx->state) { case TRX_STATE_NOT_STARTED: +#ifdef WITH_WSREP + ut_d(trx->start_file = __FILE__); + ut_d(trx->start_line = __LINE__); +#endif /* WITH_WSREP */ trx_start_low(trx); /* fall through */ case TRX_STATE_ACTIVE: @@ -2514,6 +2551,10 @@ trx_start_for_ddl_low( trx->ddl = true; +#ifdef WITH_WSREP + ut_d(trx->start_file = __FILE__); + ut_d(trx->start_line = __LINE__); +#endif /* WITH_WSREP */ trx_start_low(trx); return; diff --git a/storage/xtradb/wsrep/md5.cc b/storage/xtradb/wsrep/md5.cc new file mode 100644 index 00000000000..30be6ab7dd3 --- /dev/null +++ b/storage/xtradb/wsrep/md5.cc @@ -0,0 +1,74 @@ +/* + Copyright (c) 2014 SkySQL AB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifdef WITH_WSREP + +#if defined(HAVE_YASSL) +#include "my_config.h" +#include "md5.hpp" +#elif defined(HAVE_OPENSSL) +#include +#endif /* HAVE_YASSL */ + +/* Initialize md5 object. */ +void *wsrep_md5_init() +{ +#if defined(HAVE_YASSL) + TaoCrypt::MD5 *hasher= new TaoCrypt::MD5; + return (void*)hasher; +#elif defined(HAVE_OPENSSL) + MD5_CTX *ctx = new MD5_CTX(); + MD5_Init (ctx); + return (void *)ctx; +#endif /* HAVE_YASSL */ +} + +/** + Supply message to be hashed. + + @param ctx [IN] Pointer to MD5 context + @param buf [IN] Message to be computed. + @param len [IN] Length of the message. +*/ +void wsrep_md5_update(void *ctx, char* buf, int len) +{ +#if defined(HAVE_YASSL) + ((TaoCrypt::MD5 *)ctx)->Update((TaoCrypt::byte *) buf, len); +#elif defined(HAVE_OPENSSL) + MD5_Update((MD5_CTX*)(ctx), buf, len); +#endif /* HAVE_YASSL */ +} + +/** + Place computed MD5 digest into the given buffer. + + @param digest [OUT] Computed MD5 digest + @param ctx [IN] Pointer to MD5 context +*/ +void wsrep_compute_md5_hash(char *digest, void *ctx) +{ +#if defined(HAVE_YASSL) + ((TaoCrypt::MD5*)ctx)->Final((TaoCrypt::byte *) digest); + delete (TaoCrypt::MD5*)ctx; +#elif defined(HAVE_OPENSSL) + MD5_Final ((unsigned char*)digest, (MD5_CTX*)ctx); + delete (MD5_CTX*)ctx; +#endif /* HAVE_YASSL */ +} + +#endif /* WITH_WSREP */ + diff --git a/storage/xtradb/wsrep/wsrep_md5.h b/storage/xtradb/wsrep/wsrep_md5.h new file mode 100644 index 00000000000..1339f7f4b86 --- /dev/null +++ b/storage/xtradb/wsrep/wsrep_md5.h @@ -0,0 +1,26 @@ +#ifndef WSREP_MD5_INCLUDED +#define WSREP_MD5_INCLUDED + +/* Copyright (c) 2014 SkySQL AB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +*/ + +#ifdef WITH_WSREP +void *wsrep_md5_init(); +void wsrep_md5_update(void *ctx, char* buf, int len); +void wsrep_compute_md5_hash(char *digest, void *ctx); +#endif /* WITH_WSREP */ + +#endif /* WSREP_MD5_INCLUDED */ diff --git a/support-files/CMakeLists.txt b/support-files/CMakeLists.txt index 698d06d1889..19f6bc14663 100644 --- a/support-files/CMakeLists.txt +++ b/support-files/CMakeLists.txt @@ -41,7 +41,7 @@ ELSE() SET(inst_location ${INSTALL_SUPPORTFILESDIR}) ENDIF() -FOREACH(inifile my-huge my-innodb-heavy-4G my-large my-medium my-small) +FOREACH(inifile my-huge my-innodb-heavy-4G my-large my-medium my-small wsrep) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/${inifile}.cnf.sh ${CMAKE_CURRENT_BINARY_DIR}/${inifile}.${ini_file_extension} @ONLY) INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${inifile}.${ini_file_extension} @@ -65,6 +65,7 @@ IF(UNIX) IF(INSTALL_SUPPORTFILESDIR) INSTALL(FILES magic DESTINATION ${inst_location} COMPONENT SupportFiles) INSTALL(DIRECTORY RHEL4-SElinux/ DESTINATION ${inst_location}/SELinux/RHEL4 COMPONENT SupportFiles) + INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/wsrep_notify DESTINATION ${inst_location} COMPONENT SupportFiles) ENDIF() INSTALL(FILES mysql.m4 DESTINATION ${INSTALL_SHAREDIR}/aclocal COMPONENT Development) diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh index a1ee5c4c653..d758f12d2ab 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -253,6 +253,8 @@ wait_for_gone () { wait_for_ready () { + sst_progress_file=$datadir/sst_in_progress + i=0 while test $i -ne $service_startup_timeout ; do @@ -261,6 +263,11 @@ wait_for_ready () { return 0 fi + if test -e $sst_progress_file && [ $startup_sleep -ne 10 ];then + echo $echo_n "SST in progress, setting sleep higher" + startup_sleep=10 + fi + echo $echo_n ".$echo_c" i=`expr $i + 1` sleep 1 @@ -426,10 +433,16 @@ case "$mode" in fi exit $r ;; + 'bootstrap') + # Bootstrap the cluster, start the first node + # that initiate the cluster + echo $echo_n "Bootstrapping the cluster" + $0 start $other_args --wsrep-new-cluster + ;; *) # usage basename=`basename "$0"` - echo "Usage: $basename {start|stop|restart|reload|force-reload|status|configtest} [ MySQL server options ]" + echo "Usage: $basename {start|stop|restart|reload|force-reload|status|configtest|bootstrap} [ MySQL server options ]" exit 1 ;; esac diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index d8de3a41e7f..0a158b4fe49 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -68,6 +68,14 @@ # $ rpmbuild --define="option " ... # +# ---------------------------------------------------------------------------- +# wsrep builds +# ---------------------------------------------------------------------------- +%if %{defined with_wsrep} +%define mysql_version @VERSION@_wsrep_@WSREP_API_VERSION@.@WSREP_PATCH_VERSION@ +%define wsrep_version @WSREP_VERSION@ +%endif + # ---------------------------------------------------------------------------- # Commercial builds # ---------------------------------------------------------------------------- @@ -283,9 +291,16 @@ documentation and the manual for more information. ############################################################################## %package -n MySQL-server%{product_suffix} +%if %{defined with_wsrep} +Version: %{mysql_version} +%endif Summary: MySQL: a very fast and reliable SQL database server Group: Applications/Databases +%if %{defined with_wsrep} +Requires: %{distro_requires} rsync lsof +%else Requires: %{distro_requires} +%endif %if 0%{?commercial} Obsoletes: MySQL-server %else @@ -319,6 +334,9 @@ and the manual for more information. This package includes the MySQL server binary as well as related utilities to run and administer a MySQL server. +%if %{defined with_wsrep} +Built with wsrep patch %{wsrep_version}. +%endif If you want to access and work with the database, you have to install package "MySQL-client%{product_suffix}" as well! @@ -410,6 +428,7 @@ This package contains the shared libraries (*.so*) which certain languages and applications need to dynamically load and use MySQL. # ---------------------------------------------------------------------------- +%if %{undefined with_wsrep} %package -n MySQL-embedded%{product_suffix} Summary: MySQL - Embedded library Group: Applications/Databases @@ -439,6 +458,7 @@ The API is identical for the embedded MySQL version and the client/server version. For a description of MySQL see the base MySQL RPM or http://www.mysql.com/ +%endif ############################################################################## %prep @@ -514,6 +534,9 @@ mkdir debug -DMYSQL_UNIX_ADDR="%{mysqldatadir}/mysql.sock" \ -DFEATURE_SET="%{feature_set}" \ -DCOMPILATION_COMMENT="%{compilation_comment_debug}" \ +%if %{defined with_wsrep} + -DWITH_WSREP=1 \ +%endif -DMYSQL_SERVER_SUFFIX="%{server_suffix}" echo BEGIN_DEBUG_CONFIG ; egrep '^#define' include/config.h ; echo END_DEBUG_CONFIG make ${MAKE_JFLAG} VERBOSE=1 @@ -529,6 +552,9 @@ mkdir release -DMYSQL_UNIX_ADDR="%{mysqldatadir}/mysql.sock" \ -DFEATURE_SET="%{feature_set}" \ -DCOMPILATION_COMMENT="%{compilation_comment_release}" \ +%if %{defined with_wsrep} + -DWITH_WSREP=1 \ +%endif -DMYSQL_SERVER_SUFFIX="%{server_suffix}" echo BEGIN_NORMAL_CONFIG ; egrep '^#define' include/config.h ; echo END_NORMAL_CONFIG make ${MAKE_JFLAG} VERBOSE=1 @@ -591,11 +617,20 @@ install -m 755 $MBD/release/support-files/mysql.server $RBR%{_sysconfdir}/init.d # Create a symlink "rcmysql", pointing to the init.script. SuSE users # will appreciate that, as all services usually offer this. -ln -s %{_sysconfdir}/init.d/mysql $RBR%{_sbindir}/rcmysql +ln -sf %{_sysconfdir}/init.d/mysql $RBR%{_sbindir}/rcmysql + +%if %{defined with_wsrep} +# Create a wsrep_sst_rsync_wan symlink. +install -d $RBR%{_bindir} +ln -sf wsrep_sst_rsync $RBR%{_bindir}/wsrep_sst_rsync_wan +%endif # Touch the place where the my.cnf config file might be located # Just to make sure it's in the file list and marked as a config file touch $RBR%{_sysconfdir}/my.cnf +%if %{defined with_wsrep} +touch $RBR%{_sysconfdir}/wsrep.cnf +%endif # Install SELinux files in datadir install -m 600 $MBD/%{src_dir}/support-files/RHEL4-SElinux/mysql.{fc,te} \ @@ -1057,6 +1092,11 @@ echo "=====" >> $STATUS_HISTORY %doc %{src_dir}/Docs/INFO_SRC* %doc release/Docs/INFO_BIN* %doc release/support-files/my-*.cnf +%if %{defined with_wsrep} +%doc %{src_dir}/Docs/README-wsrep +%doc release/support-files/wsrep.cnf +%doc release/support-files/wsrep_notify +%endif %if 0%{?commercial} %doc %attr(644, root, root) %{_infodir}/mysql.info* @@ -1092,6 +1132,9 @@ echo "=====" >> $STATUS_HISTORY %doc %attr(644, root, man) %{_mandir}/man1/resolveip.1* %ghost %config(noreplace,missingok) %{_sysconfdir}/my.cnf +%if %{defined with_wsrep} +%ghost %config(noreplace,missingok) %{_sysconfdir}/wsrep.cnf +%endif %attr(755, root, root) %{_bindir}/innochecksum %attr(755, root, root) %{_bindir}/my_print_defaults @@ -1118,6 +1161,14 @@ echo "=====" >> $STATUS_HISTORY %attr(755, root, root) %{_bindir}/replace %attr(755, root, root) %{_bindir}/resolve_stack_dump %attr(755, root, root) %{_bindir}/resolveip +%if %{defined with_wsrep} +%attr(755, root, root) %{_bindir}/wsrep_sst_common +%attr(755, root, root) %{_bindir}/wsrep_sst_mysqldump +%attr(755, root, root) %{_bindir}/wsrep_sst_rsync +%attr(755, root, root) %{_bindir}/wsrep_sst_rsync_wan +%attr(755, root, root) %{_bindir}/wsrep_sst_xtrabackup +%attr(755, root, root) %{_bindir}/wsrep_sst_xtrabackup-v2 +%endif %attr(755, root, root) %{_sbindir}/mysqld %attr(755, root, root) %{_sbindir}/mysqld-debug @@ -1196,8 +1247,10 @@ echo "=====" >> $STATUS_HISTORY %defattr(-, root, root, 0755) %attr(-, root, root) %{_datadir}/mysql-test %attr(755, root, root) %{_bindir}/mysql_client_test +%if %{undefined with_wsrep} %attr(755, root, root) %{_bindir}/mysql_client_test_embedded %attr(755, root, root) %{_bindir}/mysqltest_embedded +%endif %doc %attr(644, root, man) %{_mandir}/man1/mysql_client_test.1* %doc %attr(644, root, man) %{_mandir}/man1/mysql-stress-test.pl.1* %doc %attr(644, root, man) %{_mandir}/man1/mysql-test-run.pl.1* @@ -1205,11 +1258,13 @@ echo "=====" >> $STATUS_HISTORY %doc %attr(644, root, man) %{_mandir}/man1/mysqltest_embedded.1* # ---------------------------------------------------------------------------- +%if %{undefined with_wsrep} %files -n MySQL-embedded%{product_suffix} %defattr(-, root, root, 0755) %attr(755, root, root) %{_bindir}/mysql_embedded %attr(644, root, root) %{_libdir}/mysql/libmysqld.a %attr(644, root, root) %{_libdir}/mysql/libmysqld-debug.a +%endif ############################################################################## # The spec file changelog only includes changes made to the spec file @@ -1241,6 +1296,10 @@ echo "=====" >> $STATUS_HISTORY - Make sure newly added "SPECIFIC-ULN/" directory does not disturb packaging. +* Wed Dec 07 2011 Alexey Yurchenko + +- wsrep-related cleanups. + * Wed Sep 28 2011 Joerg Bruehe - Fix duplicate mentioning of "mysql_plugin" and its manual page, diff --git a/support-files/rpm/server.cnf b/support-files/rpm/server.cnf index fb52635d4d8..6170a2e4c49 100644 --- a/support-files/rpm/server.cnf +++ b/support-files/rpm/server.cnf @@ -11,6 +11,22 @@ # this is only for the mysqld standalone daemon [mysqld] +# +# * Galera-related settings +# +[galera] +# Mandatory settings +#wsrep_provider= +#wsrep_cluster_address= +#wsrep_slave_threads=1 +#binlog_format=row +#default_storage_engine=InnoDB +#innodb_autoinc_lock_mode=2 +#query_cache_size=0 +# +# Optional setting +#innodb_flush_log_at_trx_commit=0 + # this is only for embedded server [embedded] diff --git a/support-files/wsrep.cnf b/support-files/wsrep.cnf new file mode 100644 index 00000000000..756d4f6783b --- /dev/null +++ b/support-files/wsrep.cnf @@ -0,0 +1,129 @@ +# This file contains wsrep-related mysqld options. It should be included +# in the main MySQL configuration file. +# +# Options that need to be customized: +# - wsrep_provider +# - wsrep_cluster_address +# - wsrep_sst_auth +# The rest of defaults should work out of the box. + +## +## mysqld options _MANDATORY_ for correct opration of the cluster +## +[mysqld] + +# (This must be substituted by wsrep_format) +binlog_format=ROW + +# Currently only InnoDB storage engine is supported +default-storage-engine=innodb + +# to avoid issues with 'bulk mode inserts' using autoinc +innodb_autoinc_lock_mode=2 + +# This is a must for paralell applying +innodb_locks_unsafe_for_binlog=1 + +# Query Cache is not supported with wsrep +query_cache_size=0 +query_cache_type=0 + +# Override bind-address +# In some systems bind-address defaults to 127.0.0.1, and with mysqldump SST +# it will have (most likely) disastrous consequences on donor node +bind-address=0.0.0.0 + +## +## WSREP options +## + +# Full path to wsrep provider library or 'none' +wsrep_provider=none + +# Provider specific configuration options +#wsrep_provider_options= + +# Logical cluster name. Should be the same for all nodes. +wsrep_cluster_name="my_wsrep_cluster" + +# Group communication system handle +#wsrep_cluster_address="dummy://" + +# Human-readable node name (non-unique). Hostname by default. +#wsrep_node_name= + +# Base replication [:port] of the node. +# The values supplied will be used as defaults for state transfer receiving, +# listening ports and so on. Default: address of the first network interface. +#wsrep_node_address= + +# Address for incoming client connections. Autodetect by default. +#wsrep_node_incoming_address= + +# How many threads will process writesets from other nodes +wsrep_slave_threads=1 + +# DBUG options for wsrep provider +#wsrep_dbug_option + +# Generate fake primary keys for non-PK tables (required for multi-master +# and parallel applying operation) +wsrep_certify_nonPK=1 + +# Maximum number of rows in write set +wsrep_max_ws_rows=131072 + +# Maximum size of write set +wsrep_max_ws_size=1073741824 + +# to enable debug level logging, set this to 1 +wsrep_debug=0 + +# convert locking sessions into transactions +wsrep_convert_LOCK_to_trx=0 + +# how many times to retry deadlocked autocommits +wsrep_retry_autocommit=1 + +# change auto_increment_increment and auto_increment_offset automatically +wsrep_auto_increment_control=1 + +# retry autoinc insert, which failed for duplicate key error +wsrep_drupal_282555_workaround=0 + +# enable "strictly synchronous" semantics for read operations +wsrep_causal_reads=0 + +# Command to call when node status or cluster membership changes. +# Will be passed all or some of the following options: +# --status - new status of this node +# --uuid - UUID of the cluster +# --primary - whether the component is primary or not ("yes"/"no") +# --members - comma-separated list of members +# --index - index of this node in the list +wsrep_notify_cmd= + +## +## WSREP State Transfer options +## + +# State Snapshot Transfer method +wsrep_sst_method=rsync + +# Address which donor should send State Snapshot to. +# Should be the address of THIS node. DON'T SET IT TO DONOR ADDRESS!!! +# (SST method dependent. Defaults to the first IP of the first interface) +#wsrep_sst_receive_address= + +# SST authentication string. This will be used to send SST to joining nodes. +# Depends on SST method. For mysqldump method it is root: +wsrep_sst_auth=root: + +# Desired SST donor name. +#wsrep_sst_donor= + +# Reject client queries when donating SST (false) +#wsrep_sst_donor_rejects_queries=0 + +# Protocol version to use +# wsrep_protocol_version= diff --git a/support-files/wsrep.cnf.sh b/support-files/wsrep.cnf.sh new file mode 100644 index 00000000000..756d4f6783b --- /dev/null +++ b/support-files/wsrep.cnf.sh @@ -0,0 +1,129 @@ +# This file contains wsrep-related mysqld options. It should be included +# in the main MySQL configuration file. +# +# Options that need to be customized: +# - wsrep_provider +# - wsrep_cluster_address +# - wsrep_sst_auth +# The rest of defaults should work out of the box. + +## +## mysqld options _MANDATORY_ for correct opration of the cluster +## +[mysqld] + +# (This must be substituted by wsrep_format) +binlog_format=ROW + +# Currently only InnoDB storage engine is supported +default-storage-engine=innodb + +# to avoid issues with 'bulk mode inserts' using autoinc +innodb_autoinc_lock_mode=2 + +# This is a must for paralell applying +innodb_locks_unsafe_for_binlog=1 + +# Query Cache is not supported with wsrep +query_cache_size=0 +query_cache_type=0 + +# Override bind-address +# In some systems bind-address defaults to 127.0.0.1, and with mysqldump SST +# it will have (most likely) disastrous consequences on donor node +bind-address=0.0.0.0 + +## +## WSREP options +## + +# Full path to wsrep provider library or 'none' +wsrep_provider=none + +# Provider specific configuration options +#wsrep_provider_options= + +# Logical cluster name. Should be the same for all nodes. +wsrep_cluster_name="my_wsrep_cluster" + +# Group communication system handle +#wsrep_cluster_address="dummy://" + +# Human-readable node name (non-unique). Hostname by default. +#wsrep_node_name= + +# Base replication [:port] of the node. +# The values supplied will be used as defaults for state transfer receiving, +# listening ports and so on. Default: address of the first network interface. +#wsrep_node_address= + +# Address for incoming client connections. Autodetect by default. +#wsrep_node_incoming_address= + +# How many threads will process writesets from other nodes +wsrep_slave_threads=1 + +# DBUG options for wsrep provider +#wsrep_dbug_option + +# Generate fake primary keys for non-PK tables (required for multi-master +# and parallel applying operation) +wsrep_certify_nonPK=1 + +# Maximum number of rows in write set +wsrep_max_ws_rows=131072 + +# Maximum size of write set +wsrep_max_ws_size=1073741824 + +# to enable debug level logging, set this to 1 +wsrep_debug=0 + +# convert locking sessions into transactions +wsrep_convert_LOCK_to_trx=0 + +# how many times to retry deadlocked autocommits +wsrep_retry_autocommit=1 + +# change auto_increment_increment and auto_increment_offset automatically +wsrep_auto_increment_control=1 + +# retry autoinc insert, which failed for duplicate key error +wsrep_drupal_282555_workaround=0 + +# enable "strictly synchronous" semantics for read operations +wsrep_causal_reads=0 + +# Command to call when node status or cluster membership changes. +# Will be passed all or some of the following options: +# --status - new status of this node +# --uuid - UUID of the cluster +# --primary - whether the component is primary or not ("yes"/"no") +# --members - comma-separated list of members +# --index - index of this node in the list +wsrep_notify_cmd= + +## +## WSREP State Transfer options +## + +# State Snapshot Transfer method +wsrep_sst_method=rsync + +# Address which donor should send State Snapshot to. +# Should be the address of THIS node. DON'T SET IT TO DONOR ADDRESS!!! +# (SST method dependent. Defaults to the first IP of the first interface) +#wsrep_sst_receive_address= + +# SST authentication string. This will be used to send SST to joining nodes. +# Depends on SST method. For mysqldump method it is root: +wsrep_sst_auth=root: + +# Desired SST donor name. +#wsrep_sst_donor= + +# Reject client queries when donating SST (false) +#wsrep_sst_donor_rejects_queries=0 + +# Protocol version to use +# wsrep_protocol_version= diff --git a/support-files/wsrep.cnf.sh.moved b/support-files/wsrep.cnf.sh.moved new file mode 100644 index 00000000000..756d4f6783b --- /dev/null +++ b/support-files/wsrep.cnf.sh.moved @@ -0,0 +1,129 @@ +# This file contains wsrep-related mysqld options. It should be included +# in the main MySQL configuration file. +# +# Options that need to be customized: +# - wsrep_provider +# - wsrep_cluster_address +# - wsrep_sst_auth +# The rest of defaults should work out of the box. + +## +## mysqld options _MANDATORY_ for correct opration of the cluster +## +[mysqld] + +# (This must be substituted by wsrep_format) +binlog_format=ROW + +# Currently only InnoDB storage engine is supported +default-storage-engine=innodb + +# to avoid issues with 'bulk mode inserts' using autoinc +innodb_autoinc_lock_mode=2 + +# This is a must for paralell applying +innodb_locks_unsafe_for_binlog=1 + +# Query Cache is not supported with wsrep +query_cache_size=0 +query_cache_type=0 + +# Override bind-address +# In some systems bind-address defaults to 127.0.0.1, and with mysqldump SST +# it will have (most likely) disastrous consequences on donor node +bind-address=0.0.0.0 + +## +## WSREP options +## + +# Full path to wsrep provider library or 'none' +wsrep_provider=none + +# Provider specific configuration options +#wsrep_provider_options= + +# Logical cluster name. Should be the same for all nodes. +wsrep_cluster_name="my_wsrep_cluster" + +# Group communication system handle +#wsrep_cluster_address="dummy://" + +# Human-readable node name (non-unique). Hostname by default. +#wsrep_node_name= + +# Base replication [:port] of the node. +# The values supplied will be used as defaults for state transfer receiving, +# listening ports and so on. Default: address of the first network interface. +#wsrep_node_address= + +# Address for incoming client connections. Autodetect by default. +#wsrep_node_incoming_address= + +# How many threads will process writesets from other nodes +wsrep_slave_threads=1 + +# DBUG options for wsrep provider +#wsrep_dbug_option + +# Generate fake primary keys for non-PK tables (required for multi-master +# and parallel applying operation) +wsrep_certify_nonPK=1 + +# Maximum number of rows in write set +wsrep_max_ws_rows=131072 + +# Maximum size of write set +wsrep_max_ws_size=1073741824 + +# to enable debug level logging, set this to 1 +wsrep_debug=0 + +# convert locking sessions into transactions +wsrep_convert_LOCK_to_trx=0 + +# how many times to retry deadlocked autocommits +wsrep_retry_autocommit=1 + +# change auto_increment_increment and auto_increment_offset automatically +wsrep_auto_increment_control=1 + +# retry autoinc insert, which failed for duplicate key error +wsrep_drupal_282555_workaround=0 + +# enable "strictly synchronous" semantics for read operations +wsrep_causal_reads=0 + +# Command to call when node status or cluster membership changes. +# Will be passed all or some of the following options: +# --status - new status of this node +# --uuid - UUID of the cluster +# --primary - whether the component is primary or not ("yes"/"no") +# --members - comma-separated list of members +# --index - index of this node in the list +wsrep_notify_cmd= + +## +## WSREP State Transfer options +## + +# State Snapshot Transfer method +wsrep_sst_method=rsync + +# Address which donor should send State Snapshot to. +# Should be the address of THIS node. DON'T SET IT TO DONOR ADDRESS!!! +# (SST method dependent. Defaults to the first IP of the first interface) +#wsrep_sst_receive_address= + +# SST authentication string. This will be used to send SST to joining nodes. +# Depends on SST method. For mysqldump method it is root: +wsrep_sst_auth=root: + +# Desired SST donor name. +#wsrep_sst_donor= + +# Reject client queries when donating SST (false) +#wsrep_sst_donor_rejects_queries=0 + +# Protocol version to use +# wsrep_protocol_version= diff --git a/support-files/wsrep_notify b/support-files/wsrep_notify new file mode 100644 index 00000000000..bdbe3d12a39 --- /dev/null +++ b/support-files/wsrep_notify @@ -0,0 +1,102 @@ +#!/bin/sh -eu + +# This is a simple example of wsrep notification script (wsrep_notify_cmd). +# It will create 'wsrep' schema and two tables in it: 'membeship' and 'status' +# and fill them on every membership or node status change. +# +# Edit parameters below to specify the address and login to server. + +USER=root +PSWD=rootpass +HOST=127.0.0.1 +PORT=3306 + +SCHEMA="wsrep" +MEMB_TABLE="$SCHEMA.membership" +STATUS_TABLE="$SCHEMA.status" + +BEGIN=" +SET wsrep_on=0; +DROP SCHEMA IF EXISTS $SCHEMA; CREATE SCHEMA $SCHEMA; +CREATE TABLE $MEMB_TABLE ( + idx INT UNIQUE PRIMARY KEY, + uuid CHAR(40) UNIQUE, /* node UUID */ + name VARCHAR(32), /* node name */ + addr VARCHAR(256) /* node address */ +) ENGINE=MEMORY; +CREATE TABLE $STATUS_TABLE ( + size INT, /* component size */ + idx INT, /* this node index */ + status CHAR(16), /* this node status */ + uuid CHAR(40), /* cluster UUID */ + prim BOOLEAN /* if component is primary */ +) ENGINE=MEMORY; +BEGIN; +DELETE FROM $MEMB_TABLE; +DELETE FROM $STATUS_TABLE; +" +END="COMMIT;" + +configuration_change() +{ + echo "$BEGIN;" + + local idx=0 + + for NODE in $(echo $MEMBERS | sed s/,/\ /g) + do + echo "INSERT INTO $MEMB_TABLE VALUES ( $idx, " + # Don't forget to properly quote string values + echo "'$NODE'" | sed s/\\//\',\'/g + echo ");" + idx=$(( $idx + 1 )) + done + + echo "INSERT INTO $STATUS_TABLE VALUES($idx, $INDEX, '$STATUS', '$CLUSTER_UUID', $PRIMARY);" + + echo "$END" +} + +status_update() +{ + echo "SET wsrep_on=0; BEGIN; UPDATE $STATUS_TABLE SET status='$STATUS'; COMMIT;" +} + +COM=status_update # not a configuration change by default + +while [ $# -gt 0 ] +do + case $1 in + --status) + STATUS=$2 + shift + ;; + --uuid) + CLUSTER_UUID=$2 + shift + ;; + --primary) + [ "$2" = "yes" ] && PRIMARY="1" || PRIMARY="0" + COM=configuration_change + shift + ;; + --index) + INDEX=$2 + shift + ;; + --members) + MEMBERS=$2 + shift + ;; + esac + shift +done + +# Undefined means node is shutting down +if [ "$STATUS" != "Undefined" ] +then + $COM | mysql -B -u$USER -p$PSWD -h$HOST -P$PORT +fi + +exit 0 +# diff --git a/support-files/wsrep_notify.sh b/support-files/wsrep_notify.sh new file mode 100644 index 00000000000..bdbe3d12a39 --- /dev/null +++ b/support-files/wsrep_notify.sh @@ -0,0 +1,102 @@ +#!/bin/sh -eu + +# This is a simple example of wsrep notification script (wsrep_notify_cmd). +# It will create 'wsrep' schema and two tables in it: 'membeship' and 'status' +# and fill them on every membership or node status change. +# +# Edit parameters below to specify the address and login to server. + +USER=root +PSWD=rootpass +HOST=127.0.0.1 +PORT=3306 + +SCHEMA="wsrep" +MEMB_TABLE="$SCHEMA.membership" +STATUS_TABLE="$SCHEMA.status" + +BEGIN=" +SET wsrep_on=0; +DROP SCHEMA IF EXISTS $SCHEMA; CREATE SCHEMA $SCHEMA; +CREATE TABLE $MEMB_TABLE ( + idx INT UNIQUE PRIMARY KEY, + uuid CHAR(40) UNIQUE, /* node UUID */ + name VARCHAR(32), /* node name */ + addr VARCHAR(256) /* node address */ +) ENGINE=MEMORY; +CREATE TABLE $STATUS_TABLE ( + size INT, /* component size */ + idx INT, /* this node index */ + status CHAR(16), /* this node status */ + uuid CHAR(40), /* cluster UUID */ + prim BOOLEAN /* if component is primary */ +) ENGINE=MEMORY; +BEGIN; +DELETE FROM $MEMB_TABLE; +DELETE FROM $STATUS_TABLE; +" +END="COMMIT;" + +configuration_change() +{ + echo "$BEGIN;" + + local idx=0 + + for NODE in $(echo $MEMBERS | sed s/,/\ /g) + do + echo "INSERT INTO $MEMB_TABLE VALUES ( $idx, " + # Don't forget to properly quote string values + echo "'$NODE'" | sed s/\\//\',\'/g + echo ");" + idx=$(( $idx + 1 )) + done + + echo "INSERT INTO $STATUS_TABLE VALUES($idx, $INDEX, '$STATUS', '$CLUSTER_UUID', $PRIMARY);" + + echo "$END" +} + +status_update() +{ + echo "SET wsrep_on=0; BEGIN; UPDATE $STATUS_TABLE SET status='$STATUS'; COMMIT;" +} + +COM=status_update # not a configuration change by default + +while [ $# -gt 0 ] +do + case $1 in + --status) + STATUS=$2 + shift + ;; + --uuid) + CLUSTER_UUID=$2 + shift + ;; + --primary) + [ "$2" = "yes" ] && PRIMARY="1" || PRIMARY="0" + COM=configuration_change + shift + ;; + --index) + INDEX=$2 + shift + ;; + --members) + MEMBERS=$2 + shift + ;; + esac + shift +done + +# Undefined means node is shutting down +if [ "$STATUS" != "Undefined" ] +then + $COM | mysql -B -u$USER -p$PSWD -h$HOST -P$PORT +fi + +exit 0 +# diff --git a/wsrep/CMakeLists.txt b/wsrep/CMakeLists.txt new file mode 100644 index 00000000000..d9e66739fcc --- /dev/null +++ b/wsrep/CMakeLists.txt @@ -0,0 +1,25 @@ +# Copyright (c) 2012, Codership Oy. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +INCLUDE_DIRECTORIES( "." ) +BUILD_WITH_WSREP() + +SET(WSREP_SOURCES wsrep_gtid.c wsrep_uuid.c wsrep_loader.c wsrep_dummy.c) + +ADD_CONVENIENCE_LIBRARY(wsrep ${WSREP_SOURCES}) +DTRACE_INSTRUMENT(wsrep) + +#ADD_EXECUTABLE(listener wsrep_listener.c ${WSREP_SOURCES}) +#TARGET_LINK_LIBRARIES(listener ${LIBDL}) diff --git a/wsrep/wsrep_api.h b/wsrep/wsrep_api.h new file mode 100644 index 00000000000..c3304d7ed7c --- /dev/null +++ b/wsrep/wsrep_api.h @@ -0,0 +1,1118 @@ +/* Copyright (C) 2009-2013 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/*! + @file wsrep API declaration. + + HOW TO READ THIS FILE. + + Due to C language rules this header layout doesn't lend itself to intuitive + reading. So here's the scoop: in the end this header declares two main types: + + * struct wsrep_init_args + + and + + * struct wsrep + + wsrep_init_args contains initialization parameters for wsrep provider like + names, addresses, etc. and pointers to callbacks. The callbacks will be called + by provider when it needs to do something application-specific, like log a + message or apply a writeset. It should be passed to init() call from + wsrep API. It is an application part of wsrep API contract. + + struct wsrep is the interface to wsrep provider. It contains all wsrep API + calls. It is a provider part of wsrep API contract. + + Finally, wsrep_load() method loads (dlopens) wsrep provider library. It is + defined in wsrep_loader.c unit and is part of libwsrep.a (which is not a + wsrep provider, but a convenience library). + + wsrep_unload() does the reverse. + +*/ +#ifndef WSREP_H +#define WSREP_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************** + * * + * wsrep replication API * + * * + **************************************************************************/ + +#define WSREP_INTERFACE_VERSION "25" + +/*! Empty backend spec */ +#define WSREP_NONE "none" + + +/*! + * @brief log severity levels, passed as first argument to log handler + */ +typedef enum wsrep_log_level +{ + WSREP_LOG_FATAL, //!< Unrecoverable error, application must quit. + WSREP_LOG_ERROR, //!< Operation failed, must be repeated. + WSREP_LOG_WARN, //!< Unexpected condition, but no operational failure. + WSREP_LOG_INFO, //!< Informational message. + WSREP_LOG_DEBUG //!< Debug message. Shows only of compiled with debug. +} wsrep_log_level_t; + +/*! + * @brief error log handler + * + * All messages from wsrep provider are directed to this + * handler, if present. + * + * @param level log level + * @param message log message + */ +typedef void (*wsrep_log_cb_t)(wsrep_log_level_t, const char *); + + +/*! + * Certain provider capabilities application may want to know about + */ +#define WSREP_CAP_MULTI_MASTER ( 1ULL << 0 ) +#define WSREP_CAP_CERTIFICATION ( 1ULL << 1 ) +#define WSREP_CAP_PARALLEL_APPLYING ( 1ULL << 2 ) +#define WSREP_CAP_TRX_REPLAY ( 1ULL << 3 ) +#define WSREP_CAP_ISOLATION ( 1ULL << 4 ) +#define WSREP_CAP_PAUSE ( 1ULL << 5 ) +#define WSREP_CAP_CAUSAL_READS ( 1ULL << 6 ) +#define WSREP_CAP_CAUSAL_TRX ( 1ULL << 7 ) +#define WSREP_CAP_INCREMENTAL_WRITESET ( 1ULL << 8 ) +#define WSREP_CAP_SESSION_LOCKS ( 1ULL << 9 ) +#define WSREP_CAP_DISTRIBUTED_LOCKS ( 1ULL << 10 ) +#define WSREP_CAP_CONSISTENCY_CHECK ( 1ULL << 11 ) +#define WSREP_CAP_UNORDERED ( 1ULL << 12 ) +#define WSREP_CAP_ANNOTATION ( 1ULL << 13 ) +#define WSREP_CAP_PREORDERED ( 1ULL << 14 ) + + +/*! + * Writeset flags + * + * COMMIT the writeset and all preceding writesets must be committed + * ROLLBACK all preceding writesets in a transaction must be rolled back + * ISOLATION the writeset must be applied AND committed in isolation + * PA_UNSAFE the writeset cannot be applied in parallel + * COMMUTATIVE the order in which the writeset is applied does not matter + * NATIVE the writeset contains another writeset in this provider format + * + * Note that some of the flags are mutually exclusive (e.g. COMMIT and + * ROLLBACK). + */ +#define WSREP_FLAG_COMMIT ( 1ULL << 0 ) +#define WSREP_FLAG_ROLLBACK ( 1ULL << 1 ) +#define WSREP_FLAG_ISOLATION ( 1ULL << 2 ) +#define WSREP_FLAG_PA_UNSAFE ( 1ULL << 3 ) +#define WSREP_FLAG_COMMUTATIVE ( 1ULL << 4 ) +#define WSREP_FLAG_NATIVE ( 1ULL << 5 ) + + +typedef uint64_t wsrep_trx_id_t; //!< application transaction ID +typedef uint64_t wsrep_conn_id_t; //!< application connection ID +typedef int64_t wsrep_seqno_t; //!< sequence number of a writeset, etc. +#ifdef __cplusplus +typedef bool wsrep_bool_t; +#else +typedef _Bool wsrep_bool_t; //!< should be the same as standard (C99) bool +#endif /* __cplusplus */ + +/*! undefined seqno */ +#define WSREP_SEQNO_UNDEFINED (-1) + + +/*! wsrep provider status codes */ +typedef enum wsrep_status +{ + WSREP_OK = 0, //!< success + WSREP_WARNING, //!< minor warning, error logged + WSREP_TRX_MISSING, //!< transaction is not known by wsrep + WSREP_TRX_FAIL, //!< transaction aborted, server can continue + WSREP_BF_ABORT, //!< trx was victim of brute force abort + WSREP_SIZE_EXCEEDED, //!< data exceeded maximum supported size + WSREP_CONN_FAIL, //!< error in client connection, must abort + WSREP_NODE_FAIL, //!< error in node state, wsrep must reinit + WSREP_FATAL, //!< fatal error, server must abort + WSREP_NOT_IMPLEMENTED //!< feature not implemented +} wsrep_status_t; + + +/*! wsrep callbacks status codes */ +typedef enum wsrep_cb_status +{ + WSREP_CB_SUCCESS = 0, //!< success (as in "not critical failure") + WSREP_CB_FAILURE //!< critical failure (consistency violation) + /* Technically, wsrep provider has no use for specific failure codes since + * there is nothing it can do about it but abort execution. Therefore any + * positive number shall indicate a critical failure. Optionally that value + * may be used by provider to come to a consensus about state consistency + * in a group of nodes. */ +} wsrep_cb_status_t; + + +/*! + * UUID type - for all unique IDs + */ +typedef struct wsrep_uuid { + uint8_t data[16]; +} wsrep_uuid_t; + +/*! Undefined UUID */ +static const wsrep_uuid_t WSREP_UUID_UNDEFINED = {{0,}}; + +/*! UUID string representation length, terminating '\0' not included */ +#define WSREP_UUID_STR_LEN 36 + +/*! + * Scan UUID from string + * @return length of UUID string representation or negative error code + */ +extern int +wsrep_uuid_scan (const char* str, size_t str_len, wsrep_uuid_t* uuid); + +/*! + * Print UUID to string + * @return length of UUID string representation or negative error code + */ +extern int +wsrep_uuid_print (const wsrep_uuid_t* uuid, char* str, size_t str_len); + +#define WSREP_MEMBER_NAME_LEN 32 //!< maximum logical member name length +#define WSREP_INCOMING_LEN 256 //!< max Domain Name length + 0x00 + + +/*! + * Global transaction identifier + */ +typedef struct wsrep_gtid +{ + wsrep_uuid_t uuid; /*!< History UUID */ + wsrep_seqno_t seqno; /*!< Sequence number */ +} wsrep_gtid_t; + +/*! Undefined GTID */ +static const wsrep_gtid_t WSREP_GTID_UNDEFINED = {{{0, }}, -1}; + +/*! Minimum number of bytes guaranteed to store GTID string representation, + * terminating '\0' not included (36 + 1 + 20) */ +#define WSREP_GTID_STR_LEN 57 + + +/*! + * Scan GTID from string + * @return length of GTID string representation or negative error code + */ +extern int +wsrep_gtid_scan(const char* str, size_t str_len, wsrep_gtid_t* gtid); + +/*! + * Print GTID to string + * @return length of GTID string representation or negative error code + */ +extern int +wsrep_gtid_print(const wsrep_gtid_t* gtid, char* str, size_t str_len); + + +/*! + * Transaction meta data + */ +typedef struct wsrep_trx_meta +{ + wsrep_gtid_t gtid; /*!< Global transaction identifier */ + wsrep_seqno_t depends_on; /*!< Sequence number part of the last transaction + this transaction depends on */ +} wsrep_trx_meta_t; + + +/*! + * member status + */ +typedef enum wsrep_member_status { + WSREP_MEMBER_UNDEFINED, //!< undefined state + WSREP_MEMBER_JOINER, //!< incomplete state, requested state transfer + WSREP_MEMBER_DONOR, //!< complete state, donates state transfer + WSREP_MEMBER_JOINED, //!< complete state + WSREP_MEMBER_SYNCED, //!< complete state, synchronized with group + WSREP_MEMBER_ERROR, //!< this and above is provider-specific error code + WSREP_MEMBER_MAX +} wsrep_member_status_t; + +/*! + * static information about a group member (some fields are tentative yet) + */ +typedef struct wsrep_member_info { + wsrep_uuid_t id; //!< group-wide unique member ID + char name[WSREP_MEMBER_NAME_LEN]; //!< human-readable name + char incoming[WSREP_INCOMING_LEN]; //!< address for client requests +} wsrep_member_info_t; + +/*! + * group status + */ +typedef enum wsrep_view_status { + WSREP_VIEW_PRIMARY, //!< primary group configuration (quorum present) + WSREP_VIEW_NON_PRIMARY, //!< non-primary group configuration (quorum lost) + WSREP_VIEW_DISCONNECTED, //!< not connected to group, retrying. + WSREP_VIEW_MAX +} wsrep_view_status_t; + +/*! + * view of the group + */ +typedef struct wsrep_view_info { + wsrep_gtid_t state_id; //!< global state ID + wsrep_seqno_t view; //!< global view number + wsrep_view_status_t status; //!< view status + wsrep_bool_t state_gap; //!< gap between global and local states + int my_idx; //!< index of this member in the view + int memb_num; //!< number of members in the view + int proto_ver; //!< application protocol agreed on the view + wsrep_member_info_t members[1];//!< array of member information +} wsrep_view_info_t; + +/*! + * Magic string to tell provider to engage into trivial (empty) state transfer. + * No data will be passed, but the node shall be considered JOINED. + * Should be passed in sst_req parameter of wsrep_view_cb_t. + */ +#define WSREP_STATE_TRANSFER_TRIVIAL "trivial" + +/*! + * Magic string to tell provider not to engage in state transfer at all. + * The member will stay in WSREP_MEMBER_UNDEFINED state but will keep on + * receiving all writesets. + * Should be passed in sst_req parameter of wsrep_view_cb_t. + */ +#define WSREP_STATE_TRANSFER_NONE "none" + +/*! + * @brief group view handler + * + * This handler is called in total order corresponding to the group + * configuration change. It is to provide a vital information about + * new group view. If view info indicates existence of discontinuity + * between group and member states, state transfer request message + * should be filled in by the callback implementation. + * + * @note Currently it is assumed that sst_req is allocated using + * malloc()/calloc()/realloc() and it will be freed by + * wsrep implementation. + * + * @param app_ctx application context + * @param recv_ctx receiver context + * @param view new view on the group + * @param state current state + * @param state_len lenght of current state + * @param sst_req location to store SST request + * @param sst_req_len location to store SST request length or error code, + * value of 0 means no SST. + */ +typedef enum wsrep_cb_status (*wsrep_view_cb_t) ( + void* app_ctx, + void* recv_ctx, + const wsrep_view_info_t* view, + const char* state, + size_t state_len, + void** sst_req, + size_t* sst_req_len +); + + +/*! + * @brief apply callback + * + * This handler is called from wsrep library to apply replicated writeset + * Must support brute force applying for multi-master operation + * + * @param recv_ctx receiver context pointer provided by the application + * @param data data buffer containing the writeset + * @param size data buffer size + * @param flags WSREP_FLAG_... flags + * @param meta transaction meta data of the writeset to be applied + * + * @return success code: + * @retval WSREP_OK + * @retval WSREP_NOT_IMPLEMENTED appl. does not support the writeset format + * @retval WSREP_ERROR failed to apply the writeset + */ +typedef enum wsrep_cb_status (*wsrep_apply_cb_t) ( + void* recv_ctx, + const void* data, + size_t size, + uint32_t flags, + const wsrep_trx_meta_t* meta +); + + +/*! + * @brief commit callback + * + * This handler is called to commit the changes made by apply callback. + * + * @param recv_ctx receiver context pointer provided by the application + * @param flags WSREP_FLAG_... flags + * @param meta transaction meta data of the writeset to be committed + * @param exit set to true to exit recv loop + * @param commit true - commit writeset, false - rollback writeset + * + * @return success code: + * @retval WSREP_OK + * @retval WSREP_ERROR call failed + */ +typedef enum wsrep_cb_status (*wsrep_commit_cb_t) ( + void* recv_ctx, + uint32_t flags, + const wsrep_trx_meta_t* meta, + wsrep_bool_t* exit, + wsrep_bool_t commit +); + + +/*! + * @brief unordered callback + * + * This handler is called to execute unordered actions (actions that need not + * to be executed in any particular order) attached to writeset. + * + * @param recv_ctx receiver context pointer provided by the application + * @param data data buffer containing the writeset + * @param size data buffer size + */ +typedef enum wsrep_cb_status (*wsrep_unordered_cb_t) ( + void* recv_ctx, + const void* data, + size_t size +); + + +/*! + * @brief a callback to donate state snapshot + * + * This handler is called from wsrep library when it needs this node + * to deliver state to a new cluster member. + * No state changes will be committed for the duration of this call. + * Wsrep implementation may provide internal state to be transmitted + * to new cluster member for initial state. + * + * @param app_ctx application context + * @param recv_ctx receiver context + * @param msg state transfer request message + * @param msg_len state transfer request message length + * @param gtid current state ID on this node + * @param state current wsrep internal state buffer + * @param state_len current wsrep internal state buffer len + * @param bypass bypass snapshot transfer, only transfer uuid:seqno pair + */ +typedef enum wsrep_cb_status (*wsrep_sst_donate_cb_t) ( + void* app_ctx, + void* recv_ctx, + const void* msg, + size_t msg_len, + const wsrep_gtid_t* state_id, + const char* state, + size_t state_len, + wsrep_bool_t bypass +); + + +/*! + * @brief a callback to signal application that wsrep state is synced + * with cluster + * + * This callback is called after wsrep library has got in sync with + * rest of the cluster. + * + * @param app_ctx application context + */ +typedef void (*wsrep_synced_cb_t) (void* app_ctx); + + +/*! + * Initialization parameters for wsrep provider. + */ +struct wsrep_init_args +{ + void* app_ctx; //!< Application context for callbacks + + /* Configuration parameters */ + const char* node_name; //!< Symbolic name of this node (e.g. hostname) + const char* node_address; //!< Address to be used by wsrep provider + const char* node_incoming; //!< Address for incoming client connections + const char* data_dir; //!< Directory where wsrep files are kept if any + const char* options; //!< Provider-specific configuration string + int proto_ver; //!< Max supported application protocol version + + /* Application initial state information. */ + const wsrep_gtid_t* state_id; //!< Application state GTID + const char* state; //!< Initial state for wsrep provider + size_t state_len; //!< Length of state buffer + + /* Application callbacks */ + wsrep_log_cb_t logger_cb; //!< logging handler + wsrep_view_cb_t view_handler_cb; //!< group view change handler + + /* Applier callbacks */ + wsrep_apply_cb_t apply_cb; //!< apply callback + wsrep_commit_cb_t commit_cb; //!< commit callback + wsrep_unordered_cb_t unordered_cb; //!< callback for unordered actions + + /* State Snapshot Transfer callbacks */ + wsrep_sst_donate_cb_t sst_donate_cb; //!< starting to donate + wsrep_synced_cb_t synced_cb; //!< synced with group +}; + + +/*! Type of the stats variable value in struct wsrep_status_var */ +typedef enum wsrep_var_type +{ + WSREP_VAR_STRING, //!< pointer to null-terminated string + WSREP_VAR_INT64, //!< int64_t + WSREP_VAR_DOUBLE //!< double +} +wsrep_var_type_t; + +/*! Generalized stats variable representation */ +struct wsrep_stats_var +{ + const char* name; //!< variable name + wsrep_var_type_t type; //!< variable value type + union { + int64_t _int64; + double _double; + const char* _string; + } value; //!< variable value +}; + + +/*! Abstract data buffer structure */ +typedef struct wsrep_buf +{ + const void* ptr; /*!< Pointer to data buffer */ + size_t len; /*!< Length of buffer */ +} wsrep_buf_t; + +/*! Key struct used to pass certification keys for transaction handling calls. + * A key consists of zero or more key parts. */ +typedef struct wsrep_key +{ + const wsrep_buf_t* key_parts; /*!< Array of key parts */ + size_t key_parts_num; /*!< Number of key parts */ +} wsrep_key_t; + +/*! Key type: + * EXCLUSIVE conflicts with any key type + * SEMI reserved. If not supported, should be interpeted as EXCLUSIVE + * SHARED conflicts only with EXCLUSIVE keys */ +typedef enum wsrep_key_type +{ + WSREP_KEY_SHARED = 0, + WSREP_KEY_SEMI, + WSREP_KEY_EXCLUSIVE +} wsrep_key_type_t; + +/*! Data type: + * ORDERED state modification event that should be applied and committed + * in order. + * UNORDERED some action that does not modify state and execution of which is + * optional and does not need to happen in order. + * ANNOTATION (human readable) writeset annotation. */ +typedef enum wsrep_data_type +{ + WSREP_DATA_ORDERED = 0, + WSREP_DATA_UNORDERED, + WSREP_DATA_ANNOTATION +} wsrep_data_type_t; + + +/*! Transaction handle struct passed for wsrep transaction handling calls */ +typedef struct wsrep_ws_handle +{ + wsrep_trx_id_t trx_id; //!< transaction ID + void* opaque; //!< opaque provider transaction context data +} wsrep_ws_handle_t; + +/*! + * @brief Helper method to reset trx writeset handle state when trx id changes + * + * Instead of passing wsrep_ws_handle_t directly to wsrep calls, + * wrapping handle with this call offloads bookkeeping from + * application. + */ +static inline wsrep_ws_handle_t* wsrep_ws_handle_for_trx( + wsrep_ws_handle_t* ws_handle, + wsrep_trx_id_t trx_id) +{ + if (ws_handle->trx_id != trx_id) + { + ws_handle->trx_id = trx_id; + ws_handle->opaque = NULL; + } + return ws_handle; +} + + +/*! + * A handle for processing preordered actions. + * Must be initialized to WSREP_PO_INITIALIZER before use. + */ +typedef struct wsrep_po_handle { void* opaque; } wsrep_po_handle_t; + +static const wsrep_po_handle_t WSREP_PO_INITIALIZER = { NULL }; + + +typedef struct wsrep wsrep_t; +/*! + * wsrep interface for dynamically loadable libraries + */ +struct wsrep { + + const char *version; //!< interface version string + + /*! + * @brief Initializes wsrep provider + * + * @param wsrep provider handle + * @param args wsrep initialization parameters + */ + wsrep_status_t (*init) (wsrep_t* wsrep, + const struct wsrep_init_args* args); + + /*! + * @brief Returns provider capabilities flag bitmap + * + * @param wsrep provider handle + */ + uint64_t (*capabilities) (wsrep_t* wsrep); + + /*! + * @brief Passes provider-specific configuration string to provider. + * + * @param wsrep provider handle + * @param conf configuration string + * + * @retval WSREP_OK configuration string was parsed successfully + * @retval WSREP_WARNING could't not parse conf string, no action taken + */ + wsrep_status_t (*options_set) (wsrep_t* wsrep, const char* conf); + + /*! + * @brief Returns provider-specific string with current configuration values. + * + * @param wsrep provider handle + * + * @return a dynamically allocated string with current configuration + * parameter values + */ + char* (*options_get) (wsrep_t* wsrep); + + /*! + * @brief Opens connection to cluster + * + * Returns when either node is ready to operate as a part of the clsuter + * or fails to reach operating status. + * + * @param wsrep provider handle + * @param cluster_name unique symbolic cluster name + * @param cluster_url URL-like cluster address (backend://address) + * @param state_donor name of the node to be asked for state transfer. + * @param bootstrap a flag to request initialization of a new wsrep + * service rather then a connection to the existing one. + * clister_url may still carry important initialization + * parameters, like backend spec and/or listen address. + */ + wsrep_status_t (*connect) (wsrep_t* wsrep, + const char* cluster_name, + const char* cluster_url, + const char* state_donor, + wsrep_bool_t bootstrap); + + /*! + * @brief Closes connection to cluster. + * + * If state_uuid and/or state_seqno is not NULL, will store final state + * in there. + * + * @param wsrep this wsrep handler + */ + wsrep_status_t (*disconnect)(wsrep_t* wsrep); + + /*! + * @brief start receiving replication events + * + * This function never returns + * + * @param wsrep provider handle + * @param recv_ctx receiver context + */ + wsrep_status_t (*recv)(wsrep_t* wsrep, void* recv_ctx); + + /*! + * @brief Replicates/logs result of transaction to other nodes and allocates + * required resources. + * + * Must be called before transaction commit. Returns success code, which + * caller must check. + * In case of WSREP_OK, starts commit critical section, transaction can + * commit. Otherwise transaction must rollback. + * + * @param wsrep provider handle + * @param ws_handle writeset of committing transaction + * @param conn_id connection ID + * @param flags fine tuning the replication WSREP_FLAG_* + * @param meta transaction meta data + * + * @retval WSREP_OK cluster-wide commit succeeded + * @retval WSREP_TRX_FAIL must rollback transaction + * @retval WSREP_CONN_FAIL must close client connection + * @retval WSREP_NODE_FAIL must close all connections and reinit + */ + wsrep_status_t (*pre_commit)(wsrep_t* wsrep, + wsrep_conn_id_t conn_id, + wsrep_ws_handle_t* ws_handle, + uint32_t flags, + wsrep_trx_meta_t* meta); + + /*! + * @brief Releases resources after transaction commit. + * + * Ends commit critical section. + * + * @param wsrep provider handle + * @param ws_handle writeset of committing transaction + * @retval WSREP_OK post_commit succeeded + */ + wsrep_status_t (*post_commit) (wsrep_t* wsrep, + wsrep_ws_handle_t* ws_handle); + + /*! + * @brief Releases resources after transaction rollback. + * + * @param wsrep provider handle + * @param ws_handle writeset of committing transaction + * @retval WSREP_OK post_rollback succeeded + */ + wsrep_status_t (*post_rollback)(wsrep_t* wsrep, + wsrep_ws_handle_t* ws_handle); + + /*! + * @brief Replay trx as a slave writeset + * + * If local trx has been aborted by brute force, and it has already + * replicated before this abort, we must try if we can apply it as + * slave trx. Note that slave nodes see only trx writesets and certification + * test based on write set content can be different to DBMS lock conflicts. + * + * @param wsrep provider handle + * @param ws_handle writeset of committing transaction + * @param trx_ctx transaction context + * + * @retval WSREP_OK cluster commit succeeded + * @retval WSREP_TRX_FAIL must rollback transaction + * @retval WSREP_BF_ABORT brute force abort happened after trx replicated + * must rollback transaction and try to replay + * @retval WSREP_CONN_FAIL must close client connection + * @retval WSREP_NODE_FAIL must close all connections and reinit + */ + wsrep_status_t (*replay_trx)(wsrep_t* wsrep, + wsrep_ws_handle_t* ws_handle, + void* trx_ctx); + + /*! + * @brief Abort pre_commit() call of another thread. + * + * It is possible, that some high-priority transaction needs to abort + * another transaction which is in pre_commit() call waiting for resources. + * + * The kill routine checks that abort is not attmpted against a transaction + * which is front of the caller (in total order). + * + * @param wsrep provider handle + * @param bf_seqno seqno of brute force trx, running this cancel + * @param victim_trx transaction to be aborted, and which is committing + * + * @retval WSREP_OK abort secceded + * @retval WSREP_WARNING abort failed + */ + wsrep_status_t (*abort_pre_commit)(wsrep_t* wsrep, + wsrep_seqno_t bf_seqno, + wsrep_trx_id_t victim_trx); + + /*! + * @brief Appends a row reference to transaction writeset + * + * Both copy flag and key_type can be ignored by provider (key type + * interpreted as WSREP_KEY_EXCLUSIVE). + * + * @param wsrep provider handle + * @param ws_handle writeset handle + * @param keys array of keys + * @param count length of the array of keys + * @param type type ot the key + * @param copy can be set to FALSE if keys persist through commit. + */ + wsrep_status_t (*append_key)(wsrep_t* wsrep, + wsrep_ws_handle_t* ws_handle, + const wsrep_key_t* keys, + size_t count, + enum wsrep_key_type type, + wsrep_bool_t copy); + + /*! + * @brief Appends data to transaction writeset + * + * This method can be called any time before commit and it + * appends a number of data buffers to transaction writeset. + * + * Both copy and unordered flags can be ignored by provider. + * + * @param wsrep provider handle + * @param ws_handle writeset handle + * @param data array of data buffers + * @param count buffer count + * @param type type of data + * @param copy can be set to FALSE if data persists through commit. + */ + wsrep_status_t (*append_data)(wsrep_t* wsrep, + wsrep_ws_handle_t* ws_handle, + const struct wsrep_buf* data, + size_t count, + enum wsrep_data_type type, + wsrep_bool_t copy); + + /*! + * @brief Get causal ordering for read operation + * + * This call will block until causal ordering with all possible + * preceding writes in the cluster is guaranteed. If pointer to + * gtid is non-null, the call stores the global transaction ID + * of the last transaction which is guaranteed to be ordered + * causally before this call. + * + * @param wsrep provider handle + * @param gtid location to store GTID + */ + wsrep_status_t (*causal_read)(wsrep_t* wsrep, wsrep_gtid_t* gtid); + + /*! + * @brief Clears allocated connection context. + * + * Whenever a new connection ID is passed to wsrep provider through + * any of the API calls, a connection context is allocated for this + * connection. This call is to explicitly notify provider fo connection + * closing. + * + * @param wsrep provider handle + * @param conn_id connection ID + * @param query the 'set database' query + * @param query_len length of query (does not end with 0) + */ + wsrep_status_t (*free_connection)(wsrep_t* wsrep, + wsrep_conn_id_t conn_id); + + /*! + * @brief Replicates a query and starts "total order isolation" section. + * + * Replicates the action spec and returns success code, which caller must + * check. Total order isolation continues until to_execute_end() is called. + * + * @param wsrep provider handle + * @param conn_id connection ID + * @param keys array of keys + * @param keys_num lenght of the array of keys + * @param action action buffer array to be executed + * @param count action buffer count + * @param meta transaction meta data + * + * @retval WSREP_OK cluster commit succeeded + * @retval WSREP_CONN_FAIL must close client connection + * @retval WSREP_NODE_FAIL must close all connections and reinit + */ + wsrep_status_t (*to_execute_start)(wsrep_t* wsrep, + wsrep_conn_id_t conn_id, + const wsrep_key_t* keys, + size_t keys_num, + const struct wsrep_buf* action, + size_t count, + wsrep_trx_meta_t* meta); + + /*! + * @brief Ends the total order isolation section. + * + * Marks the end of total order isolation. TO locks are freed + * and other transactions are free to commit from this point on. + * + * @param wsrep provider handle + * @param conn_id connection ID + * + * @retval WSREP_OK cluster commit succeeded + * @retval WSREP_CONN_FAIL must close client connection + * @retval WSREP_NODE_FAIL must close all connections and reinit + */ + wsrep_status_t (*to_execute_end)(wsrep_t* wsrep, wsrep_conn_id_t conn_id); + + /*! + * @brief Collects preordered replication events into a writeset. + * + * @param wsrep wsrep provider handle + * @param handle a handle associated with a given writeset + * @param data an array of data buffers. + * @param count length of data buffer array. + * @param copy whether provider needs to make a copy of events. + * + * @retval WSREP_OK cluster-wide commit succeeded + * @retval WSREP_TRX_FAIL operation failed (e.g. trx size exceeded limit) + * @retval WSREP_NODE_FAIL must close all connections and reinit + */ + wsrep_status_t (*preordered_collect) (wsrep_t* wsrep, + wsrep_po_handle_t* handle, + const struct wsrep_buf* data, + size_t count, + wsrep_bool_t copy); + + /*! + * @brief "Commits" preordered writeset to cluster. + * + * The contract is that the writeset will be committed in the same (partial) + * order this method was called. Frees resources associated with the writeset + * handle and reinitializes the handle. + * + * @param wsrep wsrep provider handle + * @param po_handle a handle associated with a given writeset + * @param source_id ID of the event producer, also serves as the partial order + * or stream ID - events with different source_ids won't be + * ordered with respect to each other. + * @param flags WSREP_FLAG_... flags + * @param pa_range the number of preceding events this event can be processed + * in parallel with. A value of 0 means strict serial + * processing. Note: commits always happen in wsrep order. + * @param commit 'true' to commit writeset to cluster (replicate) or + * 'false' to rollback (cancel) the writeset. + * + * @retval WSREP_OK cluster-wide commit succeeded + * @retval WSREP_TRX_FAIL operation failed (e.g. NON-PRIMARY component) + * @retval WSREP_NODE_FAIL must close all connections and reinit + */ + wsrep_status_t (*preordered_commit) (wsrep_t* wsrep, + wsrep_po_handle_t* handle, + const wsrep_uuid_t* source_id, + uint32_t flags, + int pa_range, + wsrep_bool_t commit); + + /*! + * @brief Signals to wsrep provider that state snapshot has been sent to + * joiner. + * + * @param wsrep provider handle + * @param state_id state ID + * @param rcode 0 or negative error code of the operation. + */ + wsrep_status_t (*sst_sent)(wsrep_t* wsrep, + const wsrep_gtid_t* state_id, + int rcode); + + /*! + * @brief Signals to wsrep provider that new state snapshot has been received. + * May deadlock if called from sst_prepare_cb. + * + * @param wsrep provider handle + * @param state_id state ID + * @param state initial state provided by SST donor + * @param state_len length of state buffer + * @param rcode 0 or negative error code of the operation. + */ + wsrep_status_t (*sst_received)(wsrep_t* wsrep, + const wsrep_gtid_t* state_id, + const void* state, + size_t state_len, + int rcode); + + + /*! + * @brief Generate request for consistent snapshot. + * + * If successfull, this call will generate internally SST request + * which in turn triggers calling SST donate callback on the nodes + * specified in donor_spec. If donor_spec is null, callback is + * called only locally. This call will block until sst_sent is called + * from callback. + * + * @param wsrep provider handle + * @param msg context message for SST donate callback + * @param msg_len length of context message + * @param donor_spec list of snapshot donors + */ + wsrep_status_t (*snapshot)(wsrep_t* wsrep, + const void* msg, + size_t msg_len, + const char* donor_spec); + + /*! + * @brief Returns an array fo status variables. + * Array is terminated by Null variable name. + * + * @param wsrep provider handle + * @return array of struct wsrep_status_var. + */ + struct wsrep_stats_var* (*stats_get) (wsrep_t* wsrep); + + /*! + * @brief Release resources that might be associated with the array. + * + * @param wsrep provider handle. + * @param var_array array returned by stats_get(). + */ + void (*stats_free) (wsrep_t* wsrep, struct wsrep_stats_var* var_array); + + /*! + * @brief Reset some stats variables to inital value, provider-dependent. + * + * @param wsrep provider handle. + */ + void (*stats_reset) (wsrep_t* wsrep); + + /*! + * @brief Pauses writeset applying/committing. + * + * @return global sequence number of the paused state or negative error code. + */ + wsrep_seqno_t (*pause) (wsrep_t* wsrep); + + /*! + * @brief Resumes writeset applying/committing. + */ + wsrep_status_t (*resume) (wsrep_t* wsrep); + + /*! + * @brief Desynchronize from cluster + * + * Effectively turns off flow control for this node, allowing it + * to fall behind the cluster. + */ + wsrep_status_t (*desync) (wsrep_t* wsrep); + + /*! + * @brief Request to resynchronize with cluster. + * + * Effectively turns on flow control. Asynchronous - actual synchronization + * event to be deliverred via sync_cb. + */ + wsrep_status_t (*resync) (wsrep_t* wsrep); + + /*! + * @brief Acquire global named lock + * + * @param wsrep wsrep provider handle + * @param name lock name + * @param shared shared or exclusive lock + * @param owner 64-bit owner ID + * @param tout timeout in nanoseconds. + * 0 - return immediately, -1 wait forever. + * @return wsrep status or negative error code + * @retval -EDEADLK lock was already acquired by this thread + * @retval -EBUSY lock was busy + */ + wsrep_status_t (*lock) (wsrep_t* wsrep, + const char* name, wsrep_bool_t shared, + uint64_t owner, int64_t tout); + + /*! + * @brief Release global named lock + * + * @param wsrep wsrep provider handle + * @param name lock name + * @param owner 64-bit owner ID + * @return wsrep status or negative error code + * @retval -EPERM lock does not belong to this owner + */ + wsrep_status_t (*unlock) (wsrep_t* wsrep, const char* name, uint64_t owner); + + /*! + * @brief Check if global named lock is locked + * + * @param wsrep wsrep provider handle + * @param name lock name + * @param owner if not NULL will contain 64-bit owner ID + * @param node if not NULL will contain owner's node UUID + * @return true if lock is locked + */ + wsrep_bool_t (*is_locked) (wsrep_t* wsrep, const char* name, uint64_t* conn, + wsrep_uuid_t* node); + + /*! + * wsrep provider name + */ + const char* provider_name; + + /*! + * wsrep provider version + */ + const char* provider_version; + + /*! + * wsrep provider vendor name + */ + const char* provider_vendor; + + /*! + * @brief Frees allocated resources before unloading the library. + * @param wsrep provider handle + */ + void (*free)(wsrep_t* wsrep); + + void *dlh; //!< reserved for future use + void *ctx; //!< reserved for implemetation private context +}; + + +/*! + * + * @brief Loads wsrep library + * + * @param spec path to wsrep library. If NULL or WSREP_NONE initialises dummy + * pass-through implementation. + * @param hptr wsrep handle + * @param log_cb callback to handle loader messages. Otherwise writes to stderr. + * + * @return zero on success, errno on failure + */ +int wsrep_load(const char* spec, wsrep_t** hptr, wsrep_log_cb_t log_cb); + +/*! + * @brief Unloads wsrep library and frees associated resources + * + * @param hptr wsrep handler pointer + */ +void wsrep_unload(wsrep_t* hptr); + +#ifdef __cplusplus +} +#endif + +#endif /* WSREP_H */ diff --git a/wsrep/wsrep_dummy.c b/wsrep/wsrep_dummy.c new file mode 100644 index 00000000000..bab5329dc02 --- /dev/null +++ b/wsrep/wsrep_dummy.c @@ -0,0 +1,407 @@ +/* Copyright (C) 2009-2010 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/*! @file Dummy wsrep API implementation. */ + +#include "wsrep_api.h" + +#include +#include +#include + +/*! Dummy backend context. */ +typedef struct wsrep_dummy +{ + wsrep_log_cb_t log_fn; + char* options; +} wsrep_dummy_t; + +/* Get pointer to wsrep_dummy context from wsrep_t pointer */ +#define WSREP_DUMMY(_p) ((wsrep_dummy_t *) (_p)->ctx) + +/* Trace function usage a-la DBUG */ +#define WSREP_DBUG_ENTER(_w) do { \ + if (WSREP_DUMMY(_w)) { \ + if (WSREP_DUMMY(_w)->log_fn) \ + WSREP_DUMMY(_w)->log_fn(WSREP_LOG_DEBUG, __FUNCTION__); \ + } \ + } while (0) + + +static void dummy_free(wsrep_t *w) +{ + WSREP_DBUG_ENTER(w); + if (WSREP_DUMMY(w)->options) { + free(WSREP_DUMMY(w)->options); + WSREP_DUMMY(w)->options = NULL; + } + free(w->ctx); + w->ctx = NULL; +} + +static wsrep_status_t dummy_init (wsrep_t* w, + const struct wsrep_init_args* args) +{ + WSREP_DUMMY(w)->log_fn = args->logger_cb; + WSREP_DBUG_ENTER(w); + if (args->options) { + WSREP_DUMMY(w)->options = strdup(args->options); + } + return WSREP_OK; +} + +static uint64_t dummy_capabilities (wsrep_t* w __attribute__((unused))) +{ + return 0; +} + +static wsrep_status_t dummy_options_set( + wsrep_t* w, + const char* conf) +{ + WSREP_DBUG_ENTER(w); + if (WSREP_DUMMY(w)->options) { + free(WSREP_DUMMY(w)->options); + WSREP_DUMMY(w)->options = NULL; + } + if (conf) { + WSREP_DUMMY(w)->options = strdup(conf); + } + return WSREP_OK; +} + +static char* dummy_options_get (wsrep_t* w) +{ + WSREP_DBUG_ENTER(w); + return WSREP_DUMMY(w)->options; +} + +static wsrep_status_t dummy_connect( + wsrep_t* w, + const char* name __attribute__((unused)), + const char* url __attribute__((unused)), + const char* donor __attribute__((unused)), + wsrep_bool_t bootstrap __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_disconnect(wsrep_t* w) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_recv(wsrep_t* w, + void* recv_ctx __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_pre_commit( + wsrep_t* w, + const wsrep_conn_id_t conn_id __attribute__((unused)), + wsrep_ws_handle_t* ws_handle __attribute__((unused)), + uint32_t flags __attribute__((unused)), + wsrep_trx_meta_t* meta __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_post_commit( + wsrep_t* w, + wsrep_ws_handle_t* ws_handle __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_post_rollback( + wsrep_t* w, + wsrep_ws_handle_t* ws_handle __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_replay_trx( + wsrep_t* w, + wsrep_ws_handle_t* ws_handle __attribute__((unused)), + void* trx_ctx __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_abort_pre_commit( + wsrep_t* w, + const wsrep_seqno_t bf_seqno __attribute__((unused)), + const wsrep_trx_id_t trx_id __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_append_key( + wsrep_t* w, + wsrep_ws_handle_t* ws_handle __attribute__((unused)), + const wsrep_key_t* key __attribute__((unused)), + const size_t key_num __attribute__((unused)), + const wsrep_key_type_t key_type __attribute__((unused)), + const bool copy __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_append_data( + wsrep_t* w, + wsrep_ws_handle_t* ws_handle __attribute__((unused)), + const struct wsrep_buf* data __attribute__((unused)), + const size_t count __attribute__((unused)), + const wsrep_data_type_t type __attribute__((unused)), + const bool copy __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_causal_read( + wsrep_t* w, + wsrep_gtid_t* gtid __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_free_connection( + wsrep_t* w, + const wsrep_conn_id_t conn_id __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_to_execute_start( + wsrep_t* w, + const wsrep_conn_id_t conn_id __attribute__((unused)), + const wsrep_key_t* key __attribute__((unused)), + const size_t key_num __attribute__((unused)), + const struct wsrep_buf* data __attribute__((unused)), + const size_t count __attribute__((unused)), + wsrep_trx_meta_t* meta __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_to_execute_end( + wsrep_t* w, + const wsrep_conn_id_t conn_id __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_preordered_collect( + wsrep_t* w, + wsrep_po_handle_t* handle __attribute__((unused)), + const struct wsrep_buf* data __attribute__((unused)), + size_t count __attribute__((unused)), + wsrep_bool_t copy __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_preordered_commit( + wsrep_t* w, + wsrep_po_handle_t* handle __attribute__((unused)), + const wsrep_uuid_t* source_id __attribute__((unused)), + uint32_t flags __attribute__((unused)), + int pa_range __attribute__((unused)), + wsrep_bool_t commit __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_sst_sent( + wsrep_t* w, + const wsrep_gtid_t* state_id __attribute__((unused)), + const int rcode __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_sst_received( + wsrep_t* w, + const wsrep_gtid_t* state_id __attribute__((unused)), + const void* state __attribute__((unused)), + const size_t state_len __attribute__((unused)), + const int rcode __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_snapshot( + wsrep_t* w, + const void* msg __attribute__((unused)), + const size_t msg_len __attribute__((unused)), + const char* donor_spec __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static struct wsrep_stats_var dummy_stats[] = { + { NULL, WSREP_VAR_STRING, { 0 } } +}; + +static struct wsrep_stats_var* dummy_stats_get (wsrep_t* w) +{ + WSREP_DBUG_ENTER(w); + return dummy_stats; +} + +static void dummy_stats_free ( + wsrep_t* w, + struct wsrep_stats_var* stats __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); +} + +static void dummy_stats_reset (wsrep_t* w) +{ + WSREP_DBUG_ENTER(w); +} + +static wsrep_seqno_t dummy_pause (wsrep_t* w) +{ + WSREP_DBUG_ENTER(w); + return -ENOSYS; +} + +static wsrep_status_t dummy_resume (wsrep_t* w) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_desync (wsrep_t* w) +{ + WSREP_DBUG_ENTER(w); + return WSREP_NOT_IMPLEMENTED; +} + +static wsrep_status_t dummy_resync (wsrep_t* w) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_lock (wsrep_t* w, + const char* s __attribute__((unused)), + bool r __attribute__((unused)), + uint64_t o __attribute__((unused)), + int64_t t __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_NOT_IMPLEMENTED; +} + +static wsrep_status_t dummy_unlock (wsrep_t* w, + const char* s __attribute__((unused)), + uint64_t o __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static bool dummy_is_locked (wsrep_t* w, + const char* s __attribute__((unused)), + uint64_t* o __attribute__((unused)), + wsrep_uuid_t* t __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return false; +} + +static wsrep_t dummy_iface = { + WSREP_INTERFACE_VERSION, + &dummy_init, + &dummy_capabilities, + &dummy_options_set, + &dummy_options_get, + &dummy_connect, + &dummy_disconnect, + &dummy_recv, + &dummy_pre_commit, + &dummy_post_commit, + &dummy_post_rollback, + &dummy_replay_trx, + &dummy_abort_pre_commit, + &dummy_append_key, + &dummy_append_data, + &dummy_causal_read, + &dummy_free_connection, + &dummy_to_execute_start, + &dummy_to_execute_end, + &dummy_preordered_collect, + &dummy_preordered_commit, + &dummy_sst_sent, + &dummy_sst_received, + &dummy_snapshot, + &dummy_stats_get, + &dummy_stats_free, + &dummy_stats_reset, + &dummy_pause, + &dummy_resume, + &dummy_desync, + &dummy_resync, + &dummy_lock, + &dummy_unlock, + &dummy_is_locked, + WSREP_NONE, + WSREP_INTERFACE_VERSION, + "Codership Oy ", + &dummy_free, + NULL, + NULL +}; + +int wsrep_dummy_loader(wsrep_t* w) +{ + if (!w) + return EINVAL; + + *w = dummy_iface; + + // allocate private context + if (!(w->ctx = malloc(sizeof(wsrep_dummy_t)))) + return ENOMEM; + + // initialize private context + WSREP_DUMMY(w)->log_fn = NULL; + WSREP_DUMMY(w)->options = NULL; + + return 0; +} diff --git a/wsrep/wsrep_gtid.c b/wsrep/wsrep_gtid.c new file mode 100644 index 00000000000..e618c5ab7d0 --- /dev/null +++ b/wsrep/wsrep_gtid.c @@ -0,0 +1,74 @@ +/* Copyright (C) 2013 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/*! @file Helper functions to deal with GTID string representations */ + +#include +#include +#include +#include + +#include "wsrep_api.h" + +/*! + * Read GTID from string + * @return length of GTID string representation or -EINVAL in case of error + */ +int +wsrep_gtid_scan(const char* str, size_t str_len, wsrep_gtid_t* gtid) +{ + unsigned int offset; + char* endptr; + + if ((offset = wsrep_uuid_scan(str, str_len, >id->uuid)) > 0 && + offset < str_len && str[offset] == ':') { + ++offset; + if (offset < str_len) + { + errno = 0; + gtid->seqno = strtoll(str + offset, &endptr, 0); + + if (errno == 0) { + offset = endptr - str; + return offset; + } + } + } + *gtid = WSREP_GTID_UNDEFINED; + return -EINVAL; +} + +/*! + * Write GTID to string + * @return length of GTID stirng representation of -EMSGSIZE if string is too + * short + */ +int +wsrep_gtid_print(const wsrep_gtid_t* gtid, char* str, size_t str_len) +{ + unsigned int offset, ret; + if ((offset = wsrep_uuid_print(>id->uuid, str, str_len)) > 0) + { + ret = snprintf(str + offset, str_len - offset, + ":%" PRId64, gtid->seqno); + if (ret <= str_len - offset) { + return (offset + ret); + } + + } + + return -EMSGSIZE; +} diff --git a/wsrep/wsrep_loader.c b/wsrep/wsrep_loader.c new file mode 100644 index 00000000000..8ae6ea962ec --- /dev/null +++ b/wsrep/wsrep_loader.c @@ -0,0 +1,203 @@ +/* Copyright (C) 2009-2011 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/*! @file wsrep implementation loader */ + +#include +#include +#include +#include + +#include "wsrep_api.h" + +// Logging stuff for the loader +static const char* log_levels[] = {"FATAL", "ERROR", "WARN", "INFO", "DEBUG"}; + +static void default_logger (wsrep_log_level_t lvl, const char* msg) +{ + fprintf (stderr, "wsrep loader: [%s] %s\n", log_levels[lvl], msg); +} + +static wsrep_log_cb_t logger = default_logger; + +/************************************************************************** + * Library loader + **************************************************************************/ + +static int verify(const wsrep_t *wh, const char *iface_ver) +{ + const size_t msg_len = 128; + char msg[msg_len]; + +#define VERIFY(_p) if (!(_p)) { \ + snprintf(msg, msg_len, "wsrep_load(): verify(): %s\n", # _p); \ + logger (WSREP_LOG_ERROR, msg); \ + return EINVAL; \ + } + + VERIFY(wh); + VERIFY(wh->version); + + if (strcmp(wh->version, iface_ver)) { + snprintf (msg, msg_len, + "provider interface version mismatch: need '%s', found '%s'", + iface_ver, wh->version); + logger (WSREP_LOG_ERROR, msg); + return EINVAL; + } + + VERIFY(wh->init); + VERIFY(wh->options_set); + VERIFY(wh->options_get); + VERIFY(wh->connect); + VERIFY(wh->disconnect); + VERIFY(wh->recv); + VERIFY(wh->pre_commit); + VERIFY(wh->post_commit); + VERIFY(wh->post_rollback); + VERIFY(wh->replay_trx); + VERIFY(wh->abort_pre_commit); + VERIFY(wh->append_key); + VERIFY(wh->append_data); + VERIFY(wh->free_connection); + VERIFY(wh->to_execute_start); + VERIFY(wh->to_execute_end); + VERIFY(wh->preordered_collect); + VERIFY(wh->preordered_commit); + VERIFY(wh->sst_sent); + VERIFY(wh->sst_received); + VERIFY(wh->stats_get); + VERIFY(wh->stats_free); + VERIFY(wh->stats_reset); + VERIFY(wh->pause); + VERIFY(wh->resume); + VERIFY(wh->desync); + VERIFY(wh->resync); + VERIFY(wh->lock); + VERIFY(wh->unlock); + VERIFY(wh->is_locked); + VERIFY(wh->provider_name); + VERIFY(wh->provider_version); + VERIFY(wh->provider_vendor); + VERIFY(wh->free); + return 0; +} + +typedef int (*wsrep_loader_fun)(wsrep_t*); + +static wsrep_loader_fun wsrep_dlf(void *dlh, const char *sym) +{ + union { + wsrep_loader_fun dlfun; + void *obj; + } alias; + alias.obj = dlsym(dlh, sym); + return alias.dlfun; +} + +extern int wsrep_dummy_loader(wsrep_t *w); + +int wsrep_load(const char *spec, wsrep_t **hptr, wsrep_log_cb_t log_cb) +{ + int ret = 0; + void *dlh = NULL; + wsrep_loader_fun dlfun; + const size_t msg_len = 1024; + char msg[msg_len + 1]; + msg[msg_len] = 0; + + if (NULL != log_cb) + logger = log_cb; + + if (!(spec && hptr)) + return EINVAL; + + snprintf (msg, msg_len, + "wsrep_load(): loading provider library '%s'", spec); + logger (WSREP_LOG_INFO, msg); + + if (!(*hptr = malloc(sizeof(wsrep_t)))) { + logger (WSREP_LOG_FATAL, "wsrep_load(): out of memory"); + return ENOMEM; + } + + if (!spec || strcmp(spec, WSREP_NONE) == 0) { + if ((ret = wsrep_dummy_loader(*hptr)) != 0) { + free (*hptr); + *hptr = NULL; + } + return ret; + } + + if (!(dlh = dlopen(spec, RTLD_NOW | RTLD_LOCAL))) { + snprintf(msg, msg_len, "wsrep_load(): dlopen(): %s", dlerror()); + logger (WSREP_LOG_ERROR, msg); + ret = EINVAL; + goto out; + } + + if (!(dlfun = wsrep_dlf(dlh, "wsrep_loader"))) { + ret = EINVAL; + goto out; + } + + if ((ret = (*dlfun)(*hptr)) != 0) { + snprintf(msg, msg_len, "wsrep_load(): loader failed: %s", + strerror(ret)); + logger (WSREP_LOG_ERROR, msg); + goto out; + } + + if ((ret = verify(*hptr, WSREP_INTERFACE_VERSION)) != 0) { + snprintf (msg, msg_len, + "wsrep_load(): interface version mismatch: my version %s, " + "provider version %s", WSREP_INTERFACE_VERSION, + (*hptr)->version); + logger (WSREP_LOG_ERROR, msg); + goto out; + } + + (*hptr)->dlh = dlh; + +out: + if (ret != 0) { + if (dlh) dlclose(dlh); + free(*hptr); + *hptr = NULL; + } else { + snprintf (msg, msg_len, + "wsrep_load(): %s %s by %s loaded successfully.", + (*hptr)->provider_name, (*hptr)->provider_version, + (*hptr)->provider_vendor); + logger (WSREP_LOG_INFO, msg); + } + + return ret; +} + +void wsrep_unload(wsrep_t *hptr) +{ + if (!hptr) { + logger (WSREP_LOG_WARN, "wsrep_unload(): null pointer."); + } else { + if (hptr->free) + hptr->free(hptr); + if (hptr->dlh) + dlclose(hptr->dlh); + free(hptr); + } +} + diff --git a/wsrep/wsrep_uuid.c b/wsrep/wsrep_uuid.c new file mode 100644 index 00000000000..baa95b2578a --- /dev/null +++ b/wsrep/wsrep_uuid.c @@ -0,0 +1,83 @@ +/* Copyright (C) 2009 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/*! @file Helper functions to deal with history UUID string representations */ + +#include +#include +#include + +#include "wsrep_api.h" + +/*! + * Read UUID from string + * @return length of UUID string representation or -EINVAL in case of error + */ +int +wsrep_uuid_scan (const char* str, size_t str_len, wsrep_uuid_t* uuid) +{ + unsigned int uuid_len = 0; + unsigned int uuid_offt = 0; + + while (uuid_len + 1 < str_len) { + /* We are skipping potential '-' after uuid_offt == 4, 6, 8, 10 + * which means + * (uuid_offt >> 1) == 2, 3, 4, 5, + * which in turn means + * (uuid_offt >> 1) - 2 <= 3 + * since it is always >= 0, because uuid_offt is unsigned */ + if (((uuid_offt >> 1) - 2) <= 3 && str[uuid_len] == '-') { + // skip dashes after 4th, 6th, 8th and 10th positions + uuid_len += 1; + continue; + } + + if (isxdigit(str[uuid_len]) && isxdigit(str[uuid_len + 1])) { + // got hex digit, scan another byte to uuid, increment uuid_offt + sscanf (str + uuid_len, "%2hhx", uuid->data + uuid_offt); + uuid_len += 2; + uuid_offt += 1; + if (sizeof (uuid->data) == uuid_offt) + return uuid_len; + } + else { + break; + } + } + + *uuid = WSREP_UUID_UNDEFINED; + return -EINVAL; +} + +/*! + * Write UUID to string + * @return length of UUID string representation or -EMSGSIZE if string is too + * short + */ +int +wsrep_uuid_print (const wsrep_uuid_t* uuid, char* str, size_t str_len) +{ + if (str_len > 36) { + const unsigned char* u = uuid->data; + return snprintf(str, str_len, "%02x%02x%02x%02x-%02x%02x-%02x%02x-" + "%02x%02x-%02x%02x%02x%02x%02x%02x", + u[ 0], u[ 1], u[ 2], u[ 3], u[ 4], u[ 5], u[ 6], u[ 7], + u[ 8], u[ 9], u[10], u[11], u[12], u[13], u[14], u[15]); + } + else { + return -EMSGSIZE; + } +} From 3bde13932ee53ee765a858e4413bc6c6af296d4b Mon Sep 17 00:00:00 2001 From: Monty Date: Sun, 3 Aug 2014 15:12:10 +0300 Subject: [PATCH 002/153] Minor cleanups, fix compiler warnings --- extra/my_print_defaults.c | 11 ++++++++--- sql/events.cc | 4 +++- sql/handler.cc | 5 ++--- sql/sql_class.cc | 4 ++-- storage/innobase/include/dict0dict.ic | 6 +++--- storage/innobase/include/dict0pagecompress.ic | 2 +- storage/innobase/include/fsp0fsp.ic | 2 +- storage/xtradb/include/dict0dict.ic | 6 +++--- storage/xtradb/include/dict0pagecompress.ic | 2 +- storage/xtradb/include/fsp0fsp.ic | 2 +- 10 files changed, 25 insertions(+), 19 deletions(-) diff --git a/extra/my_print_defaults.c b/extra/my_print_defaults.c index e91163dde1c..bfd0c3c635a 100644 --- a/extra/my_print_defaults.c +++ b/extra/my_print_defaults.c @@ -98,6 +98,11 @@ static struct my_option my_long_options[] = {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; +void cleanup_and_exit(int exit_code) +{ + my_end(0); + exit(exit_code); +} static void usage(my_bool version) { @@ -112,7 +117,7 @@ static void usage(my_bool version) my_print_default_files(config_file); my_print_variables(my_long_options); printf("\nExample usage:\n%s --defaults-file=example.cnf client client-server mysql\n", my_progname); - exit(0); + cleanup_and_exit(0); } @@ -125,7 +130,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), opt_defaults_file_used= 1; break; case 'n': - exit(0); + cleanup_and_exit(0); case 'I': case '?': usage(0); @@ -174,7 +179,7 @@ int main(int argc, char **argv) /* Check out the args */ if (get_options(&argc,&argv)) - exit(1); + cleanup_and_exit(1); nargs= argc + 1; if (opt_mysqld) diff --git a/sql/events.cc b/sql/events.cc index 63627b21777..a81447396d4 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -270,6 +270,7 @@ common_1_lev_code: static int create_query_string(THD *thd, String *buf) { + buf->length(0); /* Append the "CREATE" part of the query */ if (buf->append(STRING_WITH_LEN("CREATE "))) return 1; @@ -380,7 +381,8 @@ Events::create_event(THD *thd, Event_parse_data *parse_data, { /* Binlog the create event. */ DBUG_ASSERT(thd->query() && thd->query_length()); - String log_query; + char buffer[1024]; + String log_query(buffer, sizeof(buffer), &my_charset_bin); if (create_query_string(thd, &log_query)) { sql_print_error("Event Error: An error occurred while creating query " diff --git a/sql/handler.cc b/sql/handler.cc index 56e7da6430d..cc8fa528251 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1414,11 +1414,10 @@ int ha_commit_trans(THD *thd, bool all) err= ht->prepare(ht, thd, all); status_var_increment(thd->status_var.ha_prepare_count); if (err) + { my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); - - if (err) goto err; - + } need_prepare_ordered|= (ht->prepare_ordered != NULL); need_commit_ordered|= (ht->commit_ordered != NULL); } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 8d6ddc0bb08..b0760b1615c 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1355,8 +1355,8 @@ void THD::init(void) mysql_mutex_lock(&LOCK_global_system_variables); plugin_thdvar_init(this); /* - variables= global_system_variables above has reset - variables.pseudo_thread_id to 0. We need to correct it here to + plugin_thd_var_init() sets variables= global_system_variables, which + has reset variables.pseudo_thread_id to 0. We need to correct it here to avoid temporary tables replication failure. */ variables.pseudo_thread_id= thread_id; diff --git a/storage/innobase/include/dict0dict.ic b/storage/innobase/include/dict0dict.ic index 497a3bd86e6..84d5c57f720 100644 --- a/storage/innobase/include/dict0dict.ic +++ b/storage/innobase/include/dict0dict.ic @@ -647,7 +647,7 @@ dict_tf_is_valid( if (atomic_writes) { - if(atomic_writes < 0 || atomic_writes > ATOMIC_WRITES_OFF) { + if(atomic_writes > ATOMIC_WRITES_OFF) { fprintf(stderr, "InnoDB: Error: table flags are %ld in the data dictionary and are corrupted\n" @@ -689,7 +689,7 @@ dict_sys_tables_type_validate( ulint page_compression_level = DICT_TF_GET_PAGE_COMPRESSION_LEVEL(type); ulint atomic_writes = DICT_TF_GET_ATOMIC_WRITES(type); - ut_a(atomic_writes >= 0 && atomic_writes <= ATOMIC_WRITES_OFF); + ut_a(atomic_writes <= ATOMIC_WRITES_OFF); /* The low order bit of SYS_TABLES.TYPE is always set to 1. If the format is UNIV_FORMAT_B or higher, this field is the same @@ -768,7 +768,7 @@ dict_sys_tables_type_validate( } /* Validate that the atomic writes number is within allowed range. */ - if (atomic_writes < 0 || atomic_writes > ATOMIC_WRITES_OFF) { + if (atomic_writes > ATOMIC_WRITES_OFF) { fprintf(stderr, "InnoDB: Error: SYS_TABLES::TYPE=%lu, atomic_writes %lu\n", type, atomic_writes); return(ULINT_UNDEFINED); diff --git a/storage/innobase/include/dict0pagecompress.ic b/storage/innobase/include/dict0pagecompress.ic index ea3c7546850..811976434a8 100644 --- a/storage/innobase/include/dict0pagecompress.ic +++ b/storage/innobase/include/dict0pagecompress.ic @@ -122,7 +122,7 @@ dict_tf_get_page_compression_level( { ulint page_compression_level = DICT_TF_GET_PAGE_COMPRESSION_LEVEL(flags); - ut_ad(page_compression_level >= 0 && page_compression_level <= 9); + ut_ad(page_compression_level <= 9); return(page_compression_level); } diff --git a/storage/innobase/include/fsp0fsp.ic b/storage/innobase/include/fsp0fsp.ic index fb253370b6e..3a3eb21a61a 100644 --- a/storage/innobase/include/fsp0fsp.ic +++ b/storage/innobase/include/fsp0fsp.ic @@ -131,7 +131,7 @@ fsp_flags_is_valid( } } - if (atomic_writes < 0 || atomic_writes > ATOMIC_WRITES_OFF) { + if (atomic_writes > ATOMIC_WRITES_OFF) { fprintf(stderr, "InnoDB: Error: Tablespace flags %lu corrupted atomic_writes %lu\n", flags, atomic_writes); return (false); diff --git a/storage/xtradb/include/dict0dict.ic b/storage/xtradb/include/dict0dict.ic index 435b244ec3d..2b698dd7218 100644 --- a/storage/xtradb/include/dict0dict.ic +++ b/storage/xtradb/include/dict0dict.ic @@ -651,7 +651,7 @@ dict_tf_is_valid( if (atomic_writes) { - if(atomic_writes < 0 || atomic_writes > ATOMIC_WRITES_OFF) { + if(atomic_writes > ATOMIC_WRITES_OFF) { fprintf(stderr, "InnoDB: Error: table flags are %ld in the data dictionary and are corrupted\n" @@ -693,7 +693,7 @@ dict_sys_tables_type_validate( ulint page_compression_level = DICT_TF_GET_PAGE_COMPRESSION_LEVEL(type); ulint atomic_writes = DICT_TF_GET_ATOMIC_WRITES(type); - ut_a(atomic_writes >= 0 && atomic_writes <= ATOMIC_WRITES_OFF); + ut_a(atomic_writes <= ATOMIC_WRITES_OFF); /* The low order bit of SYS_TABLES.TYPE is always set to 1. If the format is UNIV_FORMAT_B or higher, this field is the same @@ -772,7 +772,7 @@ dict_sys_tables_type_validate( } /* Validate that the atomic writes number is within allowed range. */ - if (atomic_writes < 0 || atomic_writes > ATOMIC_WRITES_OFF) { + if (atomic_writes > ATOMIC_WRITES_OFF) { fprintf(stderr, "InnoDB: Error: SYS_TABLES::TYPE=%lu, atomic_writes %lu\n", type, atomic_writes); return(ULINT_UNDEFINED); diff --git a/storage/xtradb/include/dict0pagecompress.ic b/storage/xtradb/include/dict0pagecompress.ic index ea3c7546850..811976434a8 100644 --- a/storage/xtradb/include/dict0pagecompress.ic +++ b/storage/xtradb/include/dict0pagecompress.ic @@ -122,7 +122,7 @@ dict_tf_get_page_compression_level( { ulint page_compression_level = DICT_TF_GET_PAGE_COMPRESSION_LEVEL(flags); - ut_ad(page_compression_level >= 0 && page_compression_level <= 9); + ut_ad(page_compression_level <= 9); return(page_compression_level); } diff --git a/storage/xtradb/include/fsp0fsp.ic b/storage/xtradb/include/fsp0fsp.ic index 3563f5ef372..ddcb87b0e57 100644 --- a/storage/xtradb/include/fsp0fsp.ic +++ b/storage/xtradb/include/fsp0fsp.ic @@ -135,7 +135,7 @@ fsp_flags_is_valid( } } - if (atomic_writes < 0 || atomic_writes > ATOMIC_WRITES_OFF) { + if (atomic_writes > ATOMIC_WRITES_OFF) { fprintf(stderr, "InnoDB: Error: Tablespace flags %lu corrupted atomic_writes %lu\n", flags, atomic_writes); return (false); From b4c74e2ab4c3676dd081421649de83ee0fb0f63c Mon Sep 17 00:00:00 2001 From: Monty Date: Sun, 3 Aug 2014 15:12:53 +0300 Subject: [PATCH 003/153] Change MySQL -> MariaDB inc scripts --- scripts/make_binary_distribution.sh | 4 +-- scripts/mysql_config.sh | 4 +-- scripts/mysql_convert_table_format.sh | 2 +- scripts/mysql_find_rows.sh | 2 +- scripts/mysql_fix_extensions.sh | 6 ++-- scripts/mysql_setpermission.sh | 18 +++++----- scripts/mysql_zap.sh | 4 +-- scripts/mysqlaccess.sh | 6 ++-- scripts/mysqld_multi.sh | 50 +++++++++++++-------------- scripts/mytop.sh | 39 ++++++++++----------- 10 files changed, 67 insertions(+), 68 deletions(-) diff --git a/scripts/make_binary_distribution.sh b/scripts/make_binary_distribution.sh index 663686ac1c8..3a0f34ae44d 100644 --- a/scripts/make_binary_distribution.sh +++ b/scripts/make_binary_distribution.sh @@ -234,8 +234,8 @@ set -e if test -f ./client/.libs/mysql then echo "" - echo "The MySQL clients are compiled dynamicly, which is not allowed for" - echo "a MySQL binary tar file. Please configure with" + echo "The MariaDB clients are compiled dynamically, which is not allowed for" + echo "a MariaDB binary tar file. Please configure with" echo "--with-client-ldflags=-all-static and try again" exit 1; fi diff --git a/scripts/mysql_config.sh b/scripts/mysql_config.sh index beff6e5eb5f..938fbbfbeea 100644 --- a/scripts/mysql_config.sh +++ b/scripts/mysql_config.sh @@ -15,7 +15,7 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # This script reports various configuration settings that may be needed -# when using the MySQL client library. +# when using the MariaDB client library. which () { @@ -39,7 +39,7 @@ which () # # If we can find the given directory relatively to where mysql_config is # we should use this instead of the incompiled one. -# This is to ensure that this script also works with the binary MySQL +# This is to ensure that this script also works with the binary MariaDB # version fix_path () diff --git a/scripts/mysql_convert_table_format.sh b/scripts/mysql_convert_table_format.sh index 5f3e093d2b9..d8258726347 100644 --- a/scripts/mysql_convert_table_format.sh +++ b/scripts/mysql_convert_table_format.sh @@ -125,7 +125,7 @@ sub usage print <; chomp($opt_password); system "stty echo"; @@ -86,7 +86,7 @@ if ($opt_password eq '') } -# make the connection to MySQL +# make the connection to MariaDB $dbh= DBI->connect("DBI:mysql:mysql:host=$sqlhost:port=$opt_port:mysql_socket=$opt_socket",$opt_user,$opt_password, {PrintError => 0}) || die("Can't make a connection to the mysql server.\n The error: $DBI::errstr"); @@ -106,7 +106,7 @@ sub q1 { # first question ... while (! $end) { print "#"x70; print "\n"; - print "## Welcome to the permission setter $version for MySQL.\n"; + print "## Welcome to the permission setter $version for MariaDB.\n"; print "## made by Luuk de Boer\n"; print "#"x70; print "\n"; @@ -634,17 +634,17 @@ sub usage { print < ---------------------------------------------------------------------- The permission setter is a little program which can help you add users -or databases or change passwords in MySQL. Keep in mind that we don't -check permissions which already been set in MySQL. So if you can't -connect to MySQL using the permission you just added, take a look at -the permissions which have already been set in MySQL. +or databases or change passwords in MariaDB. Keep in mind that we don't +check permissions which already been set in MariaDB. So if you can't +connect to MariaDB using the permission you just added, take a look at +the permissions which have already been set in MariaDB. The permission setter first reads your .my.cnf file in your Home directory if it exists. @@ -653,7 +653,7 @@ Options for the permission setter: --help : print this help message and exit. -The options shown below are used for making the connection to the MySQL +The options shown below are used for making the connection to the MariaDB server. Keep in mind that the permissions for the user specified via these options must be sufficient to add users / create databases / set passwords. diff --git a/scripts/mysql_zap.sh b/scripts/mysql_zap.sh index a9c3e7a7f5a..98c3603df15 100644 --- a/scripts/mysql_zap.sh +++ b/scripts/mysql_zap.sh @@ -15,8 +15,8 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -# This is a utility for MySQL. It is not needed by any standard part -# of MySQL. +# This is a utility for MariaDB. It is not needed by any standard part +# of MariaDB. # Usage: mysql_zap [-signal] [-f] [-t] pattern diff --git a/scripts/mysqlaccess.sh b/scripts/mysqlaccess.sh index 1d01c84735a..f422b6a7dc8 100644 --- a/scripts/mysqlaccess.sh +++ b/scripts/mysqlaccess.sh @@ -34,7 +34,7 @@ BEGIN { $script_log = $ENV{'HOME'}."/$script.log"; # **************************** - # information on MySQL + # information on MariaDB $MYSQL = '@bindir@/mysql'; # path to mysql executable $SERVER = '3.21'; $MYSQL_OPT = ' --batch --unbuffered'; @@ -97,8 +97,8 @@ Usage: $script [host [user [db]]] OPTIONS -U, --superuser=# connect as superuser -P, --spassword=# password for superuser - -H, --rhost=# remote MySQL-server to connect to - --old_server connect to old MySQL-server (before v3.21) which + -H, --rhost=# remote MariaDB-server to connect to + --old_server connect to old MariaDB-server (before v3.21) which does not yet know how to handle full where clauses. -b, --brief single-line tabular report diff --git a/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh index cd1b6fc18b7..570806a615c 100644 --- a/scripts/mysqld_multi.sh +++ b/scripts/mysqld_multi.sh @@ -103,7 +103,7 @@ sub main print "WARNING: my_print_defaults command not found.\n"; print "Please make sure you have this command available and\n"; print "in your path. The command is available from the latest\n"; - print "MySQL distribution.\n"; + print "MariaDB distribution.\n"; $my_print_defaults_exists= 0; } @@ -153,7 +153,7 @@ sub main if (!defined(my_which(my_print_defaults))) { print "ABORT: Can't find command 'my_print_defaults'.\n"; - print "This command is available from the latest MySQL\n"; + print "This command is available from the latest MariaDB\n"; print "distribution. Please make sure you have the command\n"; print "in your PATH.\n"; exit(1); @@ -265,17 +265,17 @@ sub init_log } #### -#### Report living and not running MySQL servers +#### Report living and not running MariaDB servers #### sub report_mysqlds { my (@groups, $com, $i, @options, $pec); - print "Reporting MySQL servers\n"; + print "Reporting MariaDB servers\n"; if (!$opt_no_log) { - w2log("\nReporting MySQL servers","$opt_log",0,0); + w2log("\nReporting MariaDB servers","$opt_log",0,0); } @groups = &find_groups($groupids); for ($i = 0; defined($groups[$i]); $i++) @@ -286,19 +286,19 @@ sub report_mysqlds $pec = $? >> 8; if ($pec) { - print "MySQL server from group: $groups[$i] is not running\n"; + print "MariaDB server from group: $groups[$i] is not running\n"; if (!$opt_no_log) { - w2log("MySQL server from group: $groups[$i] is not running", + w2log("MariaDB server from group: $groups[$i] is not running", "$opt_log", 0, 0); } } else { - print "MySQL server from group: $groups[$i] is running\n"; + print "MariaDB server from group: $groups[$i] is running\n"; if (!$opt_no_log) { - w2log("MySQL server from group: $groups[$i] is running", + w2log("MariaDB server from group: $groups[$i] is running", "$opt_log", 0, 0); } } @@ -323,11 +323,11 @@ sub start_mysqlds() if (!$opt_no_log) { - w2log("\nStarting MySQL servers\n","$opt_log",0,0); + w2log("\nStarting MariaDB servers\n","$opt_log",0,0); } else { - print "\nStarting MySQL servers\n"; + print "\nStarting MariaDB servers\n"; } @groups = &find_groups($groupids); for ($i = 0; defined($groups[$i]); $i++) @@ -398,7 +398,7 @@ sub start_mysqlds() } if (!$i && !$opt_no_log) { - w2log("No MySQL servers to be started (check your GNRs)", + w2log("No MariaDB servers to be started (check your GNRs)", "$opt_log", 0, 0); } } @@ -413,11 +413,11 @@ sub stop_mysqlds() if (!$opt_no_log) { - w2log("\nStopping MySQL servers\n","$opt_log",0,0); + w2log("\nStopping MariaDB servers\n","$opt_log",0,0); } else { - print "\nStopping MySQL servers\n"; + print "\nStopping MariaDB servers\n"; } @groups = &find_groups($groupids); for ($i = 0; defined($groups[$i]); $i++) @@ -430,7 +430,7 @@ sub stop_mysqlds() } if (!$i && !$opt_no_log) { - w2log("No MySQL servers to be stopped (check your GNRs)", + w2log("No MariaDB servers to be stopped (check your GNRs)", "$opt_log", 0, 0); } } @@ -638,23 +638,23 @@ sub example # # 1.COMMON USER # -# Make sure that the MySQL user, who is stopping the mysqld services, has -# the same password to all MySQL servers being accessed by $my_progname. +# Make sure that the MariaDB user, who is stopping the mysqld services, has +# the same password to all MariaDB servers being accessed by $my_progname. # This user needs to have the 'Shutdown_priv' -privilege, but for security # reasons should have no other privileges. It is advised that you create a -# common 'multi_admin' user for all MySQL servers being controlled by +# common 'multi_admin' user for all MariaDB servers being controlled by # $my_progname. Here is an example how to do it: # # GRANT SHUTDOWN ON *.* TO multi_admin\@localhost IDENTIFIED BY 'password' # -# You will need to apply the above to all MySQL servers that are being +# You will need to apply the above to all MariaDB servers that are being # controlled by $my_progname. 'multi_admin' will shutdown the servers # using 'mysqladmin' -binary, when '$my_progname stop' is being called. # # 2.PID-FILE # # If you are using mysqld_safe to start mysqld, make sure that every -# MySQL server has a separate pid-file. In order to use mysqld_safe +# MariaDB server has a separate pid-file. In order to use mysqld_safe # via $my_progname, you need to use two options: # # mysqld=/path/to/mysqld_safe @@ -667,7 +667,7 @@ sub example # # 3.DATA DIRECTORY # -# It is NOT advised to run many MySQL servers within the same data directory. +# It is NOT advised to run many MariaDB servers within the same data directory. # You can do so, but please make sure to understand and deal with the # underlying caveats. In short they are: # - Speed penalty @@ -688,7 +688,7 @@ sub example # intentionally left out. You may have 'gaps' in the config file. This # gives you more flexibility. # -# 6.MySQL Server User +# 6.MariaDB Server User # # You can pass the user=... option inside [mysqld#] groups. This # can be very handy in some cases, but then you need to run $my_progname @@ -696,7 +696,7 @@ sub example # # 7.A Start-up Manage Script for $my_progname # -# In the recent MySQL distributions you can find a file called +# In the recent MariaDB distributions you can find a file called # mysqld_multi.server.sh. It is a wrapper for $my_progname. This can # be used to start and stop multiple servers during boot and shutdown. # @@ -709,7 +709,7 @@ sub example # or /root/.my.cnf and add the [mysqld_multi] and [mysqld#] groups. # # The script can be found from support-files/mysqld_multi.server.sh -# in MySQL distribution. (Verify the script before using) +# in MariaDB distribution. (Verify the script before using) # [mysqld_multi] @@ -828,7 +828,7 @@ Using: @{[join ' ', @defaults_options]} file is turned on. --password=... Password for mysqladmin user. --silent Disable warnings. ---tcp-ip Connect to the MySQL server(s) via the TCP/IP port instead +--tcp-ip Connect to the MariaDB server(s) via the TCP/IP port instead of the UNIX socket. This affects stopping and reporting. If a socket file is missing, the server may still be running, but can be accessed only via the TCP/IP port. diff --git a/scripts/mytop.sh b/scripts/mytop.sh index 480805e90b1..fe7765988fb 100644 --- a/scripts/mytop.sh +++ b/scripts/mytop.sh @@ -6,7 +6,7 @@ =head1 NAME -mytop - display MySQL server performance info like `top' +mytop - display MariaDB server performance info like `top' =cut @@ -257,7 +257,7 @@ my $dbh = DBI->connect($dsn, $config{user}, $config{pass}, if (not ref $dbh) { my $Error = < and -I commands. +And you obviously need access to a MariaDB server with the necessary +security to run the I and I commands. If you are a Windows user, using ActiveState's Perl, you can use PPM -(the Perl Package Manager) to install the MySQL and Term::ReadKey +(the Perl Package Manager) to install the MariaDB/MySQL and Term::ReadKey modules. =head2 Optional Color Support @@ -1962,24 +1961,24 @@ B was inspired by the system monitoring tool B. I routinely use B on Linux, FreeBSD, and Solaris. You are likely to notice features from each of them here. -B will connect to a MySQL server and periodically run the +B will connect to a MariaDB server and periodically run the I and I commands and attempt to summarize the information from them in a useful format. =head2 The Display The B display screen is really broken into two parts. The top 4 -lines (header) contain summary information about your MySQL +lines (header) contain summary information about your MariaDB server. For example, you might see something like: -MySQL on localhost (4.0.13-log) up 1+11:13:00 [23:29:11] +MariaDB on localhost (10.0.13-log) up 1+11:13:00 [23:29:11] Queries: 19.3M qps: 160 Slow: 1.0 Se/In/Up/De(%): 00/80/03/17 qps now: 219 Slow qps: 0.0 Threads: 1 ( 1/ 16) 00/74/00/25 Key Efficiency: 99.3% Bps in/out: 30.5k/162.8 Now in/out: 32.7k/ 3.3k The first line identifies the hostname of the server (localhost) and -the version of MySQL it is running. The right had side shows the -uptime of the MySQL server process in days+hours:minutes:seconds +the version of MariaDB it is running. The right had side shows the +uptime of the MariaDB server process in days+hours:minutes:seconds format (much like FreeBSD's top) as well as the current time. The second line displays the total number of queries the server has @@ -1993,7 +1992,7 @@ on the previous line). And the fourth line displays key buffer efficiency (how often keys are read from the buffer rather than disk) and the number of bytes that -MySQL has sent and received, both over all and in the last cycle. +MariaDB has sent and received, both over all and in the last cycle. You can toggle the header by hitting B when running B. @@ -2039,21 +2038,21 @@ have two dashes `--'. Short arguments only have one '-'. =item B<-u> or B<-user> username -Username to use when logging in to the MySQL server. Default: ``root''. +Username to use when logging in to the MariaDB server. Default: ``root''. =item B<-p> or B<-pass> or B<-password> password -Password to use when logging in to the MySQL server. Default: none. +Password to use when logging in to the MariaDB server. Default: none. =item B<-h> or B<--host> hostname[:port] -Hostname of the MySQL server. The hostname may be followed by an +Hostname of the MariaDB server. The hostname may be followed by an option port number. Note that the port is specified separate from the host when using a config file. Default: ``localhost''. =item B<--port> or B<-P> port -If you're running MySQL on a non-standard port, use this to specify +If you're running MariaDB on a non-standard port, use this to specify the port number. Default: 3306. =item B<-s> or B<--delay> seconds @@ -2071,15 +2070,15 @@ In batch mode, mytop runs only once, does not clear the screen, and places no limit on the number of lines it will print. This is suitable for running periodically (perhaps from cron) to capture the information into a file for later viewing. You might use batch mode in -a CGI script to occasionally display your MySQL server status on the +a CGI script to occasionally display your MariaDB server status on the web. Default: unset. =item B<-S> or B<--socket> /path/to/socket -If you're running B on the same host as MySQL, you may wish to -have it use the MySQL socket directly rather than a standard TCP/IP +If you're running B on the same host as MariaDB, you may wish to +have it use the MariaDB socket directly rather than a standard TCP/IP connection. If you do,just specify one. Note that specifying a socket will make B ignore any host @@ -2125,7 +2124,7 @@ Default: noprompt. =item B<--resolve> -If you have skip-resolve set on MySQL (to keep it from doing a reverse +If you have skip-resolve set on MariaDB (to keep it from doing a reverse DNS lookup on each inbound connection), mytop can replace IP addresses with hostnames but toggling this option. From 7375f025ee9cd39909c1ec5529ca8c4007b92368 Mon Sep 17 00:00:00 2001 From: Monty Date: Sun, 3 Aug 2014 15:16:56 +0300 Subject: [PATCH 004/153] Changes for using build scripts Removed -DSECURITY_HARDENED=OFF for debug build scripts ignore configure --- .gitignore | 1 + cmake/configure.pl | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index e283abf39f9..3a3733470fc 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ Makefile TAGS Testing/ VERSION.dep +configure client/async_example client/mysql client/mysql_plugin diff --git a/cmake/configure.pl b/cmake/configure.pl index a71795a3bc8..b528cda70dc 100644 --- a/cmake/configure.pl +++ b/cmake/configure.pl @@ -167,7 +167,7 @@ foreach my $option (@ARGV) } if($option =~ /with-debug/) { - $cmakeargs = $cmakeargs." -DCMAKE_BUILD_TYPE=Debug"; + $cmakeargs = $cmakeargs." -DCMAKE_BUILD_TYPE=Debug -DSECURITY_HARDENED=OFF"; next; } if($option =~ /with-ssl/) From e2b2bde358f434d945e9730acfbc6eedeb9ab8a2 Mon Sep 17 00:00:00 2001 From: Monty Date: Sun, 3 Aug 2014 15:26:47 +0300 Subject: [PATCH 005/153] Made sql_log_slow a session variable mysqldump: - Added --log-queries to allow one to disable logging for the dump sql/log_event.cc: - Removed setting of enable_slow_log as it's not required anymore. sql/sql_parse.cc: - Set enable_slow_log to value of thd->variables.sql_log_slow as this will speed up tests if slow log is disabled. - opt_log_slow_admin_statements can now only disable slow log, not enable it. sql/sql_explain.cc: - Minor cleanup Other things: - Added sql_log_slow to system variables. - Changed opt_slow_log to global_system_variables.sql_log_slow in all files - Updated tests to reflect changes --- client/mysqldump.c | 10 ++++++-- mysql-test/r/log_state.result | 13 ++++++++++- mysql-test/r/mysqldump.result | 10 ++++++++ .../sys_vars/r/slow_query_log_basic.result | 18 ++++++++++----- .../sys_vars/r/slow_query_log_func.result | 14 +++++++++-- .../sys_vars/t/slow_query_log_basic.test | 17 +++++++------- .../suite/sys_vars/t/slow_query_log_func.test | 15 ++++++++++-- mysql-test/t/log_state.test | 8 +++++++ mysql-test/t/mysqldump.test | 15 ++++++++++++ sql/log.cc | 18 +++++++-------- sql/log_event.cc | 13 +---------- sql/mysqld.cc | 23 +++++++++++-------- sql/mysqld.h | 2 +- sql/rpl_parallel.cc | 2 +- sql/slave.cc | 2 +- sql/sql_class.h | 7 +++--- sql/sql_explain.cc | 2 ++ sql/sql_parse.cc | 11 ++++----- sql/sql_prepare.cc | 2 +- sql/sql_reload.cc | 2 +- sql/sys_vars.cc | 14 +++++++---- 21 files changed, 147 insertions(+), 71 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index cb4fa022d4f..db2813158b0 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -39,7 +39,7 @@ ** 10 Jun 2003: SET NAMES and --no-set-names by Alexander Barkov */ -#define DUMP_VERSION "10.15" +#define DUMP_VERSION "10.16" #include #include @@ -111,7 +111,7 @@ static my_bool verbose= 0, opt_no_create_info= 0, opt_no_data= 0, opt_slave_apply= 0, opt_include_master_host_port= 0, opt_events= 0, opt_comments_used= 0, - opt_alltspcs=0, opt_notspcs= 0; + opt_alltspcs=0, opt_notspcs= 0, opt_logging; static my_bool insert_pat_inited= 0, debug_info_flag= 0, debug_check_flag= 0; static ulong opt_max_allowed_packet, opt_net_buffer_length; static MYSQL mysql_connection,*mysql=0; @@ -381,6 +381,8 @@ static struct my_option my_long_options[] = {"log-error", OPT_ERROR_LOG_FILE, "Append warnings and errors to given file.", &log_error_file, &log_error_file, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"log-queries", 0, "When restoring the dump, the server will, if logging turned on, log the queries to the general and slow query log.", + &opt_logging, &opt_logging, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"master-data", OPT_MASTER_DATA, "This causes the binary log position and filename to be appended to the " "output. If equal to 1, will print it as a CHANGE MASTER command; if equal" @@ -663,6 +665,10 @@ static void write_header(FILE *sql_file, char *db_name) print_comment(sql_file, 0, "-- Server version\t%s\n", mysql_get_server_info(&mysql_connection)); + if (!opt_logging) + fprintf(sql_file, +"\n/*M!100101 SET LOCAL SQL_LOG_OFF=0, LOCAL SLOW_QUERY_LOG=0 */;"); + if (opt_set_charset) fprintf(sql_file, "\n/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;" diff --git a/mysql-test/r/log_state.result b/mysql-test/r/log_state.result index cc6f3709ae4..f157887de4b 100644 --- a/mysql-test/r/log_state.result +++ b/mysql-test/r/log_state.result @@ -42,6 +42,7 @@ select * from mysql.slow_log where sql_text NOT LIKE '%slow_log%'; start_time user_host query_time lock_time rows_sent rows_examined db last_insert_id insert_id server_id sql_text thread_id # Switch to connection default set global slow_query_log= ON; +set local slow_query_log= ON; # Switch to connection con1 set session long_query_time = @long_query_time; select sleep(@long_query_time + 1); @@ -49,7 +50,13 @@ sleep(@long_query_time + 1) 0 select * from mysql.slow_log where sql_text NOT LIKE '%slow_log%'; start_time user_host query_time lock_time rows_sent rows_examined db last_insert_id insert_id server_id sql_text thread_id -TIMESTAMP USER_HOST QUERY_TIME 00:00:00.000000 1 0 test 0 0 1 select sleep(@long_query_time + 1) THREAD_ID +set local slow_query_log= ON; +select sleep(@long_query_time + 2); +sleep(@long_query_time + 2) +0 +select * from mysql.slow_log where sql_text NOT LIKE '%slow_log%'; +start_time user_host query_time lock_time rows_sent rows_examined db last_insert_id insert_id server_id sql_text thread_id +TIMESTAMP USER_HOST QUERY_TIME 00:00:00.000000 1 0 test 0 0 1 select sleep(@long_query_time + 2) THREAD_ID # Switch to connection default show global variables where Variable_name = 'general_log' or Variable_name = 'slow_query_log'; @@ -62,6 +69,7 @@ set global general_log= OFF; set global slow_query_log= ON; set global slow_query_log= OFF; set global slow_query_log= OFF; +set local slow_query_log= ON; set global general_log= ON; truncate table mysql.general_log; create table t1(f1 int); @@ -124,6 +132,9 @@ Variable_name Value general_log OFF show variables like 'slow_query_log'; Variable_name Value +slow_query_log ON +show global variables like 'slow_query_log'; +Variable_name Value slow_query_log OFF set global general_log=ON; set global log_output=default; diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 4b0b3faf629..a7ef5d4d92f 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -5290,3 +5290,13 @@ Usage: mysqldump [OPTIONS] database [tables] OR mysqldump [OPTIONS] --databases [OPTIONS] DB1 [DB2 DB3...] OR mysqldump [OPTIONS] --all-databases [OPTIONS] For more options, use mysqldump --help +# +# Test mysqldump with --disable-query-logs +# +create table t1 (a int); +insert into t1 values (1); +drop table t1; +select * from t1; +a +1 +drop table t1; diff --git a/mysql-test/suite/sys_vars/r/slow_query_log_basic.result b/mysql-test/suite/sys_vars/r/slow_query_log_basic.result index bf9a83f0380..049404f5648 100644 --- a/mysql-test/suite/sys_vars/r/slow_query_log_basic.result +++ b/mysql-test/suite/sys_vars/r/slow_query_log_basic.result @@ -42,10 +42,17 @@ ERROR 42000: Variable 'slow_query_log' can't be set to the value of ' ' SET @@global.slow_query_log = ''; ERROR 42000: Variable 'slow_query_log' can't be set to the value of '' '#-------------------FN_DYNVARS_004_04----------------------------#' -SET @@session.slow_query_log = OFF; -ERROR HY000: Variable 'slow_query_log' is a GLOBAL variable and should be set with SET GLOBAL +SET @@global.slow_query_log = ON; +SET @@session.slow_query_log = ON; SELECT @@session.slow_query_log; -ERROR HY000: Variable 'slow_query_log' is a GLOBAL variable +@@session.slow_query_log +1 +SET @@session.slow_query_log = OFF; +SELECT @@session.slow_query_log; +@@session.slow_query_log +0 +SET @@global.slow_query_log = OFF; +SET @@session.slow_query_log = ON; '#----------------------FN_DYNVARS_004_05------------------------#' SELECT IF(@@global.slow_query_log, "ON", "OFF") = VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES @@ -72,12 +79,11 @@ SELECT @@global.slow_query_log; 0 '#---------------------FN_DYNVARS_004_08----------------------#' SET @@global.slow_query_log = ON; +SET @@local.slow_query_log = OFF; SELECT @@slow_query_log = @@global.slow_query_log; @@slow_query_log = @@global.slow_query_log -1 +0 '#---------------------FN_DYNVARS_004_09----------------------#' -SET slow_query_log = ON; -ERROR HY000: Variable 'slow_query_log' is a GLOBAL variable and should be set with SET GLOBAL SET local.slow_query_log = OFF; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'slow_query_log = OFF' at line 1 SELECT local.slow_query_log; diff --git a/mysql-test/suite/sys_vars/r/slow_query_log_func.result b/mysql-test/suite/sys_vars/r/slow_query_log_func.result index f01b2c4c48b..b431f963239 100644 --- a/mysql-test/suite/sys_vars/r/slow_query_log_func.result +++ b/mysql-test/suite/sys_vars/r/slow_query_log_func.result @@ -2,7 +2,7 @@ SET @global_slow_query_log = @@global.slow_query_log; SET @global_log_output = @@global.log_output; SET @@session.long_query_time=1; SET @@global.log_output = 'TABLE'; -'----When slow_query_log = OFF----' +'----When global.slow_query_log = OFF----' SET @@global.slow_query_log = OFF; TRUNCATE mysql.slow_log; SELECT sleep(2); @@ -11,7 +11,7 @@ sleep(2) SELECT count(*) FROM mysql.slow_log; count(*) 0 -'----When slow_query_log = ON-----' +'----When global.slow_query_log = ON-----' SET @@global.slow_query_log = ON; TRUNCATE mysql.slow_log; SELECT sleep(2); @@ -20,6 +20,16 @@ sleep(2) SELECT count(*) > 0 FROM mysql.slow_log; count(*) > 0 1 +'----When local.slow_query_log = OFF-----' +SET @@local.slow_query_log = OFF; +TRUNCATE mysql.slow_log; +SELECT sleep(2); +sleep(2) +0 +SELECT count(*) FROM mysql.slow_log; +count(*) +0 +SET @@local.slow_query_log = ON; 'Bug#47905 stored procedures not logged correctly to slow query log' TRUNCATE mysql.slow_log; CREATE PROCEDURE p_test() diff --git a/mysql-test/suite/sys_vars/t/slow_query_log_basic.test b/mysql-test/suite/sys_vars/t/slow_query_log_basic.test index fef37b5ff4a..b429f9f5cea 100644 --- a/mysql-test/suite/sys_vars/t/slow_query_log_basic.test +++ b/mysql-test/suite/sys_vars/t/slow_query_log_basic.test @@ -90,14 +90,16 @@ SET @@global.slow_query_log = ''; --echo '#-------------------FN_DYNVARS_004_04----------------------------#' ################################################################## -# Test if accessing session slow_query_log gives error # +# Test that accessing session slow_query_log dows not give # ################################################################## ---Error ER_GLOBAL_VARIABLE -SET @@session.slow_query_log = OFF; ---Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@global.slow_query_log = ON; +SET @@session.slow_query_log = ON; SELECT @@session.slow_query_log; - +SET @@session.slow_query_log = OFF; +SELECT @@session.slow_query_log; +SET @@global.slow_query_log = OFF; +SET @@session.slow_query_log = ON; --echo '#----------------------FN_DYNVARS_004_05------------------------#' ############################################################################## @@ -132,18 +134,17 @@ SELECT @@global.slow_query_log; --echo '#---------------------FN_DYNVARS_004_08----------------------#' ############################################################################## # Check if accessing variable with SESSION,LOCAL and without SCOPE points # -# to same session variable # +# to same session variable (doesn't) # ############################################################################## SET @@global.slow_query_log = ON; +SET @@local.slow_query_log = OFF; SELECT @@slow_query_log = @@global.slow_query_log; --echo '#---------------------FN_DYNVARS_004_09----------------------#' ###################################################################### # Check if slow_query_log can be accessed with and without @@ sign # ###################################################################### ---Error ER_GLOBAL_VARIABLE -SET slow_query_log = ON; --Error ER_PARSE_ERROR SET local.slow_query_log = OFF; --Error ER_UNKNOWN_TABLE diff --git a/mysql-test/suite/sys_vars/t/slow_query_log_func.test b/mysql-test/suite/sys_vars/t/slow_query_log_func.test index dd202ec20ff..2f1d7449976 100644 --- a/mysql-test/suite/sys_vars/t/slow_query_log_func.test +++ b/mysql-test/suite/sys_vars/t/slow_query_log_func.test @@ -10,7 +10,7 @@ SET @@session.long_query_time=1; SET @@global.log_output = 'TABLE'; #========================================= ---echo '----When slow_query_log = OFF----' +--echo '----When global.slow_query_log = OFF----' #========================================= SET @@global.slow_query_log = OFF; @@ -21,7 +21,7 @@ SELECT sleep(2); SELECT count(*) FROM mysql.slow_log; #========================================= ---echo '----When slow_query_log = ON-----' +--echo '----When global.slow_query_log = ON-----' #========================================= SET @@global.slow_query_log = ON; @@ -31,6 +31,17 @@ SELECT sleep(2); SELECT count(*) > 0 FROM mysql.slow_log; +#========================================= +--echo '----When local.slow_query_log = OFF-----' +#========================================= + +SET @@local.slow_query_log = OFF; +TRUNCATE mysql.slow_log; +# The sleep is the slow query +SELECT sleep(2); + +SELECT count(*) FROM mysql.slow_log; +SET @@local.slow_query_log = ON; #========================================================================== --echo 'Bug#47905 stored procedures not logged correctly to slow query log' diff --git a/mysql-test/t/log_state.test b/mysql-test/t/log_state.test index 3231769a4bf..12c7a7fd92b 100644 --- a/mysql-test/t/log_state.test +++ b/mysql-test/t/log_state.test @@ -52,12 +52,18 @@ select * from mysql.slow_log where sql_text NOT LIKE '%slow_log%'; connection default; set global slow_query_log= ON; +set local slow_query_log= ON; --echo # Switch to connection con1 connection con1; set session long_query_time = @long_query_time; select sleep(@long_query_time + 1); --replace_column 1 TIMESTAMP 2 USER_HOST 3 QUERY_TIME 12 THREAD_ID select * from mysql.slow_log where sql_text NOT LIKE '%slow_log%'; +set local slow_query_log= ON; +select sleep(@long_query_time + 2); +--replace_column 1 TIMESTAMP 2 USER_HOST 3 QUERY_TIME 12 THREAD_ID +select * from mysql.slow_log where sql_text NOT LIKE '%slow_log%'; + --echo # Switch to connection default connection default; show global variables @@ -69,6 +75,7 @@ set global general_log= OFF; set global slow_query_log= ON; set global slow_query_log= OFF; set global slow_query_log= OFF; +set local slow_query_log= ON; set global general_log= ON; truncate table mysql.general_log; @@ -127,6 +134,7 @@ set global general_log_file= default; set global slow_query_log_file= default; show variables like 'general_log'; show variables like 'slow_query_log'; +show global variables like 'slow_query_log'; set global general_log=ON; set global log_output=default; show variables like 'log_output'; diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 9d6789541c0..8461ebff412 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -2473,3 +2473,18 @@ drop table t1, t2; --exec $MYSQL_DUMP --user=foo 2>&1 > $MYSQLTEST_VARDIR/tmp/bug6056.out --exec $MYSQL_DUMP --help > $MYSQLTEST_VARDIR/tmp/bug6056.out +--echo # +--echo # Test mysqldump with --disable-query-logs +--echo # + +create table t1 (a int); +insert into t1 values (1); + +--exec $MYSQL_DUMP --hex-blob --character-sets-dir=$MYSQL_SHAREDIR/charsets --tab=$MYSQLTEST_VARDIR/tmp/ test t1 +--exec $MYSQL_DUMP --disable-log-queries --skip-comments test t1 >$MYSQLTEST_VARDIR/tmp/mysqldump-test.out +drop table t1; + +--exec $MYSQL test < $MYSQLTEST_VARDIR/tmp/mysqldump-test.out +select * from t1; +drop table t1; +--remove_file $MYSQLTEST_VARDIR/tmp/mysqldump-test.out diff --git a/sql/log.cc b/sql/log.cc index 75a895e25f8..d2032b0f4ab 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -517,7 +517,7 @@ bool LOGGER::is_log_table_enabled(uint log_table_type) { switch (log_table_type) { case QUERY_LOG_SLOW: - return (table_log_handler != NULL) && opt_slow_log; + return (table_log_handler != NULL) && global_system_variables.sql_log_slow; case QUERY_LOG_GENERAL: return (table_log_handler != NULL) && opt_log ; default: @@ -1048,7 +1048,7 @@ bool Log_to_file_event_handler::init() { if (!is_initialized) { - if (opt_slow_log) + if (global_system_variables.sql_log_slow) mysql_slow_log.open_slow_log(opt_slow_logname); if (opt_log) @@ -1072,7 +1072,7 @@ void Log_to_file_event_handler::flush() /* reopen log files */ if (opt_log) mysql_log.reopen_file(); - if (opt_slow_log) + if (global_system_variables.sql_log_slow) mysql_slow_log.reopen_file(); } @@ -1200,7 +1200,7 @@ bool LOGGER::flush_slow_log() logger.lock_exclusive(); /* Reopen slow log file */ - if (opt_slow_log) + if (global_system_variables.sql_log_slow) file_log_handler->get_mysql_slow_log()->reopen_file(); /* End of log flush */ @@ -1270,11 +1270,11 @@ bool LOGGER::slow_log_print(THD *thd, const char *query, uint query_length, if (*slow_log_handler_list) { /* do not log slow queries from replication threads */ - if (thd->slave_thread && !opt_log_slow_slave_statements) + if (!thd->variables.sql_log_slow) return 0; lock_shared(); - if (!opt_slow_log) + if (!global_system_variables.sql_log_slow) { unlock(); return 0; @@ -1448,7 +1448,7 @@ bool LOGGER::activate_log_handler(THD* thd, uint log_type) lock_exclusive(); switch (log_type) { case QUERY_LOG_SLOW: - if (!opt_slow_log) + if (!global_system_variables.sql_log_slow) { file_log= file_log_handler->get_mysql_slow_log(); @@ -1462,7 +1462,7 @@ bool LOGGER::activate_log_handler(THD* thd, uint log_type) else { init_slow_log(log_output_options); - opt_slow_log= TRUE; + global_system_variables.sql_log_slow= TRUE; } } break; @@ -1501,7 +1501,7 @@ void LOGGER::deactivate_log_handler(THD *thd, uint log_type) switch (log_type) { case QUERY_LOG_SLOW: - tmp_opt= &opt_slow_log; + tmp_opt= &global_system_variables.sql_log_slow; file_log= file_log_handler->get_mysql_slow_log(); break; case QUERY_LOG_GENERAL: diff --git a/sql/log_event.cc b/sql/log_event.cc index 6a85893803e..27dddb69144 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -4280,6 +4280,7 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi, THD_STAGE_INFO(thd, stage_init); MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, thd->query(), thd->query_length()); + thd->enable_slow_log= thd->variables.sql_log_slow; mysql_parse(thd, thd->query(), thd->query_length(), &parser_state); /* Finalize server status flags after executing a statement. */ thd->update_server_status(); @@ -4287,18 +4288,6 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi, } thd->variables.option_bits&= ~OPTION_MASTER_SQL_ERROR; - - /* - Resetting the enable_slow_log thd variable. - - We need to reset it back to the opt_log_slow_slave_statements - value after the statement execution (and slow logging - is done). It might have changed if the statement was an - admin statement (in which case, down in mysql_parse execution - thd->enable_slow_log is set to the value of - opt_log_slow_admin_statements). - */ - thd->enable_slow_log= opt_log_slow_slave_statements; } else { diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 066dae224eb..e420a70b33f 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -373,7 +373,7 @@ static DYNAMIC_ARRAY all_options; /* Global variables */ bool opt_bin_log, opt_bin_log_used=0, opt_ignore_builtin_innodb= 0; -my_bool opt_log, opt_slow_log, debug_assert_if_crashed_table= 0, opt_help= 0; +my_bool opt_log, debug_assert_if_crashed_table= 0, opt_help= 0; static my_bool opt_abort; ulonglong log_output_options; my_bool opt_userstat_running; @@ -3329,7 +3329,7 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused))) sql_print_information("Got signal %d to shutdown mysqld",sig); #endif /* switch to the old log message processing */ - logger.set_handlers(LOG_FILE, opt_slow_log ? LOG_FILE:LOG_NONE, + logger.set_handlers(LOG_FILE, global_system_variables.sql_log_slow ? LOG_FILE:LOG_NONE, opt_log ? LOG_FILE:LOG_NONE); DBUG_PRINT("info",("Got signal: %d abort_loop: %d",sig,abort_loop)); if (!abort_loop) @@ -3367,13 +3367,15 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused))) if (log_output_options & LOG_NONE) { logger.set_handlers(LOG_FILE, - opt_slow_log ? LOG_TABLE : LOG_NONE, + global_system_variables.sql_log_slow ? + LOG_TABLE : LOG_NONE, opt_log ? LOG_TABLE : LOG_NONE); } else { logger.set_handlers(LOG_FILE, - opt_slow_log ? log_output_options : LOG_NONE, + global_system_variables.sql_log_slow ? + log_output_options : LOG_NONE, opt_log ? log_output_options : LOG_NONE); } break; @@ -4263,7 +4265,8 @@ static int init_common_variables() "--log option, log tables are used. " "To enable logging to files use the --log-output option."); - if (opt_slow_log && opt_slow_logname && *opt_slow_logname && + if (global_system_variables.sql_log_slow && opt_slow_logname && + *opt_slow_logname && !(log_output_options & (LOG_FILE | LOG_NONE))) sql_print_warning("Although a path was specified for the " "--log-slow-queries option, log tables are used. " @@ -4904,7 +4907,9 @@ a file name for --log-bin-index option", opt_binlog_index_name); /* purecov: end */ } - logger.set_handlers(LOG_FILE, opt_slow_log ? log_output_options:LOG_NONE, + logger.set_handlers(LOG_FILE, + global_system_variables.sql_log_slow ? + log_output_options:LOG_NONE, opt_log ? log_output_options:LOG_NONE); } @@ -8123,7 +8128,7 @@ static int mysql_init_variables(void) /* We can only test for sub paths if my_symlink.c is using realpath */ myisam_test_invalid_symlink= test_if_data_home_dir; #endif - opt_log= opt_slow_log= 0; + opt_log= 0; opt_bin_log= opt_bin_log_used= 0; opt_disable_networking= opt_skip_show_db=0; opt_skip_name_resolve= 0; @@ -8818,7 +8823,7 @@ static int get_options(int *argc_ptr, char ***argv_ptr) if ((opt_log_slow_admin_statements || opt_log_queries_not_using_indexes || opt_log_slow_slave_statements) && - !opt_slow_log) + !global_system_variables.sql_log_slow) sql_print_warning("options --log-slow-admin-statements, --log-queries-not-using-indexes and --log-slow-slave-statements have no effect if --log_slow_queries is not set"); if (global_system_variables.net_buffer_length > global_system_variables.max_allowed_packet) @@ -9033,7 +9038,7 @@ void set_server_version(void) if (!strstr(MYSQL_SERVER_SUFFIX_STR, "-debug")) end= strmov(end, "-debug"); #endif - if (opt_log || opt_slow_log || opt_bin_log) + if (opt_log || global_system_variables.sql_log_slow || opt_bin_log) strmov(end, "-log"); // This may slow down system } diff --git a/sql/mysqld.h b/sql/mysqld.h index a1656a49047..21c020b8b5e 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -80,7 +80,7 @@ extern CHARSET_INFO *character_set_filesystem; extern MY_BITMAP temp_pool; extern bool opt_large_files, server_id_supplied; extern bool opt_update_log, opt_bin_log, opt_error_log; -extern my_bool opt_log, opt_slow_log, opt_bootstrap; +extern my_bool opt_log, opt_bootstrap; extern my_bool opt_backup_history_log; extern my_bool opt_backup_progress_log; extern ulonglong log_output_options; diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index e72d3470a7f..90ee2360eb7 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -235,7 +235,7 @@ handle_rpl_parallel_thread(void *arg) thd->security_ctx->skip_grants(); thd->variables.max_allowed_packet= slave_max_allowed_packet; thd->slave_thread= 1; - thd->enable_slow_log= opt_log_slow_slave_statements; + thd->variables.sql_log_slow= opt_log_slow_slave_statements; thd->variables.log_slow_filter= global_system_variables.log_slow_filter; set_slave_thread_options(thd); thd->client_capabilities = CLIENT_LOCAL_FILES; diff --git a/sql/slave.cc b/sql/slave.cc index f7d019a6c39..bb90d24b0bb 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2922,7 +2922,7 @@ static int init_slave_thread(THD* thd, Master_info *mi, thd->security_ctx->skip_grants(); thd->slave_thread= 1; thd->connection_name= mi->connection_name; - thd->enable_slow_log= opt_log_slow_slave_statements; + thd->variables.sql_log_slow= opt_log_slow_slave_statements; thd->variables.log_slow_filter= global_system_variables.log_slow_filter; set_slave_thread_options(thd); thd->client_capabilities = CLIENT_LOCAL_FILES; diff --git a/sql/sql_class.h b/sql/sql_class.h index f3537086132..f96110e0b0f 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -567,9 +567,6 @@ typedef struct system_variables ulong log_slow_rate_limit; ulong binlog_format; ///< binlog format for this thd (see enum_binlog_format) ulong progress_report_time; - my_bool binlog_annotate_row_events; - my_bool binlog_direct_non_trans_update; - my_bool sql_log_bin; ulong completion_type; ulong query_cache_type; ulong tx_isolation; @@ -608,6 +605,10 @@ typedef struct system_variables my_bool old_passwords; my_bool big_tables; my_bool query_cache_strip_comments; + my_bool sql_log_slow; + my_bool sql_log_bin; + my_bool binlog_annotate_row_events; + my_bool binlog_direct_non_trans_update; plugin_ref table_plugin; plugin_ref tmp_table_plugin; diff --git a/sql/sql_explain.cc b/sql/sql_explain.cc index 9df4fd965a5..53ac095d1d0 100644 --- a/sql/sql_explain.cc +++ b/sql/sql_explain.cc @@ -1006,8 +1006,10 @@ int Explain_insert::print_explain(Explain_query *query, void delete_explain_query(LEX *lex) { + DBUG_ENTER("delete_explain_query"); delete lex->explain; lex->explain= NULL; + DBUG_VOID_RETURN; } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 019fd55e3d8..1da595858b3 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1131,7 +1131,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, Commands which always take a long time are logged into the slow log only if opt_log_slow_admin_statements is set. */ - thd->enable_slow_log= TRUE; + thd->enable_slow_log= thd->variables.sql_log_slow; thd->query_plan_flags= QPLAN_INIT; thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */ @@ -1516,7 +1516,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, status_var_increment(thd->status_var.com_other); - thd->enable_slow_log= opt_log_slow_admin_statements; + thd->enable_slow_log&= opt_log_slow_admin_statements; thd->query_plan_flags|= QPLAN_ADMIN; if (check_global_access(thd, REPL_SLAVE_ACL)) break; @@ -1784,7 +1784,6 @@ void log_slow_statement(THD *thd) { DBUG_ENTER("log_slow_statement"); - /* The following should never be true with our current code base, but better to keep this here so we don't accidently try to log a @@ -1795,12 +1794,10 @@ void log_slow_statement(THD *thd) /* Follow the slow log filter configuration. */ - if (!thd->enable_slow_log || + if (!thd->enable_slow_log || !global_system_variables.sql_log_slow || (thd->variables.log_slow_filter && !(thd->variables.log_slow_filter & thd->query_plan_flags))) - { goto end; - } if (((thd->server_status & SERVER_QUERY_WAS_SLOW) || ((thd->server_status & @@ -3060,7 +3057,7 @@ end_with_restore_list: and thus classify as slow administrative statements just like ALTER TABLE. */ - thd->enable_slow_log= opt_log_slow_admin_statements; + thd->enable_slow_log&= opt_log_slow_admin_statements; thd->query_plan_flags|= QPLAN_ADMIN; bzero((char*) &create_info, sizeof(create_info)); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index ebceae70ee5..9ea496a81dc 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -3205,7 +3205,7 @@ void Prepared_statement::setup_set_params() because we want to look it up in the query cache) or not. */ if ((mysql_bin_log.is_open() && is_update_query(lex->sql_command)) || - opt_log || opt_slow_log || + opt_log || thd->variables.sql_log_slow || query_cache_is_cacheable_query(lex)) { set_params_from_vars= insert_params_from_vars_with_log; diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc index bb3d5bb899a..10ff6dee31f 100644 --- a/sql/sql_reload.cc +++ b/sql/sql_reload.cc @@ -130,7 +130,7 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options, result= 1; } - if ((options & REFRESH_SLOW_LOG) && opt_slow_log) + if ((options & REFRESH_SLOW_LOG) && global_system_variables.sql_log_slow) logger.flush_slow_log(); if ((options & REFRESH_GENERAL_LOG) && opt_log) diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 9495d16247d..7f7c725afc7 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -3841,7 +3841,7 @@ static void reopen_slow_log(char* name) static bool fix_slow_log_file(sys_var *self, THD *thd, enum_var_type type) { return fix_log(&opt_slow_logname, opt_log_basename, "-slow.log", - opt_slow_log, reopen_slow_log); + global_system_variables.sql_log_slow, reopen_slow_log); } static Sys_var_charptr Sys_slow_log_path( "slow_query_log_file", "Log slow queries to given log file. " @@ -3892,6 +3892,7 @@ static Sys_var_have Sys_have_symlink( READ_ONLY GLOBAL_VAR(have_symlink), NO_CMD_LINE); static bool fix_log_state(sys_var *self, THD *thd, enum_var_type type); + static Sys_var_mybool Sys_general_log( "general_log", "Log connections and queries to a table or log file. " "Defaults logging to a file 'hostname'.log or a table mysql.general_log" @@ -3905,9 +3906,9 @@ static Sys_var_mybool Sys_slow_query_log( "Log slow queries to a table or log file. Defaults logging to a file " "'hostname'-slow.log or a table mysql.slow_log if --log-output=TABLE is " "used. Must be enabled to activate other slow log options", - GLOBAL_VAR(opt_slow_log), CMD_LINE(OPT_ARG), - DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), - ON_UPDATE(fix_log_state)); + SESSION_VAR(sql_log_slow), CMD_LINE(OPT_ARG), + DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG, + ON_CHECK(0), ON_UPDATE(fix_log_state)); static bool fix_log_state(sys_var *self, THD *thd, enum_var_type type) { @@ -3915,6 +3916,9 @@ static bool fix_log_state(sys_var *self, THD *thd, enum_var_type type) my_bool *UNINIT_VAR(newvalptr), newval, UNINIT_VAR(oldval); uint UNINIT_VAR(log_type); + if (type != OPT_GLOBAL) + return 0; + if (self == &Sys_general_log) { newvalptr= &opt_log; @@ -3923,7 +3927,7 @@ static bool fix_log_state(sys_var *self, THD *thd, enum_var_type type) } else if (self == &Sys_slow_query_log) { - newvalptr= &opt_slow_log; + newvalptr= &global_system_variables.sql_log_slow; oldval= logger.get_slow_log_file_handler()->is_open(); log_type= QUERY_LOG_SLOW; } From 2062c9a65acc660c03ab07b1358f6bf8aab4488f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 13 Aug 2014 09:03:28 +0300 Subject: [PATCH 006/153] MDEV-6567: Raw debug output in the error log. Removed raw debug output when no error on OS operation has not happened. --- storage/innobase/os/os0file.cc | 9 ++++++--- storage/xtradb/os/os0file.cc | 7 +++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index 45ca07bc7c4..c70a3206910 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -802,6 +802,12 @@ os_file_handle_error_cond_exit( is better to ignore on_error_silent and print an error message to the log. */ + if (should_exit || !on_error_silent) { + fprintf(stderr, + " InnoDB: Operation %s to file %s and at line %ld\n", + operation, file, line); + } + if (should_exit || !on_error_silent) { ib_logf(IB_LOG_LEVEL_ERROR, "File %s: '%s' returned OS " "error " ULINTPF ".%s", name ? name : "(unknown)", @@ -809,9 +815,6 @@ os_file_handle_error_cond_exit( ? " Cannot continue operation" : ""); } - fprintf(stderr, - " InnoDB: at file %s and at line %ld\n", file, line); - if (should_exit) { exit(1); } diff --git a/storage/xtradb/os/os0file.cc b/storage/xtradb/os/os0file.cc index 394c3199f76..f29e5e07385 100644 --- a/storage/xtradb/os/os0file.cc +++ b/storage/xtradb/os/os0file.cc @@ -871,8 +871,11 @@ os_file_handle_error_cond_exit( is better to ignore on_error_silent and print an error message to the log. */ - fprintf(stderr, - " InnoDB: at file %s and at line %ld\n", file, line); + if (should_exit || !on_error_silent) { + fprintf(stderr, + " InnoDB: Operation %s to file %s and at line %ld\n", + operation, file, line); + } if (should_exit || !on_error_silent) { ib_logf(IB_LOG_LEVEL_ERROR, "File %s: '%s' returned OS " From 6b47e896c03bc8c2568b767ac4bbe917ac9f414c Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Wed, 13 Aug 2014 15:24:32 +0300 Subject: [PATCH 007/153] Basic test of slave_run_triggers_for_rbr variable added. --- .../r/slave_run_triggers_for_rbr_basic.result | 45 +++++++++++++++++++ .../t/slave_run_triggers_for_rbr_basic.test | 30 +++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 mysql-test/suite/sys_vars/r/slave_run_triggers_for_rbr_basic.result create mode 100644 mysql-test/suite/sys_vars/t/slave_run_triggers_for_rbr_basic.test diff --git a/mysql-test/suite/sys_vars/r/slave_run_triggers_for_rbr_basic.result b/mysql-test/suite/sys_vars/r/slave_run_triggers_for_rbr_basic.result new file mode 100644 index 00000000000..02a3cdf27ce --- /dev/null +++ b/mysql-test/suite/sys_vars/r/slave_run_triggers_for_rbr_basic.result @@ -0,0 +1,45 @@ +SET @old_slave_run_triggers_for_rbr= @@global.slave_run_triggers_for_rbr; +SET @@global.slave_run_triggers_for_rbr= NO; +select @@global.slave_run_triggers_for_rbr; +@@global.slave_run_triggers_for_rbr +NO +SET @@global.slave_run_triggers_for_rbr= YES; +select @@global.slave_run_triggers_for_rbr; +@@global.slave_run_triggers_for_rbr +YES +SET @@global.slave_run_triggers_for_rbr= LOGGING; +select @@global.slave_run_triggers_for_rbr; +@@global.slave_run_triggers_for_rbr +LOGGING +SET @@global.slave_run_triggers_for_rbr= default; +select @@global.slave_run_triggers_for_rbr; +@@global.slave_run_triggers_for_rbr +NO +SET @@global.slave_run_triggers_for_rbr= 0; +select @@global.slave_run_triggers_for_rbr; +@@global.slave_run_triggers_for_rbr +NO +SET @@global.slave_run_triggers_for_rbr= 1; +select @@global.slave_run_triggers_for_rbr; +@@global.slave_run_triggers_for_rbr +YES +SET @@global.slave_run_triggers_for_rbr= 2; +select @@global.slave_run_triggers_for_rbr; +@@global.slave_run_triggers_for_rbr +LOGGING +SET @@global.slave_run_triggers_for_rbr= 3; +ERROR 42000: Variable 'slave_run_triggers_for_rbr' can't be set to the value of '3' +select @@global.slave_run_triggers_for_rbr; +@@global.slave_run_triggers_for_rbr +LOGGING +SET @@global.slave_run_triggers_for_rbr= "N"; +ERROR 42000: Variable 'slave_run_triggers_for_rbr' can't be set to the value of 'N' +select @@global.slave_run_triggers_for_rbr; +@@global.slave_run_triggers_for_rbr +LOGGING +SET @@global.slave_run_triggers_for_rbr= -1; +ERROR 42000: Variable 'slave_run_triggers_for_rbr' can't be set to the value of '-1' +select @@global.slave_run_triggers_for_rbr; +@@global.slave_run_triggers_for_rbr +LOGGING +SET @@global.slave_run_triggers_for_rbr= @old_slave_run_triggers_for_rbr; diff --git a/mysql-test/suite/sys_vars/t/slave_run_triggers_for_rbr_basic.test b/mysql-test/suite/sys_vars/t/slave_run_triggers_for_rbr_basic.test new file mode 100644 index 00000000000..ac5296677b9 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/slave_run_triggers_for_rbr_basic.test @@ -0,0 +1,30 @@ + +-- source include/have_rbr_triggers.inc + +SET @old_slave_run_triggers_for_rbr= @@global.slave_run_triggers_for_rbr; +SET @@global.slave_run_triggers_for_rbr= NO; +select @@global.slave_run_triggers_for_rbr; +SET @@global.slave_run_triggers_for_rbr= YES; +select @@global.slave_run_triggers_for_rbr; +SET @@global.slave_run_triggers_for_rbr= LOGGING; +select @@global.slave_run_triggers_for_rbr; +SET @@global.slave_run_triggers_for_rbr= default; +select @@global.slave_run_triggers_for_rbr; +SET @@global.slave_run_triggers_for_rbr= 0; +select @@global.slave_run_triggers_for_rbr; +SET @@global.slave_run_triggers_for_rbr= 1; +select @@global.slave_run_triggers_for_rbr; +SET @@global.slave_run_triggers_for_rbr= 2; +select @@global.slave_run_triggers_for_rbr; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.slave_run_triggers_for_rbr= 3; +select @@global.slave_run_triggers_for_rbr; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.slave_run_triggers_for_rbr= "N"; +select @@global.slave_run_triggers_for_rbr; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.slave_run_triggers_for_rbr= -1; +select @@global.slave_run_triggers_for_rbr; + + +SET @@global.slave_run_triggers_for_rbr= @old_slave_run_triggers_for_rbr; From 8d3a432f12e5fdfbde3368dc5a859ecc3e42621f Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Wed, 13 Aug 2014 18:06:53 +0400 Subject: [PATCH 008/153] MDEV-6575: main.view --ps-protocol fails in ANALYZE code - After PREPARE is done, save the value of thd->select_number (this is what will be assigned to next select_lex object) - Restore the value at each execution of the prepared statement. --- sql/sql_prepare.cc | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 9ea496a81dc..6b5a3396abe 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -160,6 +160,20 @@ public: uint param_count; uint last_errno; uint flags; + /* + The value of thd->select_number at the end of the PREPARE phase. + + The issue is: each statement execution opens VIEWs, which may cause + select_lex objects to be created, and select_number values to be assigned. + + On the other hand, PREPARE assigns select_number values for triggers and + subqueries. + + In order for select_number values from EXECUTE not to conflict with + select_number values from PREPARE, we keep the number and set it at each + execution. + */ + uint select_number_after_prepare; char last_error[MYSQL_ERRMSG_SIZE]; #ifndef EMBEDDED_LIBRARY bool (*set_params)(Prepared_statement *st, uchar *data, uchar *data_end, @@ -3455,6 +3469,8 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) trans_rollback_implicit(thd); thd->mdl_context.release_transactional_locks(); } + + select_number_after_prepare= thd->select_number; lex_end(lex); cleanup_stmt(); @@ -3581,7 +3597,8 @@ Prepared_statement::execute_loop(String *expanded_query, Reprepare_observer reprepare_observer; bool error; int reprepare_attempt= 0; - + + thd->select_number= select_number_after_prepare; /* Check if we got an error when sending long data */ if (state == Query_arena::STMT_ERROR) { From 8984bef2e431db42761d3f267b950293cfd864de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Mon, 18 Aug 2014 10:52:59 +0300 Subject: [PATCH 009/153] MDEV-6172: Monitor progress of ALTER TABLE ... ADD INDEX, ALGORITHM=INPLACE for InnoDB Added thd_progress calls to row_merge_sort to give some hint how merge sort progresses. --- storage/innobase/row/row0merge.cc | 13 +++++++++++++ storage/xtradb/row/row0merge.cc | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index ab97b5a9f28..d9e0dc709be 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -2100,6 +2100,7 @@ row_merge( /* Copy the last blocks, if there are any. */ while (foffs0 < ihalf) { + if (UNIV_UNLIKELY(trx_is_interrupted(trx))) { return(DB_INTERRUPTED); } @@ -2116,6 +2117,7 @@ row_merge( ut_ad(foffs0 == ihalf); while (foffs1 < file->offset) { + if (trx_is_interrupted(trx)) { return(DB_INTERRUPTED); } @@ -2175,6 +2177,7 @@ row_merge_sort( { const ulint half = file->offset / 2; ulint num_runs; + ulint cur_run = 0; ulint* run_offset; dberr_t error = DB_SUCCESS; DBUG_ENTER("row_merge_sort"); @@ -2198,8 +2201,16 @@ row_merge_sort( of file marker). Thus, it must be at least one block. */ ut_ad(file->offset > 0); + thd_progress_init(trx->mysql_thd, num_runs); + /* Merge the runs until we have one big run */ do { + cur_run++; + + /* Report progress of merge sort to MySQL for + show processlist progress field */ + thd_progress_report(trx->mysql_thd, cur_run, num_runs); + error = row_merge(trx, dup, file, block, tmpfd, &num_runs, run_offset); @@ -2212,6 +2223,8 @@ row_merge_sort( mem_free(run_offset); + thd_progress_end(trx->mysql_thd); + DBUG_RETURN(error); } diff --git a/storage/xtradb/row/row0merge.cc b/storage/xtradb/row/row0merge.cc index 0b2e966efe0..4428de30473 100644 --- a/storage/xtradb/row/row0merge.cc +++ b/storage/xtradb/row/row0merge.cc @@ -2106,6 +2106,7 @@ row_merge( /* Copy the last blocks, if there are any. */ while (foffs0 < ihalf) { + if (UNIV_UNLIKELY(trx_is_interrupted(trx))) { return(DB_INTERRUPTED); } @@ -2122,6 +2123,7 @@ row_merge( ut_ad(foffs0 == ihalf); while (foffs1 < file->offset) { + if (trx_is_interrupted(trx)) { return(DB_INTERRUPTED); } @@ -2181,6 +2183,7 @@ row_merge_sort( { const ulint half = file->offset / 2; ulint num_runs; + ulint cur_run = 0; ulint* run_offset; dberr_t error = DB_SUCCESS; DBUG_ENTER("row_merge_sort"); @@ -2204,8 +2207,16 @@ row_merge_sort( of file marker). Thus, it must be at least one block. */ ut_ad(file->offset > 0); + thd_progress_init(trx->mysql_thd, num_runs); + /* Merge the runs until we have one big run */ do { + cur_run++; + + /* Report progress of merge sort to MySQL for + show processlist progress field */ + thd_progress_report(trx->mysql_thd, cur_run, num_runs); + error = row_merge(trx, dup, file, block, tmpfd, &num_runs, run_offset); @@ -2218,6 +2229,8 @@ row_merge_sort( mem_free(run_offset); + thd_progress_end(trx->mysql_thd); + DBUG_RETURN(error); } From f1c1c04a34f39bcd6622b9886fb089dd41e51103 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Tue, 19 Aug 2014 15:18:18 +0400 Subject: [PATCH 010/153] MDEV-4262 - P_S discovery Discover P_S tables automatically. Most of this patch is code clean-up: - removed tests and code responsible for P_S tables correctness verification - always return error from ha_perfschema::create() - install/upgrade scripts won't create P_S tables anymore --- .../perfschema/include/upgrade_check.inc | 3 +- .../perfschema/r/pfs_upgrade_event.result | 53 - .../perfschema/r/pfs_upgrade_func.result | 53 - .../perfschema/r/pfs_upgrade_proc.result | 53 - .../perfschema/r/pfs_upgrade_table.result | 53 - .../perfschema/r/pfs_upgrade_view.result | 53 - .../r/tampered_perfschema_table1.result | 6 - .../t/tampered_perfschema_table1-master.opt | 1 - .../t/tampered_perfschema_table1.test | 25 - scripts/mysql_performance_tables.sql | 1424 ----------------- sql/mysqld.cc | 8 - storage/perfschema/CMakeLists.txt | 1 - storage/perfschema/ha_perfschema.cc | 35 +- storage/perfschema/pfs_check.cc | 62 - storage/perfschema/pfs_engine_table.cc | 134 +- storage/perfschema/pfs_engine_table.h | 12 +- storage/perfschema/pfs_server.h | 2 - storage/perfschema/table_accounts.cc | 35 +- storage/perfschema/table_accounts.h | 2 - .../table_esgs_by_account_by_event_name.cc | 59 +- .../table_esgs_by_account_by_event_name.h | 2 - .../table_esgs_by_host_by_event_name.cc | 53 +- .../table_esgs_by_host_by_event_name.h | 2 - .../table_esgs_by_thread_by_event_name.cc | 53 +- .../table_esgs_by_thread_by_event_name.h | 2 - .../table_esgs_by_user_by_event_name.cc | 53 +- .../table_esgs_by_user_by_event_name.h | 2 - .../table_esgs_global_by_event_name.cc | 47 +- .../table_esgs_global_by_event_name.h | 2 - .../table_esms_by_account_by_event_name.cc | 173 +- .../table_esms_by_account_by_event_name.h | 2 - storage/perfschema/table_esms_by_digest.cc | 185 +-- storage/perfschema/table_esms_by_digest.h | 2 - .../table_esms_by_host_by_event_name.cc | 167 +- .../table_esms_by_host_by_event_name.h | 2 - .../table_esms_by_thread_by_event_name.cc | 167 +- .../table_esms_by_thread_by_event_name.h | 2 - .../table_esms_by_user_by_event_name.cc | 167 +- .../table_esms_by_user_by_event_name.h | 2 - .../table_esms_global_by_event_name.cc | 161 +- .../table_esms_global_by_event_name.h | 2 - storage/perfschema/table_events_stages.cc | 97 +- storage/perfschema/table_events_stages.h | 6 - storage/perfschema/table_events_statements.cc | 337 ++-- storage/perfschema/table_events_statements.h | 6 - storage/perfschema/table_events_waits.cc | 169 +- storage/perfschema/table_events_waits.h | 6 - .../perfschema/table_events_waits_summary.cc | 53 +- .../perfschema/table_events_waits_summary.h | 2 - .../table_ews_by_account_by_event_name.cc | 59 +- .../table_ews_by_account_by_event_name.h | 2 - .../table_ews_by_host_by_event_name.cc | 53 +- .../table_ews_by_host_by_event_name.h | 2 - .../table_ews_by_thread_by_event_name.cc | 53 +- .../table_ews_by_thread_by_event_name.h | 2 - .../table_ews_by_user_by_event_name.cc | 53 +- .../table_ews_by_user_by_event_name.h | 2 - .../table_ews_global_by_event_name.cc | 47 +- .../table_ews_global_by_event_name.h | 2 - storage/perfschema/table_file_instances.cc | 29 +- storage/perfschema/table_file_instances.h | 2 - storage/perfschema/table_file_summary.cc | 372 ----- storage/perfschema/table_file_summary.h | 151 -- .../table_file_summary_by_event_name.cc | 155 +- .../table_file_summary_by_event_name.h | 2 - .../table_file_summary_by_instance.cc | 167 +- .../table_file_summary_by_instance.h | 2 - storage/perfschema/table_host_cache.cc | 185 +-- storage/perfschema/table_host_cache.h | 2 - storage/perfschema/table_hosts.cc | 29 +- storage/perfschema/table_hosts.h | 2 - storage/perfschema/table_os_global_by_type.cc | 59 +- storage/perfschema/table_os_global_by_type.h | 2 - .../perfschema/table_performance_timers.cc | 36 +- storage/perfschema/table_performance_timers.h | 2 - .../table_session_account_connect_attrs.cc | 8 +- storage/perfschema/table_session_connect.cc | 27 - storage/perfschema/table_session_connect.h | 2 - .../perfschema/table_session_connect_attrs.cc | 8 +- storage/perfschema/table_setup_actors.cc | 29 +- storage/perfschema/table_setup_actors.h | 2 - storage/perfschema/table_setup_consumers.cc | 23 +- storage/perfschema/table_setup_consumers.h | 2 - storage/perfschema/table_setup_instruments.cc | 29 +- storage/perfschema/table_setup_instruments.h | 2 - storage/perfschema/table_setup_objects.cc | 41 +- storage/perfschema/table_setup_objects.h | 2 - storage/perfschema/table_setup_timers.cc | 24 +- storage/perfschema/table_setup_timers.h | 2 - storage/perfschema/table_socket_instances.cc | 53 +- storage/perfschema/table_socket_instances.h | 2 - .../table_socket_summary_by_event_name.cc | 155 +- .../table_socket_summary_by_event_name.h | 2 - .../table_socket_summary_by_instance.cc | 161 +- .../table_socket_summary_by_instance.h | 2 - storage/perfschema/table_sync_instances.cc | 87 +- storage/perfschema/table_sync_instances.h | 6 - storage/perfschema/table_threads.cc | 95 +- storage/perfschema/table_threads.h | 2 - .../perfschema/table_tiws_by_index_usage.cc | 245 +-- .../perfschema/table_tiws_by_index_usage.h | 2 - storage/perfschema/table_tiws_by_table.cc | 239 +-- storage/perfschema/table_tiws_by_table.h | 2 - storage/perfschema/table_tlws_by_table.cc | 449 +----- storage/perfschema/table_tlws_by_table.h | 2 - storage/perfschema/table_users.cc | 29 +- storage/perfschema/table_users.h | 2 - 107 files changed, 889 insertions(+), 6317 deletions(-) delete mode 100644 mysql-test/suite/perfschema/r/tampered_perfschema_table1.result delete mode 100644 mysql-test/suite/perfschema/t/tampered_perfschema_table1-master.opt delete mode 100644 mysql-test/suite/perfschema/t/tampered_perfschema_table1.test delete mode 100644 storage/perfschema/pfs_check.cc delete mode 100644 storage/perfschema/table_file_summary.cc delete mode 100644 storage/perfschema/table_file_summary.h diff --git a/mysql-test/suite/perfschema/include/upgrade_check.inc b/mysql-test/suite/perfschema/include/upgrade_check.inc index 52d4cfd1e63..327d63cc633 100644 --- a/mysql-test/suite/perfschema/include/upgrade_check.inc +++ b/mysql-test/suite/perfschema/include/upgrade_check.inc @@ -3,11 +3,10 @@ # --source include/count_sessions.inc ---error 1 --exec $MYSQL_UPGRADE --skip-verbose --force > $out_file 2> $err_file --source include/wait_until_count_sessions.inc -# Verify that mysql_upgrade complained about the performance_schema +# Verify that mysql_upgrade does not complain about the performance_schema --replace_regex /at line [0-9]+/at line ###/ --cat_file $err_file diff --git a/mysql-test/suite/perfschema/r/pfs_upgrade_event.result b/mysql-test/suite/perfschema/r/pfs_upgrade_event.result index cbd684a6232..6397ef7d90c 100644 --- a/mysql-test/suite/perfschema/r/pfs_upgrade_event.result +++ b/mysql-test/suite/perfschema/r/pfs_upgrade_event.result @@ -3,59 +3,6 @@ drop event if exists test.user_event; create event test.user_event on schedule every 1 day do select "not supposed to be here"; update mysql.event set db='performance_schema' where name='user_event'; -ERROR 1050 (42S01) at line ###: Table 'cond_instances' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_current' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_history' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_history_long' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_by_instance' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_by_host_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_by_user_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_by_account_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_by_thread_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_global_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'file_instances' already exists -ERROR 1050 (42S01) at line ###: Table 'file_summary_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'file_summary_by_instance' already exists -ERROR 1050 (42S01) at line ###: Table 'socket_instances' already exists -ERROR 1050 (42S01) at line ###: Table 'socket_summary_by_instance' already exists -ERROR 1050 (42S01) at line ###: Table 'socket_summary_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'host_cache' already exists -ERROR 1050 (42S01) at line ###: Table 'mutex_instances' already exists -ERROR 1050 (42S01) at line ###: Table 'objects_summary_global_by_type' already exists -ERROR 1050 (42S01) at line ###: Table 'performance_timers' already exists -ERROR 1050 (42S01) at line ###: Table 'rwlock_instances' already exists -ERROR 1050 (42S01) at line ###: Table 'setup_actors' already exists -ERROR 1050 (42S01) at line ###: Table 'setup_consumers' already exists -ERROR 1050 (42S01) at line ###: Table 'setup_instruments' already exists -ERROR 1050 (42S01) at line ###: Table 'setup_objects' already exists -ERROR 1050 (42S01) at line ###: Table 'setup_timers' already exists -ERROR 1050 (42S01) at line ###: Table 'table_io_waits_summary_by_index_usage' already exists -ERROR 1050 (42S01) at line ###: Table 'table_io_waits_summary_by_table' already exists -ERROR 1050 (42S01) at line ###: Table 'table_lock_waits_summary_by_table' already exists -ERROR 1050 (42S01) at line ###: Table 'threads' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_current' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_history' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_history_long' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_summary_by_thread_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_summary_by_host_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_summary_by_user_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_summary_by_account_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_summary_global_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_current' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_history' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_history_long' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_by_thread_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_by_host_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_by_user_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_by_account_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_global_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'hosts' already exists -ERROR 1050 (42S01) at line ###: Table 'users' already exists -ERROR 1050 (42S01) at line ###: Table 'accounts' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_by_digest' already exists -ERROR 1050 (42S01) at line ###: Table 'session_connect_attrs' already exists -ERROR 1050 (42S01) at line ###: Table 'session_account_connect_attrs' already exists -FATAL ERROR: Upgrade failed select name from mysql.event where db='performance_schema'; name user_event diff --git a/mysql-test/suite/perfschema/r/pfs_upgrade_func.result b/mysql-test/suite/perfschema/r/pfs_upgrade_func.result index 6978e1ed0a8..e03b526b045 100644 --- a/mysql-test/suite/perfschema/r/pfs_upgrade_func.result +++ b/mysql-test/suite/perfschema/r/pfs_upgrade_func.result @@ -3,59 +3,6 @@ drop function if exists test.user_func; create function test.user_func() returns integer return 0; update mysql.proc set db='performance_schema' where name='user_func'; -ERROR 1050 (42S01) at line ###: Table 'cond_instances' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_current' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_history' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_history_long' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_by_instance' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_by_host_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_by_user_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_by_account_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_by_thread_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_global_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'file_instances' already exists -ERROR 1050 (42S01) at line ###: Table 'file_summary_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'file_summary_by_instance' already exists -ERROR 1050 (42S01) at line ###: Table 'socket_instances' already exists -ERROR 1050 (42S01) at line ###: Table 'socket_summary_by_instance' already exists -ERROR 1050 (42S01) at line ###: Table 'socket_summary_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'host_cache' already exists -ERROR 1050 (42S01) at line ###: Table 'mutex_instances' already exists -ERROR 1050 (42S01) at line ###: Table 'objects_summary_global_by_type' already exists -ERROR 1050 (42S01) at line ###: Table 'performance_timers' already exists -ERROR 1050 (42S01) at line ###: Table 'rwlock_instances' already exists -ERROR 1050 (42S01) at line ###: Table 'setup_actors' already exists -ERROR 1050 (42S01) at line ###: Table 'setup_consumers' already exists -ERROR 1050 (42S01) at line ###: Table 'setup_instruments' already exists -ERROR 1050 (42S01) at line ###: Table 'setup_objects' already exists -ERROR 1050 (42S01) at line ###: Table 'setup_timers' already exists -ERROR 1050 (42S01) at line ###: Table 'table_io_waits_summary_by_index_usage' already exists -ERROR 1050 (42S01) at line ###: Table 'table_io_waits_summary_by_table' already exists -ERROR 1050 (42S01) at line ###: Table 'table_lock_waits_summary_by_table' already exists -ERROR 1050 (42S01) at line ###: Table 'threads' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_current' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_history' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_history_long' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_summary_by_thread_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_summary_by_host_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_summary_by_user_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_summary_by_account_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_summary_global_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_current' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_history' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_history_long' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_by_thread_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_by_host_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_by_user_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_by_account_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_global_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'hosts' already exists -ERROR 1050 (42S01) at line ###: Table 'users' already exists -ERROR 1050 (42S01) at line ###: Table 'accounts' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_by_digest' already exists -ERROR 1050 (42S01) at line ###: Table 'session_connect_attrs' already exists -ERROR 1050 (42S01) at line ###: Table 'session_account_connect_attrs' already exists -FATAL ERROR: Upgrade failed select name from mysql.proc where db='performance_schema'; name user_func diff --git a/mysql-test/suite/perfschema/r/pfs_upgrade_proc.result b/mysql-test/suite/perfschema/r/pfs_upgrade_proc.result index f5a13fb445d..95e0943d326 100644 --- a/mysql-test/suite/perfschema/r/pfs_upgrade_proc.result +++ b/mysql-test/suite/perfschema/r/pfs_upgrade_proc.result @@ -3,59 +3,6 @@ drop procedure if exists test.user_proc; create procedure test.user_proc() select "Not supposed to be here"; update mysql.proc set db='performance_schema' where name='user_proc'; -ERROR 1050 (42S01) at line ###: Table 'cond_instances' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_current' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_history' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_history_long' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_by_instance' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_by_host_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_by_user_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_by_account_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_by_thread_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_global_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'file_instances' already exists -ERROR 1050 (42S01) at line ###: Table 'file_summary_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'file_summary_by_instance' already exists -ERROR 1050 (42S01) at line ###: Table 'socket_instances' already exists -ERROR 1050 (42S01) at line ###: Table 'socket_summary_by_instance' already exists -ERROR 1050 (42S01) at line ###: Table 'socket_summary_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'host_cache' already exists -ERROR 1050 (42S01) at line ###: Table 'mutex_instances' already exists -ERROR 1050 (42S01) at line ###: Table 'objects_summary_global_by_type' already exists -ERROR 1050 (42S01) at line ###: Table 'performance_timers' already exists -ERROR 1050 (42S01) at line ###: Table 'rwlock_instances' already exists -ERROR 1050 (42S01) at line ###: Table 'setup_actors' already exists -ERROR 1050 (42S01) at line ###: Table 'setup_consumers' already exists -ERROR 1050 (42S01) at line ###: Table 'setup_instruments' already exists -ERROR 1050 (42S01) at line ###: Table 'setup_objects' already exists -ERROR 1050 (42S01) at line ###: Table 'setup_timers' already exists -ERROR 1050 (42S01) at line ###: Table 'table_io_waits_summary_by_index_usage' already exists -ERROR 1050 (42S01) at line ###: Table 'table_io_waits_summary_by_table' already exists -ERROR 1050 (42S01) at line ###: Table 'table_lock_waits_summary_by_table' already exists -ERROR 1050 (42S01) at line ###: Table 'threads' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_current' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_history' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_history_long' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_summary_by_thread_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_summary_by_host_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_summary_by_user_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_summary_by_account_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_summary_global_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_current' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_history' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_history_long' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_by_thread_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_by_host_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_by_user_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_by_account_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_global_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'hosts' already exists -ERROR 1050 (42S01) at line ###: Table 'users' already exists -ERROR 1050 (42S01) at line ###: Table 'accounts' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_by_digest' already exists -ERROR 1050 (42S01) at line ###: Table 'session_connect_attrs' already exists -ERROR 1050 (42S01) at line ###: Table 'session_account_connect_attrs' already exists -FATAL ERROR: Upgrade failed select name from mysql.proc where db='performance_schema'; name user_proc diff --git a/mysql-test/suite/perfschema/r/pfs_upgrade_table.result b/mysql-test/suite/perfschema/r/pfs_upgrade_table.result index bb5ba7060ae..a5f5ad5ae17 100644 --- a/mysql-test/suite/perfschema/r/pfs_upgrade_table.result +++ b/mysql-test/suite/perfschema/r/pfs_upgrade_table.result @@ -5,59 +5,6 @@ use performance_schema; show tables like "user_table"; Tables_in_performance_schema (user_table) user_table -ERROR 1050 (42S01) at line ###: Table 'cond_instances' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_current' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_history' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_history_long' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_by_instance' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_by_host_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_by_user_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_by_account_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_by_thread_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_global_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'file_instances' already exists -ERROR 1050 (42S01) at line ###: Table 'file_summary_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'file_summary_by_instance' already exists -ERROR 1050 (42S01) at line ###: Table 'socket_instances' already exists -ERROR 1050 (42S01) at line ###: Table 'socket_summary_by_instance' already exists -ERROR 1050 (42S01) at line ###: Table 'socket_summary_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'host_cache' already exists -ERROR 1050 (42S01) at line ###: Table 'mutex_instances' already exists -ERROR 1050 (42S01) at line ###: Table 'objects_summary_global_by_type' already exists -ERROR 1050 (42S01) at line ###: Table 'performance_timers' already exists -ERROR 1050 (42S01) at line ###: Table 'rwlock_instances' already exists -ERROR 1050 (42S01) at line ###: Table 'setup_actors' already exists -ERROR 1050 (42S01) at line ###: Table 'setup_consumers' already exists -ERROR 1050 (42S01) at line ###: Table 'setup_instruments' already exists -ERROR 1050 (42S01) at line ###: Table 'setup_objects' already exists -ERROR 1050 (42S01) at line ###: Table 'setup_timers' already exists -ERROR 1050 (42S01) at line ###: Table 'table_io_waits_summary_by_index_usage' already exists -ERROR 1050 (42S01) at line ###: Table 'table_io_waits_summary_by_table' already exists -ERROR 1050 (42S01) at line ###: Table 'table_lock_waits_summary_by_table' already exists -ERROR 1050 (42S01) at line ###: Table 'threads' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_current' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_history' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_history_long' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_summary_by_thread_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_summary_by_host_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_summary_by_user_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_summary_by_account_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_summary_global_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_current' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_history' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_history_long' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_by_thread_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_by_host_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_by_user_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_by_account_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_global_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'hosts' already exists -ERROR 1050 (42S01) at line ###: Table 'users' already exists -ERROR 1050 (42S01) at line ###: Table 'accounts' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_by_digest' already exists -ERROR 1050 (42S01) at line ###: Table 'session_connect_attrs' already exists -ERROR 1050 (42S01) at line ###: Table 'session_account_connect_attrs' already exists -FATAL ERROR: Upgrade failed show tables like "user_table"; Tables_in_performance_schema (user_table) user_table diff --git a/mysql-test/suite/perfschema/r/pfs_upgrade_view.result b/mysql-test/suite/perfschema/r/pfs_upgrade_view.result index f9541680b6d..3c6df20a62c 100644 --- a/mysql-test/suite/perfschema/r/pfs_upgrade_view.result +++ b/mysql-test/suite/perfschema/r/pfs_upgrade_view.result @@ -5,59 +5,6 @@ use performance_schema; show tables like "user_view"; Tables_in_performance_schema (user_view) user_view -ERROR 1050 (42S01) at line ###: Table 'cond_instances' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_current' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_history' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_history_long' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_by_instance' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_by_host_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_by_user_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_by_account_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_by_thread_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_waits_summary_global_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'file_instances' already exists -ERROR 1050 (42S01) at line ###: Table 'file_summary_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'file_summary_by_instance' already exists -ERROR 1050 (42S01) at line ###: Table 'socket_instances' already exists -ERROR 1050 (42S01) at line ###: Table 'socket_summary_by_instance' already exists -ERROR 1050 (42S01) at line ###: Table 'socket_summary_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'host_cache' already exists -ERROR 1050 (42S01) at line ###: Table 'mutex_instances' already exists -ERROR 1050 (42S01) at line ###: Table 'objects_summary_global_by_type' already exists -ERROR 1050 (42S01) at line ###: Table 'performance_timers' already exists -ERROR 1050 (42S01) at line ###: Table 'rwlock_instances' already exists -ERROR 1050 (42S01) at line ###: Table 'setup_actors' already exists -ERROR 1050 (42S01) at line ###: Table 'setup_consumers' already exists -ERROR 1050 (42S01) at line ###: Table 'setup_instruments' already exists -ERROR 1050 (42S01) at line ###: Table 'setup_objects' already exists -ERROR 1050 (42S01) at line ###: Table 'setup_timers' already exists -ERROR 1050 (42S01) at line ###: Table 'table_io_waits_summary_by_index_usage' already exists -ERROR 1050 (42S01) at line ###: Table 'table_io_waits_summary_by_table' already exists -ERROR 1050 (42S01) at line ###: Table 'table_lock_waits_summary_by_table' already exists -ERROR 1050 (42S01) at line ###: Table 'threads' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_current' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_history' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_history_long' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_summary_by_thread_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_summary_by_host_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_summary_by_user_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_summary_by_account_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_stages_summary_global_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_current' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_history' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_history_long' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_by_thread_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_by_host_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_by_user_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_by_account_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_global_by_event_name' already exists -ERROR 1050 (42S01) at line ###: Table 'hosts' already exists -ERROR 1050 (42S01) at line ###: Table 'users' already exists -ERROR 1050 (42S01) at line ###: Table 'accounts' already exists -ERROR 1050 (42S01) at line ###: Table 'events_statements_summary_by_digest' already exists -ERROR 1050 (42S01) at line ###: Table 'session_connect_attrs' already exists -ERROR 1050 (42S01) at line ###: Table 'session_account_connect_attrs' already exists -FATAL ERROR: Upgrade failed show tables like "user_view"; Tables_in_performance_schema (user_view) user_view diff --git a/mysql-test/suite/perfschema/r/tampered_perfschema_table1.result b/mysql-test/suite/perfschema/r/tampered_perfschema_table1.result deleted file mode 100644 index e9537e5474c..00000000000 --- a/mysql-test/suite/perfschema/r/tampered_perfschema_table1.result +++ /dev/null @@ -1,6 +0,0 @@ -call mtr.add_suppression( -"Column count of performance_schema.setup_instruments is wrong. " -"Expected 4, found 3. The table is probably corrupted"); -select * from performance_schema.setup_instruments limit 1; -ERROR HY000: Native table 'performance_schema'.'setup_instruments' has the wrong structure -select * from performance_schema.setup_consumers limit 1; diff --git a/mysql-test/suite/perfschema/t/tampered_perfschema_table1-master.opt b/mysql-test/suite/perfschema/t/tampered_perfschema_table1-master.opt deleted file mode 100644 index 5f094e68be7..00000000000 --- a/mysql-test/suite/perfschema/t/tampered_perfschema_table1-master.opt +++ /dev/null @@ -1 +0,0 @@ ---loose-debug=+d,tampered_perfschema_table1 diff --git a/mysql-test/suite/perfschema/t/tampered_perfschema_table1.test b/mysql-test/suite/perfschema/t/tampered_perfschema_table1.test deleted file mode 100644 index 09e3d3aaa2c..00000000000 --- a/mysql-test/suite/perfschema/t/tampered_perfschema_table1.test +++ /dev/null @@ -1,25 +0,0 @@ -# Tests for PERFORMANCE_SCHEMA - -# This test uses error injection, -# see PFS_engine_table_share::check_all_tables() - -# Verify that the server starts even when a performance schema table -# is corrupted, with an incompatible change. -# Verify that using that table nicely fails. -# Verify that other tables are not affected. - ---source include/have_debug.inc ---source include/not_embedded.inc ---source include/have_perfschema.inc - -call mtr.add_suppression( -"Column count of performance_schema.setup_instruments is wrong. " -"Expected 4, found 3. The table is probably corrupted"); - ---error ER_WRONG_NATIVE_TABLE_STRUCTURE -select * from performance_schema.setup_instruments limit 1; - ---disable_result_log -select * from performance_schema.setup_consumers limit 1; ---enable_result_log - diff --git a/scripts/mysql_performance_tables.sql b/scripts/mysql_performance_tables.sql index d4955782e4d..306160355de 100644 --- a/scripts/mysql_performance_tables.sql +++ b/scripts/mysql_performance_tables.sql @@ -53,1427 +53,3 @@ SET @str = IF(@broken_pfs = 0, @cmd, 'SET @dummy = 0'); PREPARE stmt FROM @str; EXECUTE stmt; DROP PREPARE stmt; - --- --- From this point, only create the performance schema tables --- if the server is built with performance schema --- - -set @have_pfs= (select count(engine) from information_schema.engines where engine='PERFORMANCE_SCHEMA' and support != 'NO'); - --- --- TABLE COND_INSTANCES --- - -SET @cmd="CREATE TABLE performance_schema.cond_instances(" - "NAME VARCHAR(128) not null," - "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE EVENTS_WAITS_CURRENT --- - -SET @cmd="CREATE TABLE performance_schema.events_waits_current(" - "THREAD_ID BIGINT unsigned not null," - "EVENT_ID BIGINT unsigned not null," - "END_EVENT_ID BIGINT unsigned," - "EVENT_NAME VARCHAR(128) not null," - "SOURCE VARCHAR(64)," - "TIMER_START BIGINT unsigned," - "TIMER_END BIGINT unsigned," - "TIMER_WAIT BIGINT unsigned," - "SPINS INTEGER unsigned," - "OBJECT_SCHEMA VARCHAR(64)," - "OBJECT_NAME VARCHAR(512)," - "INDEX_NAME VARCHAR(64)," - "OBJECT_TYPE VARCHAR(64)," - "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null," - "NESTING_EVENT_ID BIGINT unsigned," - "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT')," - "OPERATION VARCHAR(32) not null," - "NUMBER_OF_BYTES BIGINT," - "FLAGS INTEGER unsigned" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE EVENTS_WAITS_HISTORY --- - -SET @cmd="CREATE TABLE performance_schema.events_waits_history(" - "THREAD_ID BIGINT unsigned not null," - "EVENT_ID BIGINT unsigned not null," - "END_EVENT_ID BIGINT unsigned," - "EVENT_NAME VARCHAR(128) not null," - "SOURCE VARCHAR(64)," - "TIMER_START BIGINT unsigned," - "TIMER_END BIGINT unsigned," - "TIMER_WAIT BIGINT unsigned," - "SPINS INTEGER unsigned," - "OBJECT_SCHEMA VARCHAR(64)," - "OBJECT_NAME VARCHAR(512)," - "INDEX_NAME VARCHAR(64)," - "OBJECT_TYPE VARCHAR(64)," - "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null," - "NESTING_EVENT_ID BIGINT unsigned," - "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT')," - "OPERATION VARCHAR(32) not null," - "NUMBER_OF_BYTES BIGINT," - "FLAGS INTEGER unsigned" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE EVENTS_WAITS_HISTORY_LONG --- - -SET @cmd="CREATE TABLE performance_schema.events_waits_history_long(" - "THREAD_ID BIGINT unsigned not null," - "EVENT_ID BIGINT unsigned not null," - "END_EVENT_ID BIGINT unsigned," - "EVENT_NAME VARCHAR(128) not null," - "SOURCE VARCHAR(64)," - "TIMER_START BIGINT unsigned," - "TIMER_END BIGINT unsigned," - "TIMER_WAIT BIGINT unsigned," - "SPINS INTEGER unsigned," - "OBJECT_SCHEMA VARCHAR(64)," - "OBJECT_NAME VARCHAR(512)," - "INDEX_NAME VARCHAR(64)," - "OBJECT_TYPE VARCHAR(64)," - "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null," - "NESTING_EVENT_ID BIGINT unsigned," - "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT')," - "OPERATION VARCHAR(32) not null," - "NUMBER_OF_BYTES BIGINT," - "FLAGS INTEGER unsigned" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE EVENTS_WAITS_SUMMARY_BY_INSTANCE --- - -SET @cmd="CREATE TABLE performance_schema.events_waits_summary_by_instance(" - "EVENT_NAME VARCHAR(128) not null," - "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null," - "COUNT_STAR BIGINT unsigned not null," - "SUM_TIMER_WAIT BIGINT unsigned not null," - "MIN_TIMER_WAIT BIGINT unsigned not null," - "AVG_TIMER_WAIT BIGINT unsigned not null," - "MAX_TIMER_WAIT BIGINT unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME --- - -SET @cmd="CREATE TABLE performance_schema.events_waits_summary_by_host_by_event_name(" - "HOST CHAR(60) collate utf8_bin default null," - "EVENT_NAME VARCHAR(128) not null," - "COUNT_STAR BIGINT unsigned not null," - "SUM_TIMER_WAIT BIGINT unsigned not null," - "MIN_TIMER_WAIT BIGINT unsigned not null," - "AVG_TIMER_WAIT BIGINT unsigned not null," - "MAX_TIMER_WAIT BIGINT unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME --- - -SET @cmd="CREATE TABLE performance_schema.events_waits_summary_by_user_by_event_name(" - "USER CHAR(16) collate utf8_bin default null," - "EVENT_NAME VARCHAR(128) not null," - "COUNT_STAR BIGINT unsigned not null," - "SUM_TIMER_WAIT BIGINT unsigned not null," - "MIN_TIMER_WAIT BIGINT unsigned not null," - "AVG_TIMER_WAIT BIGINT unsigned not null," - "MAX_TIMER_WAIT BIGINT unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME --- - -SET @cmd="CREATE TABLE performance_schema.events_waits_summary_by_account_by_event_name(" - "USER CHAR(16) collate utf8_bin default null," - "HOST CHAR(60) collate utf8_bin default null," - "EVENT_NAME VARCHAR(128) not null," - "COUNT_STAR BIGINT unsigned not null," - "SUM_TIMER_WAIT BIGINT unsigned not null," - "MIN_TIMER_WAIT BIGINT unsigned not null," - "AVG_TIMER_WAIT BIGINT unsigned not null," - "MAX_TIMER_WAIT BIGINT unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME --- - -SET @cmd="CREATE TABLE performance_schema.events_waits_summary_by_thread_by_event_name(" - "THREAD_ID BIGINT unsigned not null," - "EVENT_NAME VARCHAR(128) not null," - "COUNT_STAR BIGINT unsigned not null," - "SUM_TIMER_WAIT BIGINT unsigned not null," - "MIN_TIMER_WAIT BIGINT unsigned not null," - "AVG_TIMER_WAIT BIGINT unsigned not null," - "MAX_TIMER_WAIT BIGINT unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME --- - -SET @cmd="CREATE TABLE performance_schema.events_waits_summary_global_by_event_name(" - "EVENT_NAME VARCHAR(128) not null," - "COUNT_STAR BIGINT unsigned not null," - "SUM_TIMER_WAIT BIGINT unsigned not null," - "MIN_TIMER_WAIT BIGINT unsigned not null," - "AVG_TIMER_WAIT BIGINT unsigned not null," - "MAX_TIMER_WAIT BIGINT unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE FILE_INSTANCES --- - -SET @cmd="CREATE TABLE performance_schema.file_instances(" - "FILE_NAME VARCHAR(512) not null," - "EVENT_NAME VARCHAR(128) not null," - "OPEN_COUNT INTEGER unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE FILE_SUMMARY_BY_EVENT_NAME --- - -SET @cmd="CREATE TABLE performance_schema.file_summary_by_event_name(" - "EVENT_NAME VARCHAR(128) not null," - "COUNT_STAR BIGINT unsigned not null," - "SUM_TIMER_WAIT BIGINT unsigned not null," - "MIN_TIMER_WAIT BIGINT unsigned not null," - "AVG_TIMER_WAIT BIGINT unsigned not null," - "MAX_TIMER_WAIT BIGINT unsigned not null," - "COUNT_READ BIGINT unsigned not null," - "SUM_TIMER_READ BIGINT unsigned not null," - "MIN_TIMER_READ BIGINT unsigned not null," - "AVG_TIMER_READ BIGINT unsigned not null," - "MAX_TIMER_READ BIGINT unsigned not null," - "SUM_NUMBER_OF_BYTES_READ BIGINT not null," - "COUNT_WRITE BIGINT unsigned not null," - "SUM_TIMER_WRITE BIGINT unsigned not null," - "MIN_TIMER_WRITE BIGINT unsigned not null," - "AVG_TIMER_WRITE BIGINT unsigned not null," - "MAX_TIMER_WRITE BIGINT unsigned not null," - "SUM_NUMBER_OF_BYTES_WRITE BIGINT not null," - "COUNT_MISC BIGINT unsigned not null," - "SUM_TIMER_MISC BIGINT unsigned not null," - "MIN_TIMER_MISC BIGINT unsigned not null," - "AVG_TIMER_MISC BIGINT unsigned not null," - "MAX_TIMER_MISC BIGINT unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE FILE_SUMMARY_BY_INSTANCE --- - -SET @cmd="CREATE TABLE performance_schema.file_summary_by_instance(" - "FILE_NAME VARCHAR(512) not null," - "EVENT_NAME VARCHAR(128) not null," - "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null," - "COUNT_STAR BIGINT unsigned not null," - "SUM_TIMER_WAIT BIGINT unsigned not null," - "MIN_TIMER_WAIT BIGINT unsigned not null," - "AVG_TIMER_WAIT BIGINT unsigned not null," - "MAX_TIMER_WAIT BIGINT unsigned not null," - "COUNT_READ BIGINT unsigned not null," - "SUM_TIMER_READ BIGINT unsigned not null," - "MIN_TIMER_READ BIGINT unsigned not null," - "AVG_TIMER_READ BIGINT unsigned not null," - "MAX_TIMER_READ BIGINT unsigned not null," - "SUM_NUMBER_OF_BYTES_READ BIGINT not null," - "COUNT_WRITE BIGINT unsigned not null," - "SUM_TIMER_WRITE BIGINT unsigned not null," - "MIN_TIMER_WRITE BIGINT unsigned not null," - "AVG_TIMER_WRITE BIGINT unsigned not null," - "MAX_TIMER_WRITE BIGINT unsigned not null," - "SUM_NUMBER_OF_BYTES_WRITE BIGINT not null," - "COUNT_MISC BIGINT unsigned not null," - "SUM_TIMER_MISC BIGINT unsigned not null," - "MIN_TIMER_MISC BIGINT unsigned not null," - "AVG_TIMER_MISC BIGINT unsigned not null," - "MAX_TIMER_MISC BIGINT unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - - --- --- TABLE SOCKET_INSTANCES --- - -SET @cmd="CREATE TABLE performance_schema.socket_instances(" - "EVENT_NAME VARCHAR(128) not null," - "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null," - "THREAD_ID BIGINT unsigned," - "SOCKET_ID INTEGER not null," - "IP VARCHAR(64) not null," - "PORT INTEGER not null," - "STATE ENUM('IDLE','ACTIVE') not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE SOCKET_SUMMARY_BY_INSTANCE --- - -SET @cmd="CREATE TABLE performance_schema.socket_summary_by_instance(" - "EVENT_NAME VARCHAR(128) not null," - "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null," - "COUNT_STAR BIGINT unsigned not null," - "SUM_TIMER_WAIT BIGINT unsigned not null," - "MIN_TIMER_WAIT BIGINT unsigned not null," - "AVG_TIMER_WAIT BIGINT unsigned not null," - "MAX_TIMER_WAIT BIGINT unsigned not null," - "COUNT_READ BIGINT unsigned not null," - "SUM_TIMER_READ BIGINT unsigned not null," - "MIN_TIMER_READ BIGINT unsigned not null," - "AVG_TIMER_READ BIGINT unsigned not null," - "MAX_TIMER_READ BIGINT unsigned not null," - "SUM_NUMBER_OF_BYTES_READ BIGINT unsigned not null," - "COUNT_WRITE BIGINT unsigned not null," - "SUM_TIMER_WRITE BIGINT unsigned not null," - "MIN_TIMER_WRITE BIGINT unsigned not null," - "AVG_TIMER_WRITE BIGINT unsigned not null," - "MAX_TIMER_WRITE BIGINT unsigned not null," - "SUM_NUMBER_OF_BYTES_WRITE BIGINT unsigned not null," - "COUNT_MISC BIGINT unsigned not null," - "SUM_TIMER_MISC BIGINT unsigned not null," - "MIN_TIMER_MISC BIGINT unsigned not null," - "AVG_TIMER_MISC BIGINT unsigned not null," - "MAX_TIMER_MISC BIGINT unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE SOCKET_SUMMARY_BY_INSTANCE --- - -SET @cmd="CREATE TABLE performance_schema.socket_summary_by_event_name(" - "EVENT_NAME VARCHAR(128) not null," - "COUNT_STAR BIGINT unsigned not null," - "SUM_TIMER_WAIT BIGINT unsigned not null," - "MIN_TIMER_WAIT BIGINT unsigned not null," - "AVG_TIMER_WAIT BIGINT unsigned not null," - "MAX_TIMER_WAIT BIGINT unsigned not null," - "COUNT_READ BIGINT unsigned not null," - "SUM_TIMER_READ BIGINT unsigned not null," - "MIN_TIMER_READ BIGINT unsigned not null," - "AVG_TIMER_READ BIGINT unsigned not null," - "MAX_TIMER_READ BIGINT unsigned not null," - "SUM_NUMBER_OF_BYTES_READ BIGINT unsigned not null," - "COUNT_WRITE BIGINT unsigned not null," - "SUM_TIMER_WRITE BIGINT unsigned not null," - "MIN_TIMER_WRITE BIGINT unsigned not null," - "AVG_TIMER_WRITE BIGINT unsigned not null," - "MAX_TIMER_WRITE BIGINT unsigned not null," - "SUM_NUMBER_OF_BYTES_WRITE BIGINT unsigned not null," - "COUNT_MISC BIGINT unsigned not null," - "SUM_TIMER_MISC BIGINT unsigned not null," - "MIN_TIMER_MISC BIGINT unsigned not null," - "AVG_TIMER_MISC BIGINT unsigned not null," - "MAX_TIMER_MISC BIGINT unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE HOST_CACHE --- - -SET @cmd="CREATE TABLE performance_schema.host_cache(" - "IP VARCHAR(64) not null," - "HOST VARCHAR(255) collate utf8_bin," - "HOST_VALIDATED ENUM ('YES', 'NO') not null," - "SUM_CONNECT_ERRORS BIGINT not null," - "COUNT_HOST_BLOCKED_ERRORS BIGINT not null," - "COUNT_NAMEINFO_TRANSIENT_ERRORS BIGINT not null," - "COUNT_NAMEINFO_PERMANENT_ERRORS BIGINT not null," - "COUNT_FORMAT_ERRORS BIGINT not null," - "COUNT_ADDRINFO_TRANSIENT_ERRORS BIGINT not null," - "COUNT_ADDRINFO_PERMANENT_ERRORS BIGINT not null," - "COUNT_FCRDNS_ERRORS BIGINT not null," - "COUNT_HOST_ACL_ERRORS BIGINT not null," - "COUNT_NO_AUTH_PLUGIN_ERRORS BIGINT not null," - "COUNT_AUTH_PLUGIN_ERRORS BIGINT not null," - "COUNT_HANDSHAKE_ERRORS BIGINT not null," - "COUNT_PROXY_USER_ERRORS BIGINT not null," - "COUNT_PROXY_USER_ACL_ERRORS BIGINT not null," - "COUNT_AUTHENTICATION_ERRORS BIGINT not null," - "COUNT_SSL_ERRORS BIGINT not null," - "COUNT_MAX_USER_CONNECTIONS_ERRORS BIGINT not null," - "COUNT_MAX_USER_CONNECTIONS_PER_HOUR_ERRORS BIGINT not null," - "COUNT_DEFAULT_DATABASE_ERRORS BIGINT not null," - "COUNT_INIT_CONNECT_ERRORS BIGINT not null," - "COUNT_LOCAL_ERRORS BIGINT not null," - "COUNT_UNKNOWN_ERRORS BIGINT not null," - "FIRST_SEEN TIMESTAMP(0) NOT NULL default 0," - "LAST_SEEN TIMESTAMP(0) NOT NULL default 0," - "FIRST_ERROR_SEEN TIMESTAMP(0) null default 0," - "LAST_ERROR_SEEN TIMESTAMP(0) null default 0" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE MUTEX_INSTANCES --- - -SET @cmd="CREATE TABLE performance_schema.mutex_instances(" - "NAME VARCHAR(128) not null," - "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null," - "LOCKED_BY_THREAD_ID BIGINT unsigned" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE OBJECTS_SUMMARY_GLOBAL_BY_TYPE --- - -SET @cmd="CREATE TABLE performance_schema.objects_summary_global_by_type(" - "OBJECT_TYPE VARCHAR(64)," - "OBJECT_SCHEMA VARCHAR(64)," - "OBJECT_NAME VARCHAR(64)," - "COUNT_STAR BIGINT unsigned not null," - "SUM_TIMER_WAIT BIGINT unsigned not null," - "MIN_TIMER_WAIT BIGINT unsigned not null," - "AVG_TIMER_WAIT BIGINT unsigned not null," - "MAX_TIMER_WAIT BIGINT unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE PERFORMANCE_TIMERS --- - -SET @cmd="CREATE TABLE performance_schema.performance_timers(" - "TIMER_NAME ENUM ('CYCLE', 'NANOSECOND', 'MICROSECOND', 'MILLISECOND', 'TICK') not null," - "TIMER_FREQUENCY BIGINT," - "TIMER_RESOLUTION BIGINT," - "TIMER_OVERHEAD BIGINT" - ") ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE RWLOCK_INSTANCES --- - -SET @cmd="CREATE TABLE performance_schema.rwlock_instances(" - "NAME VARCHAR(128) not null," - "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null," - "WRITE_LOCKED_BY_THREAD_ID BIGINT unsigned," - "READ_LOCKED_BY_COUNT INTEGER unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE SETUP_ACTORS --- - -SET @cmd="CREATE TABLE performance_schema.setup_actors(" - "HOST CHAR(60) collate utf8_bin default '%' not null," - "USER CHAR(16) collate utf8_bin default '%' not null," - "ROLE CHAR(16) collate utf8_bin default '%' not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE SETUP_CONSUMERS --- - -SET @cmd="CREATE TABLE performance_schema.setup_consumers(" - "NAME VARCHAR(64) not null," - "ENABLED ENUM ('YES', 'NO') not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE SETUP_INSTRUMENTS --- - -SET @cmd="CREATE TABLE performance_schema.setup_instruments(" - "NAME VARCHAR(128) not null," - "ENABLED ENUM ('YES', 'NO') not null," - "TIMED ENUM ('YES', 'NO') not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE SETUP_OBJECTS --- - -SET @cmd="CREATE TABLE performance_schema.setup_objects(" - "OBJECT_TYPE ENUM ('TABLE') not null default 'TABLE'," - "OBJECT_SCHEMA VARCHAR(64) default '%'," - "OBJECT_NAME VARCHAR(64) not null default '%'," - "ENABLED ENUM ('YES', 'NO') not null default 'YES'," - "TIMED ENUM ('YES', 'NO') not null default 'YES'" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE SETUP_TIMERS --- - -SET @cmd="CREATE TABLE performance_schema.setup_timers(" - "NAME VARCHAR(64) not null," - "TIMER_NAME ENUM ('CYCLE', 'NANOSECOND', 'MICROSECOND', 'MILLISECOND', 'TICK') not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE TABLE_IO_WAITS_SUMMARY_BY_INDEX_USAGE --- - -SET @cmd="CREATE TABLE performance_schema.table_io_waits_summary_by_index_usage(" - "OBJECT_TYPE VARCHAR(64)," - "OBJECT_SCHEMA VARCHAR(64)," - "OBJECT_NAME VARCHAR(64)," - "INDEX_NAME VARCHAR(64)," - "COUNT_STAR BIGINT unsigned not null," - "SUM_TIMER_WAIT BIGINT unsigned not null," - "MIN_TIMER_WAIT BIGINT unsigned not null," - "AVG_TIMER_WAIT BIGINT unsigned not null," - "MAX_TIMER_WAIT BIGINT unsigned not null," - "COUNT_READ BIGINT unsigned not null," - "SUM_TIMER_READ BIGINT unsigned not null," - "MIN_TIMER_READ BIGINT unsigned not null," - "AVG_TIMER_READ BIGINT unsigned not null," - "MAX_TIMER_READ BIGINT unsigned not null," - "COUNT_WRITE BIGINT unsigned not null," - "SUM_TIMER_WRITE BIGINT unsigned not null," - "MIN_TIMER_WRITE BIGINT unsigned not null," - "AVG_TIMER_WRITE BIGINT unsigned not null," - "MAX_TIMER_WRITE BIGINT unsigned not null," - "COUNT_FETCH BIGINT unsigned not null," - "SUM_TIMER_FETCH BIGINT unsigned not null," - "MIN_TIMER_FETCH BIGINT unsigned not null," - "AVG_TIMER_FETCH BIGINT unsigned not null," - "MAX_TIMER_FETCH BIGINT unsigned not null," - "COUNT_INSERT BIGINT unsigned not null," - "SUM_TIMER_INSERT BIGINT unsigned not null," - "MIN_TIMER_INSERT BIGINT unsigned not null," - "AVG_TIMER_INSERT BIGINT unsigned not null," - "MAX_TIMER_INSERT BIGINT unsigned not null," - "COUNT_UPDATE BIGINT unsigned not null," - "SUM_TIMER_UPDATE BIGINT unsigned not null," - "MIN_TIMER_UPDATE BIGINT unsigned not null," - "AVG_TIMER_UPDATE BIGINT unsigned not null," - "MAX_TIMER_UPDATE BIGINT unsigned not null," - "COUNT_DELETE BIGINT unsigned not null," - "SUM_TIMER_DELETE BIGINT unsigned not null," - "MIN_TIMER_DELETE BIGINT unsigned not null," - "AVG_TIMER_DELETE BIGINT unsigned not null," - "MAX_TIMER_DELETE BIGINT unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE TABLE_IO_WAITS_SUMMARY_BY_TABLE --- - -SET @cmd="CREATE TABLE performance_schema.table_io_waits_summary_by_table(" - "OBJECT_TYPE VARCHAR(64)," - "OBJECT_SCHEMA VARCHAR(64)," - "OBJECT_NAME VARCHAR(64)," - "COUNT_STAR BIGINT unsigned not null," - "SUM_TIMER_WAIT BIGINT unsigned not null," - "MIN_TIMER_WAIT BIGINT unsigned not null," - "AVG_TIMER_WAIT BIGINT unsigned not null," - "MAX_TIMER_WAIT BIGINT unsigned not null," - "COUNT_READ BIGINT unsigned not null," - "SUM_TIMER_READ BIGINT unsigned not null," - "MIN_TIMER_READ BIGINT unsigned not null," - "AVG_TIMER_READ BIGINT unsigned not null," - "MAX_TIMER_READ BIGINT unsigned not null," - "COUNT_WRITE BIGINT unsigned not null," - "SUM_TIMER_WRITE BIGINT unsigned not null," - "MIN_TIMER_WRITE BIGINT unsigned not null," - "AVG_TIMER_WRITE BIGINT unsigned not null," - "MAX_TIMER_WRITE BIGINT unsigned not null," - "COUNT_FETCH BIGINT unsigned not null," - "SUM_TIMER_FETCH BIGINT unsigned not null," - "MIN_TIMER_FETCH BIGINT unsigned not null," - "AVG_TIMER_FETCH BIGINT unsigned not null," - "MAX_TIMER_FETCH BIGINT unsigned not null," - "COUNT_INSERT BIGINT unsigned not null," - "SUM_TIMER_INSERT BIGINT unsigned not null," - "MIN_TIMER_INSERT BIGINT unsigned not null," - "AVG_TIMER_INSERT BIGINT unsigned not null," - "MAX_TIMER_INSERT BIGINT unsigned not null," - "COUNT_UPDATE BIGINT unsigned not null," - "SUM_TIMER_UPDATE BIGINT unsigned not null," - "MIN_TIMER_UPDATE BIGINT unsigned not null," - "AVG_TIMER_UPDATE BIGINT unsigned not null," - "MAX_TIMER_UPDATE BIGINT unsigned not null," - "COUNT_DELETE BIGINT unsigned not null," - "SUM_TIMER_DELETE BIGINT unsigned not null," - "MIN_TIMER_DELETE BIGINT unsigned not null," - "AVG_TIMER_DELETE BIGINT unsigned not null," - "MAX_TIMER_DELETE BIGINT unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE TABLE_LOCK_WAITS_SUMMARY_BY_TABLE --- - -SET @cmd="CREATE TABLE performance_schema.table_lock_waits_summary_by_table(" - "OBJECT_TYPE VARCHAR(64)," - "OBJECT_SCHEMA VARCHAR(64)," - "OBJECT_NAME VARCHAR(64)," - "COUNT_STAR BIGINT unsigned not null," - "SUM_TIMER_WAIT BIGINT unsigned not null," - "MIN_TIMER_WAIT BIGINT unsigned not null," - "AVG_TIMER_WAIT BIGINT unsigned not null," - "MAX_TIMER_WAIT BIGINT unsigned not null," - "COUNT_READ BIGINT unsigned not null," - "SUM_TIMER_READ BIGINT unsigned not null," - "MIN_TIMER_READ BIGINT unsigned not null," - "AVG_TIMER_READ BIGINT unsigned not null," - "MAX_TIMER_READ BIGINT unsigned not null," - "COUNT_WRITE BIGINT unsigned not null," - "SUM_TIMER_WRITE BIGINT unsigned not null," - "MIN_TIMER_WRITE BIGINT unsigned not null," - "AVG_TIMER_WRITE BIGINT unsigned not null," - "MAX_TIMER_WRITE BIGINT unsigned not null," - "COUNT_READ_NORMAL BIGINT unsigned not null," - "SUM_TIMER_READ_NORMAL BIGINT unsigned not null," - "MIN_TIMER_READ_NORMAL BIGINT unsigned not null," - "AVG_TIMER_READ_NORMAL BIGINT unsigned not null," - "MAX_TIMER_READ_NORMAL BIGINT unsigned not null," - "COUNT_READ_WITH_SHARED_LOCKS BIGINT unsigned not null," - "SUM_TIMER_READ_WITH_SHARED_LOCKS BIGINT unsigned not null," - "MIN_TIMER_READ_WITH_SHARED_LOCKS BIGINT unsigned not null," - "AVG_TIMER_READ_WITH_SHARED_LOCKS BIGINT unsigned not null," - "MAX_TIMER_READ_WITH_SHARED_LOCKS BIGINT unsigned not null," - "COUNT_READ_HIGH_PRIORITY BIGINT unsigned not null," - "SUM_TIMER_READ_HIGH_PRIORITY BIGINT unsigned not null," - "MIN_TIMER_READ_HIGH_PRIORITY BIGINT unsigned not null," - "AVG_TIMER_READ_HIGH_PRIORITY BIGINT unsigned not null," - "MAX_TIMER_READ_HIGH_PRIORITY BIGINT unsigned not null," - "COUNT_READ_NO_INSERT BIGINT unsigned not null," - "SUM_TIMER_READ_NO_INSERT BIGINT unsigned not null," - "MIN_TIMER_READ_NO_INSERT BIGINT unsigned not null," - "AVG_TIMER_READ_NO_INSERT BIGINT unsigned not null," - "MAX_TIMER_READ_NO_INSERT BIGINT unsigned not null," - "COUNT_READ_EXTERNAL BIGINT unsigned not null," - "SUM_TIMER_READ_EXTERNAL BIGINT unsigned not null," - "MIN_TIMER_READ_EXTERNAL BIGINT unsigned not null," - "AVG_TIMER_READ_EXTERNAL BIGINT unsigned not null," - "MAX_TIMER_READ_EXTERNAL BIGINT unsigned not null," - "COUNT_WRITE_ALLOW_WRITE BIGINT unsigned not null," - "SUM_TIMER_WRITE_ALLOW_WRITE BIGINT unsigned not null," - "MIN_TIMER_WRITE_ALLOW_WRITE BIGINT unsigned not null," - "AVG_TIMER_WRITE_ALLOW_WRITE BIGINT unsigned not null," - "MAX_TIMER_WRITE_ALLOW_WRITE BIGINT unsigned not null," - "COUNT_WRITE_CONCURRENT_INSERT BIGINT unsigned not null," - "SUM_TIMER_WRITE_CONCURRENT_INSERT BIGINT unsigned not null," - "MIN_TIMER_WRITE_CONCURRENT_INSERT BIGINT unsigned not null," - "AVG_TIMER_WRITE_CONCURRENT_INSERT BIGINT unsigned not null," - "MAX_TIMER_WRITE_CONCURRENT_INSERT BIGINT unsigned not null," - "COUNT_WRITE_DELAYED BIGINT unsigned not null," - "SUM_TIMER_WRITE_DELAYED BIGINT unsigned not null," - "MIN_TIMER_WRITE_DELAYED BIGINT unsigned not null," - "AVG_TIMER_WRITE_DELAYED BIGINT unsigned not null," - "MAX_TIMER_WRITE_DELAYED BIGINT unsigned not null," - "COUNT_WRITE_LOW_PRIORITY BIGINT unsigned not null," - "SUM_TIMER_WRITE_LOW_PRIORITY BIGINT unsigned not null," - "MIN_TIMER_WRITE_LOW_PRIORITY BIGINT unsigned not null," - "AVG_TIMER_WRITE_LOW_PRIORITY BIGINT unsigned not null," - "MAX_TIMER_WRITE_LOW_PRIORITY BIGINT unsigned not null," - "COUNT_WRITE_NORMAL BIGINT unsigned not null," - "SUM_TIMER_WRITE_NORMAL BIGINT unsigned not null," - "MIN_TIMER_WRITE_NORMAL BIGINT unsigned not null," - "AVG_TIMER_WRITE_NORMAL BIGINT unsigned not null," - "MAX_TIMER_WRITE_NORMAL BIGINT unsigned not null," - "COUNT_WRITE_EXTERNAL BIGINT unsigned not null," - "SUM_TIMER_WRITE_EXTERNAL BIGINT unsigned not null," - "MIN_TIMER_WRITE_EXTERNAL BIGINT unsigned not null," - "AVG_TIMER_WRITE_EXTERNAL BIGINT unsigned not null," - "MAX_TIMER_WRITE_EXTERNAL BIGINT unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE THREADS --- - -SET @cmd="CREATE TABLE performance_schema.threads(" - "THREAD_ID BIGINT unsigned not null," - "NAME VARCHAR(128) not null," - "TYPE VARCHAR(10) not null," - "PROCESSLIST_ID BIGINT unsigned," - "PROCESSLIST_USER VARCHAR(16)," - "PROCESSLIST_HOST VARCHAR(60)," - "PROCESSLIST_DB VARCHAR(64)," - "PROCESSLIST_COMMAND VARCHAR(16)," - "PROCESSLIST_TIME BIGINT," - "PROCESSLIST_STATE VARCHAR(64)," - "PROCESSLIST_INFO LONGTEXT," - "PARENT_THREAD_ID BIGINT unsigned," - "ROLE VARCHAR(64)," - "INSTRUMENTED ENUM ('YES', 'NO') not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE EVENTS_STAGES_CURRENT --- - -SET @cmd="CREATE TABLE performance_schema.events_stages_current(" - "THREAD_ID BIGINT unsigned not null," - "EVENT_ID BIGINT unsigned not null," - "END_EVENT_ID BIGINT unsigned," - "EVENT_NAME VARCHAR(128) not null," - "SOURCE VARCHAR(64)," - "TIMER_START BIGINT unsigned," - "TIMER_END BIGINT unsigned," - "TIMER_WAIT BIGINT unsigned," - "NESTING_EVENT_ID BIGINT unsigned," - "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT')" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE EVENTS_STAGES_HISTORY --- - -SET @cmd="CREATE TABLE performance_schema.events_stages_history(" - "THREAD_ID BIGINT unsigned not null," - "EVENT_ID BIGINT unsigned not null," - "END_EVENT_ID BIGINT unsigned," - "EVENT_NAME VARCHAR(128) not null," - "SOURCE VARCHAR(64)," - "TIMER_START BIGINT unsigned," - "TIMER_END BIGINT unsigned," - "TIMER_WAIT BIGINT unsigned," - "NESTING_EVENT_ID BIGINT unsigned," - "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT')" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE EVENTS_STAGES_HISTORY_LONG --- - -SET @cmd="CREATE TABLE performance_schema.events_stages_history_long(" - "THREAD_ID BIGINT unsigned not null," - "EVENT_ID BIGINT unsigned not null," - "END_EVENT_ID BIGINT unsigned," - "EVENT_NAME VARCHAR(128) not null," - "SOURCE VARCHAR(64)," - "TIMER_START BIGINT unsigned," - "TIMER_END BIGINT unsigned," - "TIMER_WAIT BIGINT unsigned," - "NESTING_EVENT_ID BIGINT unsigned," - "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT')" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME --- - -SET @cmd="CREATE TABLE performance_schema.events_stages_summary_by_thread_by_event_name(" - "THREAD_ID BIGINT unsigned not null," - "EVENT_NAME VARCHAR(128) not null," - "COUNT_STAR BIGINT unsigned not null," - "SUM_TIMER_WAIT BIGINT unsigned not null," - "MIN_TIMER_WAIT BIGINT unsigned not null," - "AVG_TIMER_WAIT BIGINT unsigned not null," - "MAX_TIMER_WAIT BIGINT unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME --- - -SET @cmd="CREATE TABLE performance_schema.events_stages_summary_by_host_by_event_name(" - "HOST CHAR(60) collate utf8_bin default null," - "EVENT_NAME VARCHAR(128) not null," - "COUNT_STAR BIGINT unsigned not null," - "SUM_TIMER_WAIT BIGINT unsigned not null," - "MIN_TIMER_WAIT BIGINT unsigned not null," - "AVG_TIMER_WAIT BIGINT unsigned not null," - "MAX_TIMER_WAIT BIGINT unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME --- - -SET @cmd="CREATE TABLE performance_schema.events_stages_summary_by_user_by_event_name(" - "USER CHAR(16) collate utf8_bin default null," - "EVENT_NAME VARCHAR(128) not null," - "COUNT_STAR BIGINT unsigned not null," - "SUM_TIMER_WAIT BIGINT unsigned not null," - "MIN_TIMER_WAIT BIGINT unsigned not null," - "AVG_TIMER_WAIT BIGINT unsigned not null," - "MAX_TIMER_WAIT BIGINT unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME --- - -SET @cmd="CREATE TABLE performance_schema.events_stages_summary_by_account_by_event_name(" - "USER CHAR(16) collate utf8_bin default null," - "HOST CHAR(60) collate utf8_bin default null," - "EVENT_NAME VARCHAR(128) not null," - "COUNT_STAR BIGINT unsigned not null," - "SUM_TIMER_WAIT BIGINT unsigned not null," - "MIN_TIMER_WAIT BIGINT unsigned not null," - "AVG_TIMER_WAIT BIGINT unsigned not null," - "MAX_TIMER_WAIT BIGINT unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE EVENTS_STAGES_SUMMARY_GLOBAL_BY_EVENT_NAME --- - -SET @cmd="CREATE TABLE performance_schema.events_stages_summary_global_by_event_name(" - "EVENT_NAME VARCHAR(128) not null," - "COUNT_STAR BIGINT unsigned not null," - "SUM_TIMER_WAIT BIGINT unsigned not null," - "MIN_TIMER_WAIT BIGINT unsigned not null," - "AVG_TIMER_WAIT BIGINT unsigned not null," - "MAX_TIMER_WAIT BIGINT unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE EVENTS_STATEMENTS_CURRENT --- - -SET @cmd="CREATE TABLE performance_schema.events_statements_current(" - "THREAD_ID BIGINT unsigned not null," - "EVENT_ID BIGINT unsigned not null," - "END_EVENT_ID BIGINT unsigned," - "EVENT_NAME VARCHAR(128) not null," - "SOURCE VARCHAR(64)," - "TIMER_START BIGINT unsigned," - "TIMER_END BIGINT unsigned," - "TIMER_WAIT BIGINT unsigned," - "LOCK_TIME bigint unsigned not null," - "SQL_TEXT LONGTEXT," - "DIGEST VARCHAR(32)," - "DIGEST_TEXT LONGTEXT," - "CURRENT_SCHEMA VARCHAR(64)," - "OBJECT_TYPE VARCHAR(64)," - "OBJECT_SCHEMA VARCHAR(64)," - "OBJECT_NAME VARCHAR(64)," - "OBJECT_INSTANCE_BEGIN BIGINT unsigned," - "MYSQL_ERRNO INTEGER," - "RETURNED_SQLSTATE VARCHAR(5)," - "MESSAGE_TEXT VARCHAR(128)," - "ERRORS BIGINT unsigned not null," - "WARNINGS BIGINT unsigned not null," - "ROWS_AFFECTED BIGINT unsigned not null," - "ROWS_SENT BIGINT unsigned not null," - "ROWS_EXAMINED BIGINT unsigned not null," - "CREATED_TMP_DISK_TABLES BIGINT unsigned not null," - "CREATED_TMP_TABLES BIGINT unsigned not null," - "SELECT_FULL_JOIN BIGINT unsigned not null," - "SELECT_FULL_RANGE_JOIN BIGINT unsigned not null," - "SELECT_RANGE BIGINT unsigned not null," - "SELECT_RANGE_CHECK BIGINT unsigned not null," - "SELECT_SCAN BIGINT unsigned not null," - "SORT_MERGE_PASSES BIGINT unsigned not null," - "SORT_RANGE BIGINT unsigned not null," - "SORT_ROWS BIGINT unsigned not null," - "SORT_SCAN BIGINT unsigned not null," - "NO_INDEX_USED BIGINT unsigned not null," - "NO_GOOD_INDEX_USED BIGINT unsigned not null," - "NESTING_EVENT_ID BIGINT unsigned," - "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT')" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE EVENTS_STATEMENTS_HISTORY --- - -SET @cmd="CREATE TABLE performance_schema.events_statements_history(" - "THREAD_ID BIGINT unsigned not null," - "EVENT_ID BIGINT unsigned not null," - "END_EVENT_ID BIGINT unsigned," - "EVENT_NAME VARCHAR(128) not null," - "SOURCE VARCHAR(64)," - "TIMER_START BIGINT unsigned," - "TIMER_END BIGINT unsigned," - "TIMER_WAIT BIGINT unsigned," - "LOCK_TIME bigint unsigned not null," - "SQL_TEXT LONGTEXT," - "DIGEST VARCHAR(32)," - "DIGEST_TEXT LONGTEXT," - "CURRENT_SCHEMA VARCHAR(64)," - "OBJECT_TYPE VARCHAR(64)," - "OBJECT_SCHEMA VARCHAR(64)," - "OBJECT_NAME VARCHAR(64)," - "OBJECT_INSTANCE_BEGIN BIGINT unsigned," - "MYSQL_ERRNO INTEGER," - "RETURNED_SQLSTATE VARCHAR(5)," - "MESSAGE_TEXT VARCHAR(128)," - "ERRORS BIGINT unsigned not null," - "WARNINGS BIGINT unsigned not null," - "ROWS_AFFECTED BIGINT unsigned not null," - "ROWS_SENT BIGINT unsigned not null," - "ROWS_EXAMINED BIGINT unsigned not null," - "CREATED_TMP_DISK_TABLES BIGINT unsigned not null," - "CREATED_TMP_TABLES BIGINT unsigned not null," - "SELECT_FULL_JOIN BIGINT unsigned not null," - "SELECT_FULL_RANGE_JOIN BIGINT unsigned not null," - "SELECT_RANGE BIGINT unsigned not null," - "SELECT_RANGE_CHECK BIGINT unsigned not null," - "SELECT_SCAN BIGINT unsigned not null," - "SORT_MERGE_PASSES BIGINT unsigned not null," - "SORT_RANGE BIGINT unsigned not null," - "SORT_ROWS BIGINT unsigned not null," - "SORT_SCAN BIGINT unsigned not null," - "NO_INDEX_USED BIGINT unsigned not null," - "NO_GOOD_INDEX_USED BIGINT unsigned not null," - "NESTING_EVENT_ID BIGINT unsigned," - "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT')" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE EVENTS_STATEMENTS_HISTORY_LONG --- - -SET @cmd="CREATE TABLE performance_schema.events_statements_history_long(" - "THREAD_ID BIGINT unsigned not null," - "EVENT_ID BIGINT unsigned not null," - "END_EVENT_ID BIGINT unsigned," - "EVENT_NAME VARCHAR(128) not null," - "SOURCE VARCHAR(64)," - "TIMER_START BIGINT unsigned," - "TIMER_END BIGINT unsigned," - "TIMER_WAIT BIGINT unsigned," - "LOCK_TIME bigint unsigned not null," - "SQL_TEXT LONGTEXT," - "DIGEST VARCHAR(32)," - "DIGEST_TEXT LONGTEXT," - "CURRENT_SCHEMA VARCHAR(64)," - "OBJECT_TYPE VARCHAR(64)," - "OBJECT_SCHEMA VARCHAR(64)," - "OBJECT_NAME VARCHAR(64)," - "OBJECT_INSTANCE_BEGIN BIGINT unsigned," - "MYSQL_ERRNO INTEGER," - "RETURNED_SQLSTATE VARCHAR(5)," - "MESSAGE_TEXT VARCHAR(128)," - "ERRORS BIGINT unsigned not null," - "WARNINGS BIGINT unsigned not null," - "ROWS_AFFECTED BIGINT unsigned not null," - "ROWS_SENT BIGINT unsigned not null," - "ROWS_EXAMINED BIGINT unsigned not null," - "CREATED_TMP_DISK_TABLES BIGINT unsigned not null," - "CREATED_TMP_TABLES BIGINT unsigned not null," - "SELECT_FULL_JOIN BIGINT unsigned not null," - "SELECT_FULL_RANGE_JOIN BIGINT unsigned not null," - "SELECT_RANGE BIGINT unsigned not null," - "SELECT_RANGE_CHECK BIGINT unsigned not null," - "SELECT_SCAN BIGINT unsigned not null," - "SORT_MERGE_PASSES BIGINT unsigned not null," - "SORT_RANGE BIGINT unsigned not null," - "SORT_ROWS BIGINT unsigned not null," - "SORT_SCAN BIGINT unsigned not null," - "NO_INDEX_USED BIGINT unsigned not null," - "NO_GOOD_INDEX_USED BIGINT unsigned not null," - "NESTING_EVENT_ID BIGINT unsigned," - "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT')" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME --- - -SET @cmd="CREATE TABLE performance_schema.events_statements_summary_by_thread_by_event_name(" - "THREAD_ID BIGINT unsigned not null," - "EVENT_NAME VARCHAR(128) not null," - "COUNT_STAR BIGINT unsigned not null," - "SUM_TIMER_WAIT BIGINT unsigned not null," - "MIN_TIMER_WAIT BIGINT unsigned not null," - "AVG_TIMER_WAIT BIGINT unsigned not null," - "MAX_TIMER_WAIT BIGINT unsigned not null," - "SUM_LOCK_TIME BIGINT unsigned not null," - "SUM_ERRORS BIGINT unsigned not null," - "SUM_WARNINGS BIGINT unsigned not null," - "SUM_ROWS_AFFECTED BIGINT unsigned not null," - "SUM_ROWS_SENT BIGINT unsigned not null," - "SUM_ROWS_EXAMINED BIGINT unsigned not null," - "SUM_CREATED_TMP_DISK_TABLES BIGINT unsigned not null," - "SUM_CREATED_TMP_TABLES BIGINT unsigned not null," - "SUM_SELECT_FULL_JOIN BIGINT unsigned not null," - "SUM_SELECT_FULL_RANGE_JOIN BIGINT unsigned not null," - "SUM_SELECT_RANGE BIGINT unsigned not null," - "SUM_SELECT_RANGE_CHECK BIGINT unsigned not null," - "SUM_SELECT_SCAN BIGINT unsigned not null," - "SUM_SORT_MERGE_PASSES BIGINT unsigned not null," - "SUM_SORT_RANGE BIGINT unsigned not null," - "SUM_SORT_ROWS BIGINT unsigned not null," - "SUM_SORT_SCAN BIGINT unsigned not null," - "SUM_NO_INDEX_USED BIGINT unsigned not null," - "SUM_NO_GOOD_INDEX_USED BIGINT unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME --- - -SET @cmd="CREATE TABLE performance_schema.events_statements_summary_by_host_by_event_name(" - "HOST CHAR(60) collate utf8_bin default null," - "EVENT_NAME VARCHAR(128) not null," - "COUNT_STAR BIGINT unsigned not null," - "SUM_TIMER_WAIT BIGINT unsigned not null," - "MIN_TIMER_WAIT BIGINT unsigned not null," - "AVG_TIMER_WAIT BIGINT unsigned not null," - "MAX_TIMER_WAIT BIGINT unsigned not null," - "SUM_LOCK_TIME BIGINT unsigned not null," - "SUM_ERRORS BIGINT unsigned not null," - "SUM_WARNINGS BIGINT unsigned not null," - "SUM_ROWS_AFFECTED BIGINT unsigned not null," - "SUM_ROWS_SENT BIGINT unsigned not null," - "SUM_ROWS_EXAMINED BIGINT unsigned not null," - "SUM_CREATED_TMP_DISK_TABLES BIGINT unsigned not null," - "SUM_CREATED_TMP_TABLES BIGINT unsigned not null," - "SUM_SELECT_FULL_JOIN BIGINT unsigned not null," - "SUM_SELECT_FULL_RANGE_JOIN BIGINT unsigned not null," - "SUM_SELECT_RANGE BIGINT unsigned not null," - "SUM_SELECT_RANGE_CHECK BIGINT unsigned not null," - "SUM_SELECT_SCAN BIGINT unsigned not null," - "SUM_SORT_MERGE_PASSES BIGINT unsigned not null," - "SUM_SORT_RANGE BIGINT unsigned not null," - "SUM_SORT_ROWS BIGINT unsigned not null," - "SUM_SORT_SCAN BIGINT unsigned not null," - "SUM_NO_INDEX_USED BIGINT unsigned not null," - "SUM_NO_GOOD_INDEX_USED BIGINT unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME --- - -SET @cmd="CREATE TABLE performance_schema.events_statements_summary_by_user_by_event_name(" - "USER CHAR(16) collate utf8_bin default null," - "EVENT_NAME VARCHAR(128) not null," - "COUNT_STAR BIGINT unsigned not null," - "SUM_TIMER_WAIT BIGINT unsigned not null," - "MIN_TIMER_WAIT BIGINT unsigned not null," - "AVG_TIMER_WAIT BIGINT unsigned not null," - "MAX_TIMER_WAIT BIGINT unsigned not null," - "SUM_LOCK_TIME BIGINT unsigned not null," - "SUM_ERRORS BIGINT unsigned not null," - "SUM_WARNINGS BIGINT unsigned not null," - "SUM_ROWS_AFFECTED BIGINT unsigned not null," - "SUM_ROWS_SENT BIGINT unsigned not null," - "SUM_ROWS_EXAMINED BIGINT unsigned not null," - "SUM_CREATED_TMP_DISK_TABLES BIGINT unsigned not null," - "SUM_CREATED_TMP_TABLES BIGINT unsigned not null," - "SUM_SELECT_FULL_JOIN BIGINT unsigned not null," - "SUM_SELECT_FULL_RANGE_JOIN BIGINT unsigned not null," - "SUM_SELECT_RANGE BIGINT unsigned not null," - "SUM_SELECT_RANGE_CHECK BIGINT unsigned not null," - "SUM_SELECT_SCAN BIGINT unsigned not null," - "SUM_SORT_MERGE_PASSES BIGINT unsigned not null," - "SUM_SORT_RANGE BIGINT unsigned not null," - "SUM_SORT_ROWS BIGINT unsigned not null," - "SUM_SORT_SCAN BIGINT unsigned not null," - "SUM_NO_INDEX_USED BIGINT unsigned not null," - "SUM_NO_GOOD_INDEX_USED BIGINT unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME --- - -SET @cmd="CREATE TABLE performance_schema.events_statements_summary_by_account_by_event_name(" - "USER CHAR(16) collate utf8_bin default null," - "HOST CHAR(60) collate utf8_bin default null," - "EVENT_NAME VARCHAR(128) not null," - "COUNT_STAR BIGINT unsigned not null," - "SUM_TIMER_WAIT BIGINT unsigned not null," - "MIN_TIMER_WAIT BIGINT unsigned not null," - "AVG_TIMER_WAIT BIGINT unsigned not null," - "MAX_TIMER_WAIT BIGINT unsigned not null," - "SUM_LOCK_TIME BIGINT unsigned not null," - "SUM_ERRORS BIGINT unsigned not null," - "SUM_WARNINGS BIGINT unsigned not null," - "SUM_ROWS_AFFECTED BIGINT unsigned not null," - "SUM_ROWS_SENT BIGINT unsigned not null," - "SUM_ROWS_EXAMINED BIGINT unsigned not null," - "SUM_CREATED_TMP_DISK_TABLES BIGINT unsigned not null," - "SUM_CREATED_TMP_TABLES BIGINT unsigned not null," - "SUM_SELECT_FULL_JOIN BIGINT unsigned not null," - "SUM_SELECT_FULL_RANGE_JOIN BIGINT unsigned not null," - "SUM_SELECT_RANGE BIGINT unsigned not null," - "SUM_SELECT_RANGE_CHECK BIGINT unsigned not null," - "SUM_SELECT_SCAN BIGINT unsigned not null," - "SUM_SORT_MERGE_PASSES BIGINT unsigned not null," - "SUM_SORT_RANGE BIGINT unsigned not null," - "SUM_SORT_ROWS BIGINT unsigned not null," - "SUM_SORT_SCAN BIGINT unsigned not null," - "SUM_NO_INDEX_USED BIGINT unsigned not null," - "SUM_NO_GOOD_INDEX_USED BIGINT unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME --- - -SET @cmd="CREATE TABLE performance_schema.events_statements_summary_global_by_event_name(" - "EVENT_NAME VARCHAR(128) not null," - "COUNT_STAR BIGINT unsigned not null," - "SUM_TIMER_WAIT BIGINT unsigned not null," - "MIN_TIMER_WAIT BIGINT unsigned not null," - "AVG_TIMER_WAIT BIGINT unsigned not null," - "MAX_TIMER_WAIT BIGINT unsigned not null," - "SUM_LOCK_TIME BIGINT unsigned not null," - "SUM_ERRORS BIGINT unsigned not null," - "SUM_WARNINGS BIGINT unsigned not null," - "SUM_ROWS_AFFECTED BIGINT unsigned not null," - "SUM_ROWS_SENT BIGINT unsigned not null," - "SUM_ROWS_EXAMINED BIGINT unsigned not null," - "SUM_CREATED_TMP_DISK_TABLES BIGINT unsigned not null," - "SUM_CREATED_TMP_TABLES BIGINT unsigned not null," - "SUM_SELECT_FULL_JOIN BIGINT unsigned not null," - "SUM_SELECT_FULL_RANGE_JOIN BIGINT unsigned not null," - "SUM_SELECT_RANGE BIGINT unsigned not null," - "SUM_SELECT_RANGE_CHECK BIGINT unsigned not null," - "SUM_SELECT_SCAN BIGINT unsigned not null," - "SUM_SORT_MERGE_PASSES BIGINT unsigned not null," - "SUM_SORT_RANGE BIGINT unsigned not null," - "SUM_SORT_ROWS BIGINT unsigned not null," - "SUM_SORT_SCAN BIGINT unsigned not null," - "SUM_NO_INDEX_USED BIGINT unsigned not null," - "SUM_NO_GOOD_INDEX_USED BIGINT unsigned not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE HOSTS --- - -SET @cmd="CREATE TABLE performance_schema.hosts(" - "HOST CHAR(60) collate utf8_bin default null," - "CURRENT_CONNECTIONS bigint not null," - "TOTAL_CONNECTIONS bigint not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE USERS --- - -SET @cmd="CREATE TABLE performance_schema.users(" - "USER CHAR(16) collate utf8_bin default null," - "CURRENT_CONNECTIONS bigint not null," - "TOTAL_CONNECTIONS bigint not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE ACCOUNTS --- - -SET @cmd="CREATE TABLE performance_schema.accounts(" - "USER CHAR(16) collate utf8_bin default null," - "HOST CHAR(60) collate utf8_bin default null," - "CURRENT_CONNECTIONS bigint not null," - "TOTAL_CONNECTIONS bigint not null" - ")ENGINE=PERFORMANCE_SCHEMA;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE EVENTS_STATEMENTS_SUMMARY_BY_DIGEST --- - -SET @cmd="CREATE TABLE performance_schema.events_statements_summary_by_digest(" - "SCHEMA_NAME VARCHAR(64)," - "DIGEST VARCHAR(32)," - "DIGEST_TEXT LONGTEXT," - "COUNT_STAR BIGINT unsigned not null," - "SUM_TIMER_WAIT BIGINT unsigned not null," - "MIN_TIMER_WAIT BIGINT unsigned not null," - "AVG_TIMER_WAIT BIGINT unsigned not null," - "MAX_TIMER_WAIT BIGINT unsigned not null," - "SUM_LOCK_TIME BIGINT unsigned not null," - "SUM_ERRORS BIGINT unsigned not null," - "SUM_WARNINGS BIGINT unsigned not null," - "SUM_ROWS_AFFECTED BIGINT unsigned not null," - "SUM_ROWS_SENT BIGINT unsigned not null," - "SUM_ROWS_EXAMINED BIGINT unsigned not null," - "SUM_CREATED_TMP_DISK_TABLES BIGINT unsigned not null," - "SUM_CREATED_TMP_TABLES BIGINT unsigned not null," - "SUM_SELECT_FULL_JOIN BIGINT unsigned not null," - "SUM_SELECT_FULL_RANGE_JOIN BIGINT unsigned not null," - "SUM_SELECT_RANGE BIGINT unsigned not null," - "SUM_SELECT_RANGE_CHECK BIGINT unsigned not null," - "SUM_SELECT_SCAN BIGINT unsigned not null," - "SUM_SORT_MERGE_PASSES BIGINT unsigned not null," - "SUM_SORT_RANGE BIGINT unsigned not null," - "SUM_SORT_ROWS BIGINT unsigned not null," - "SUM_SORT_SCAN BIGINT unsigned not null," - "SUM_NO_INDEX_USED BIGINT unsigned not null," - "SUM_NO_GOOD_INDEX_USED BIGINT unsigned not null," - "FIRST_SEEN TIMESTAMP(0) NOT NULL default 0," - "LAST_SEEN TIMESTAMP(0) NOT NULL default 0" - ")ENGINE=PERFORMANCE_SCHEMA;"; - - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE SESSION_CONNECT_ATTRS --- - -SET @cmd="CREATE TABLE performance_schema.session_connect_attrs(" - "PROCESSLIST_ID INT NOT NULL," - "ATTR_NAME VARCHAR(32) NOT NULL," - "ATTR_VALUE VARCHAR(1024)," - "ORDINAL_POSITION INT" - ")ENGINE=PERFORMANCE_SCHEMA CHARACTER SET utf8 COLLATE utf8_bin;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; - --- --- TABLE SESSION_ACCOUNT_CONNECT_ATTRS --- - -SET @cmd="CREATE TABLE performance_schema.session_account_connect_attrs " - " LIKE performance_schema.session_connect_attrs;"; - -SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0'); -PREPARE stmt FROM @str; -EXECUTE stmt; -DROP PREPARE stmt; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index e420a70b33f..57d2cc6922d 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5452,14 +5452,6 @@ int mysqld_main(int argc, char **argv) #ifdef WITH_PERFSCHEMA_STORAGE_ENGINE initialize_performance_schema_acl(opt_bootstrap); - /* - Do not check the structure of the performance schema tables - during bootstrap: - - the tables are not supposed to exist yet, bootstrap will create them - - a check would print spurious error messages - */ - if (! opt_bootstrap) - check_performance_schema(); #endif initialize_information_schema_acl(); diff --git a/storage/perfschema/CMakeLists.txt b/storage/perfschema/CMakeLists.txt index 718baa8296b..b77cae6d018 100644 --- a/storage/perfschema/CMakeLists.txt +++ b/storage/perfschema/CMakeLists.txt @@ -131,7 +131,6 @@ pfs.cc pfs_account.cc pfs_atomic.cc pfs_autosize.cc -pfs_check.cc pfs_column_values.cc pfs_con_slice.cc pfs_defaults.cc diff --git a/storage/perfschema/ha_perfschema.cc b/storage/perfschema/ha_perfschema.cc index 58db8dc0031..8d41ff1711d 100644 --- a/storage/perfschema/ha_perfschema.cc +++ b/storage/perfschema/ha_perfschema.cc @@ -71,6 +71,23 @@ find_table_share(const char *db, const char *name) DBUG_RETURN(result); } +static int pfs_discover_table(handlerton *hton, THD *thd, TABLE_SHARE *share) +{ + const PFS_engine_table_share *pfs_share; + + if ((pfs_share= find_table_share(share->db.str, share->table_name.str))) + return share->init_from_sql_statement_string(thd, false, + pfs_share->sql.str, + pfs_share->sql.length); + return HA_ERR_NO_SUCH_TABLE; +} + +static int pfs_discover_table_existence(handlerton *hton, const char *db, + const char *table_name) +{ + return MY_TEST(find_table_share(db, table_name)); +} + static int pfs_init_func(void *p) { DBUG_ENTER("pfs_init_func"); @@ -99,6 +116,9 @@ static int pfs_init_func(void *p) the performance schema. See Bug#43039. */ pfs_hton->db_type= DB_TYPE_PERFORMANCE_SCHEMA; + pfs_hton->discover_table= pfs_discover_table; + pfs_hton->discover_table_existence= pfs_discover_table_existence; + pfs_hton->discover_table_names= pfs_discover_table_names; PFS_engine_table_share::init_all_locks(); @@ -438,25 +458,10 @@ int ha_perfschema::create(const char *name, TABLE *table_arg, HA_CREATE_INFO *create_info) { DBUG_ENTER("ha_perfschema::create"); - DBUG_ASSERT(table_arg); - DBUG_ASSERT(table_arg->s); - if (find_table_share(table_arg->s->db.str, - table_arg->s->table_name.str)) - { - /* - Attempting to create a known performance schema table. - Allowing the create, to create .FRM files, - for the initial database install, and mysql_upgrade. - This should fail once .FRM are removed. - */ - DBUG_RETURN(0); - } /* This is not a general purpose engine. Failure to CREATE TABLE is the expected result. */ - DBUG_PRINT("error", ("unknown table: %s.%s", table_arg->s->db.str, - table_arg->s->table_name.str)); DBUG_RETURN(HA_ERR_WRONG_COMMAND); } diff --git a/storage/perfschema/pfs_check.cc b/storage/perfschema/pfs_check.cc deleted file mode 100644 index c8800e7ec96..00000000000 --- a/storage/perfschema/pfs_check.cc +++ /dev/null @@ -1,62 +0,0 @@ -/* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ - -/** - @file storage/perfschema/pfs_check.cc - Check the performance schema table structure. - The code in this file is implemented in pfs_check.cc - instead of pfs_server.cc, to separate dependencies to server - structures (THD, ...) in a dedicated file. - This code organization helps a lot maintenance of the unit tests. -*/ - -#include "my_global.h" -#include "pfs_server.h" -#include "pfs_engine_table.h" - -/* -*/ - -/** - Check that the performance schema tables - have the expected structure. - Discrepancies are written in the server log, - but are not considered fatal, so this function does not - return an error code: - - some differences are compatible, and should not cause a failure - - some differences are not compatible, but then the DBA needs an operational - server to be able to DROP+CREATE the tables with the proper structure, - as part of the initial server installation or during an upgrade. - In case of discrepancies, later attempt to perform DML against - the performance schema will be rejected with an error. -*/ -void check_performance_schema() -{ - DBUG_ENTER("check_performance_schema"); - - THD *thd= new THD(); - if (thd == NULL) - DBUG_VOID_RETURN; - - thd->thread_stack= (char*) &thd; - thd->store_globals(); - - PFS_engine_table_share::check_all_tables(thd); - - thd->reset_globals(); - delete thd; - DBUG_VOID_RETURN; -} - diff --git a/storage/perfschema/pfs_engine_table.cc b/storage/perfschema/pfs_engine_table.cc index 958a2bdd7bd..c132f82f681 100644 --- a/storage/perfschema/pfs_engine_table.cc +++ b/storage/perfschema/pfs_engine_table.cc @@ -151,91 +151,6 @@ static PFS_engine_table_share *all_shares[]= NULL }; -/** - Check all the tables structure. - @param thd current thread -*/ -void PFS_engine_table_share::check_all_tables(THD *thd) -{ - PFS_engine_table_share **current; - - DBUG_EXECUTE_IF("tampered_perfschema_table1", - { - /* Hack SETUP_INSTRUMENT, incompatible change. */ - all_shares[20]->m_field_def->count++; - }); - - for (current= &all_shares[0]; (*current) != NULL; current++) - (*current)->check_one_table(thd); -} - -/** Error reporting for schema integrity checks. */ -class PFS_check_intact : public Table_check_intact -{ -protected: - virtual void report_error(uint code, const char *fmt, ...); - -public: - PFS_check_intact() - {} - - ~PFS_check_intact() - {} -}; - -void PFS_check_intact::report_error(uint code, const char *fmt, ...) -{ - va_list args; - char buff[MYSQL_ERRMSG_SIZE]; - - va_start(args, fmt); - my_vsnprintf(buff, sizeof(buff), fmt, args); - va_end(args); - - /* - This is an install/upgrade issue: - - do not report it in the user connection, there is none in main(), - - report it in the server error log. - */ - sql_print_error("%s", buff); -} - -/** - Check integrity of the actual table schema. - The actual table schema (.frm) is compared to the expected schema. - @param thd current thread -*/ -void PFS_engine_table_share::check_one_table(THD *thd) -{ - TABLE_LIST tables; - - tables.init_one_table(PERFORMANCE_SCHEMA_str.str, - PERFORMANCE_SCHEMA_str.length, - m_name.str, m_name.length, - m_name.str, TL_READ); - - /* Work around until Bug#32115 is backported. */ - LEX dummy_lex; - LEX *old_lex= thd->lex; - thd->lex= &dummy_lex; - lex_start(thd); - - if (! open_and_lock_tables(thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) - { - PFS_check_intact checker; - - if (!checker.check(tables.table, m_field_def)) - m_checked= true; - close_thread_tables(thd); - } - else - sql_print_error(ER(ER_WRONG_NATIVE_TABLE_STRUCTURE), - PERFORMANCE_SCHEMA_str.str, m_name.str); - - lex_end(&dummy_lex); - thd->lex= old_lex; -} - /** Initialize all the table share locks. */ void PFS_engine_table_share::init_all_locks(void) { @@ -268,15 +183,6 @@ int PFS_engine_table_share::write_row(TABLE *table, unsigned char *buf, { my_bitmap_map *org_bitmap; - /* - Make sure the table structure is as expected before mapping - hard wired columns in m_write_row. - */ - if (! m_checked) - { - return HA_ERR_TABLE_NEEDS_UPGRADE; - } - if (m_write_row == NULL) { return HA_ERR_WRONG_COMMAND; @@ -347,15 +253,6 @@ int PFS_engine_table::read_row(TABLE *table, Field *f; Field **fields_reset; - /* - Make sure the table structure is as expected before mapping - hard wired columns in read_row_values. - */ - if (! m_share_ptr->m_checked) - { - return HA_ERR_TABLE_NEEDS_UPGRADE; - } - /* We must read all columns in case a table is opened for update */ bool read_all= !bitmap_is_clear_all(table->write_set); @@ -392,15 +289,6 @@ int PFS_engine_table::update_row(TABLE *table, { my_bitmap_map *org_bitmap; - /* - Make sure the table structure is as expected before mapping - hard wired columns in update_row_values. - */ - if (! m_share_ptr->m_checked) - { - return HA_ERR_TABLE_NEEDS_UPGRADE; - } - /* We internally read from Fields to support the write interface */ org_bitmap= dbug_tmp_use_all_columns(table, table->read_set); int result= update_row_values(table, old_buf, new_buf, fields); @@ -415,15 +303,6 @@ int PFS_engine_table::delete_row(TABLE *table, { my_bitmap_map *org_bitmap; - /* - Make sure the table structure is as expected before mapping - hard wired columns in delete_row_values. - */ - if (! m_share_ptr->m_checked) - { - return HA_ERR_TABLE_NEEDS_UPGRADE; - } - /* We internally read from Fields to support the delete interface */ org_bitmap= dbug_tmp_use_all_columns(table, table->read_set); int result= delete_row_values(table, buf, fields); @@ -1440,5 +1319,18 @@ end: DBUG_RETURN(false); } +int pfs_discover_table_names(handlerton *hton __attribute__((unused)), + LEX_STRING *db, + MY_DIR *dir __attribute__((unused)), + handlerton::discovered_list *result) +{ + if (compare_table_names(db->str, PERFORMANCE_SCHEMA_str.str)) + return 0; + for (size_t i= 0; i < array_elements(all_shares) - 1; i++) + result->add_table(all_shares[i]->m_name.str, + all_shares[i]->m_name.length); + return 0; +} + /** @} */ diff --git a/storage/perfschema/pfs_engine_table.h b/storage/perfschema/pfs_engine_table.h index 981d72ee19e..2bbf8891420 100644 --- a/storage/perfschema/pfs_engine_table.h +++ b/storage/perfschema/pfs_engine_table.h @@ -212,8 +212,6 @@ typedef ha_rows (*pfs_get_row_count_t)(void); */ struct PFS_engine_table_share { - static void check_all_tables(THD *thd); - void check_one_table(THD *thd); static void init_all_locks(void); static void delete_all_locks(void); /** Get the row count. */ @@ -244,10 +242,8 @@ struct PFS_engine_table_share uint m_ref_length; /** The lock, stored on behalf of the SQL layer. */ THR_LOCK *m_thr_lock_ptr; - /** Table fields definition. */ - TABLE_FIELD_DEF *m_field_def; - /** Schema integrity flag. */ - bool m_checked; + /** Table definition. */ + LEX_STRING sql; }; /** @@ -461,5 +457,9 @@ struct PFS_triple_index bool pfs_show_status(handlerton *hton, THD *thd, stat_print_fn *print, enum ha_stat_type stat); +int pfs_discover_table_names(handlerton *hton, LEX_STRING *db, + MY_DIR *dir, + handlerton::discovered_list *result); + /** @} */ #endif diff --git a/storage/perfschema/pfs_server.h b/storage/perfschema/pfs_server.h index 606a814c168..83e0d3ba9fa 100644 --- a/storage/perfschema/pfs_server.h +++ b/storage/perfschema/pfs_server.h @@ -231,8 +231,6 @@ void pfs_automated_sizing(PFS_global_param *param); */ void initialize_performance_schema_acl(bool bootstrap); -void check_performance_schema(); - /** Initialize the dynamic array holding individual instrument settings collected from the server configuration options. diff --git a/storage/perfschema/table_accounts.cc b/storage/perfschema/table_accounts.cc index eb14a0fe481..be18e0b7ce8 100644 --- a/storage/perfschema/table_accounts.cc +++ b/storage/perfschema/table_accounts.cc @@ -23,34 +23,6 @@ THR_LOCK table_accounts::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("USER") }, - { C_STRING_WITH_LEN("char(16)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("HOST") }, - { C_STRING_WITH_LEN("char(60)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("CURRENT_CONNECTIONS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("TOTAL_CONNECTIONS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_accounts::m_field_def= -{ 4, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_accounts::m_share= { @@ -63,8 +35,11 @@ table_accounts::m_share= 1000, /* records */ sizeof(PFS_simple_index), /* ref length */ &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE accounts(" + "USER CHAR(16) collate utf8_bin default null," + "HOST CHAR(60) collate utf8_bin default null," + "CURRENT_CONNECTIONS bigint not null," + "TOTAL_CONNECTIONS bigint not null)") } }; PFS_engine_table* table_accounts::create() diff --git a/storage/perfschema/table_accounts.h b/storage/perfschema/table_accounts.h index 232cb9d9b36..4c1932641d2 100644 --- a/storage/perfschema/table_accounts.h +++ b/storage/perfschema/table_accounts.h @@ -67,8 +67,6 @@ private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_accounts m_row; diff --git a/storage/perfschema/table_esgs_by_account_by_event_name.cc b/storage/perfschema/table_esgs_by_account_by_event_name.cc index 4f0fc6858f9..a565cbb49bd 100644 --- a/storage/perfschema/table_esgs_by_account_by_event_name.cc +++ b/storage/perfschema/table_esgs_by_account_by_event_name.cc @@ -29,54 +29,6 @@ THR_LOCK table_esgs_by_account_by_event_name::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("USER") }, - { C_STRING_WITH_LEN("char(16)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("HOST") }, - { C_STRING_WITH_LEN("char(60)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_STAR") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_esgs_by_account_by_event_name::m_field_def= -{ 8, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_esgs_by_account_by_event_name::m_share= { @@ -89,8 +41,15 @@ table_esgs_by_account_by_event_name::m_share= 1000, /* records */ sizeof(pos_esgs_by_account_by_event_name), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE events_stages_summary_by_account_by_event_name(" + "USER CHAR(16) collate utf8_bin default null," + "HOST CHAR(60) collate utf8_bin default null," + "EVENT_NAME VARCHAR(128) not null," + "COUNT_STAR BIGINT unsigned not null," + "SUM_TIMER_WAIT BIGINT unsigned not null," + "MIN_TIMER_WAIT BIGINT unsigned not null," + "AVG_TIMER_WAIT BIGINT unsigned not null," + "MAX_TIMER_WAIT BIGINT unsigned not null)") } }; PFS_engine_table* diff --git a/storage/perfschema/table_esgs_by_account_by_event_name.h b/storage/perfschema/table_esgs_by_account_by_event_name.h index 2cd51783db1..531c4874557 100644 --- a/storage/perfschema/table_esgs_by_account_by_event_name.h +++ b/storage/perfschema/table_esgs_by_account_by_event_name.h @@ -108,8 +108,6 @@ protected: private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_esgs_by_account_by_event_name m_row; diff --git a/storage/perfschema/table_esgs_by_host_by_event_name.cc b/storage/perfschema/table_esgs_by_host_by_event_name.cc index 904f0e21b3c..76e60b32a80 100644 --- a/storage/perfschema/table_esgs_by_host_by_event_name.cc +++ b/storage/perfschema/table_esgs_by_host_by_event_name.cc @@ -30,49 +30,6 @@ THR_LOCK table_esgs_by_host_by_event_name::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("HOST") }, - { C_STRING_WITH_LEN("char(60)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_STAR") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_esgs_by_host_by_event_name::m_field_def= -{ 7, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_esgs_by_host_by_event_name::m_share= { @@ -85,8 +42,14 @@ table_esgs_by_host_by_event_name::m_share= 1000, /* records */ sizeof(pos_esgs_by_host_by_event_name), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE events_stages_summary_by_host_by_event_name(" + "HOST CHAR(60) collate utf8_bin default null," + "EVENT_NAME VARCHAR(128) not null," + "COUNT_STAR BIGINT unsigned not null," + "SUM_TIMER_WAIT BIGINT unsigned not null," + "MIN_TIMER_WAIT BIGINT unsigned not null," + "AVG_TIMER_WAIT BIGINT unsigned not null," + "MAX_TIMER_WAIT BIGINT unsigned not null)") } }; PFS_engine_table* diff --git a/storage/perfschema/table_esgs_by_host_by_event_name.h b/storage/perfschema/table_esgs_by_host_by_event_name.h index a8404e11e93..59a16c24828 100644 --- a/storage/perfschema/table_esgs_by_host_by_event_name.h +++ b/storage/perfschema/table_esgs_by_host_by_event_name.h @@ -108,8 +108,6 @@ protected: private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_esgs_by_host_by_event_name m_row; diff --git a/storage/perfschema/table_esgs_by_thread_by_event_name.cc b/storage/perfschema/table_esgs_by_thread_by_event_name.cc index 8a4d67695fa..4fde6013ade 100644 --- a/storage/perfschema/table_esgs_by_thread_by_event_name.cc +++ b/storage/perfschema/table_esgs_by_thread_by_event_name.cc @@ -29,49 +29,6 @@ THR_LOCK table_esgs_by_thread_by_event_name::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("THREAD_ID") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_STAR") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_esgs_by_thread_by_event_name::m_field_def= -{ 7, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_esgs_by_thread_by_event_name::m_share= { @@ -84,8 +41,14 @@ table_esgs_by_thread_by_event_name::m_share= 1000, /* records */ sizeof(pos_esgs_by_thread_by_event_name), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE events_stages_summary_by_thread_by_event_name(" + "THREAD_ID BIGINT unsigned not null," + "EVENT_NAME VARCHAR(128) not null," + "COUNT_STAR BIGINT unsigned not null," + "SUM_TIMER_WAIT BIGINT unsigned not null," + "MIN_TIMER_WAIT BIGINT unsigned not null," + "AVG_TIMER_WAIT BIGINT unsigned not null," + "MAX_TIMER_WAIT BIGINT unsigned not null)") } }; PFS_engine_table* diff --git a/storage/perfschema/table_esgs_by_thread_by_event_name.h b/storage/perfschema/table_esgs_by_thread_by_event_name.h index 5295a9eacdf..38c6d667d28 100644 --- a/storage/perfschema/table_esgs_by_thread_by_event_name.h +++ b/storage/perfschema/table_esgs_by_thread_by_event_name.h @@ -112,8 +112,6 @@ protected: private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_esgs_by_thread_by_event_name m_row; diff --git a/storage/perfschema/table_esgs_by_user_by_event_name.cc b/storage/perfschema/table_esgs_by_user_by_event_name.cc index 736559dd5e2..cdb7ed651a8 100644 --- a/storage/perfschema/table_esgs_by_user_by_event_name.cc +++ b/storage/perfschema/table_esgs_by_user_by_event_name.cc @@ -30,49 +30,6 @@ THR_LOCK table_esgs_by_user_by_event_name::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("USER") }, - { C_STRING_WITH_LEN("char(16)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_STAR") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_esgs_by_user_by_event_name::m_field_def= -{ 7, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_esgs_by_user_by_event_name::m_share= { @@ -85,8 +42,14 @@ table_esgs_by_user_by_event_name::m_share= 1000, /* records */ sizeof(pos_esgs_by_user_by_event_name), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE events_stages_summary_by_user_by_event_name(" + "USER CHAR(16) collate utf8_bin default null," + "EVENT_NAME VARCHAR(128) not null," + "COUNT_STAR BIGINT unsigned not null," + "SUM_TIMER_WAIT BIGINT unsigned not null," + "MIN_TIMER_WAIT BIGINT unsigned not null," + "AVG_TIMER_WAIT BIGINT unsigned not null," + "MAX_TIMER_WAIT BIGINT unsigned not null)") } }; PFS_engine_table* diff --git a/storage/perfschema/table_esgs_by_user_by_event_name.h b/storage/perfschema/table_esgs_by_user_by_event_name.h index 9fc66033caa..3e1a03bd7f1 100644 --- a/storage/perfschema/table_esgs_by_user_by_event_name.h +++ b/storage/perfschema/table_esgs_by_user_by_event_name.h @@ -113,8 +113,6 @@ protected: private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_esgs_by_user_by_event_name m_row; diff --git a/storage/perfschema/table_esgs_global_by_event_name.cc b/storage/perfschema/table_esgs_global_by_event_name.cc index 1dea1f8aceb..0d59940f4ea 100644 --- a/storage/perfschema/table_esgs_global_by_event_name.cc +++ b/storage/perfschema/table_esgs_global_by_event_name.cc @@ -31,44 +31,6 @@ THR_LOCK table_esgs_global_by_event_name::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_STAR") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_esgs_global_by_event_name::m_field_def= -{ 6, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_esgs_global_by_event_name::m_share= { @@ -81,8 +43,13 @@ table_esgs_global_by_event_name::m_share= 1000, /* records */ sizeof(PFS_simple_index), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE events_stages_summary_global_by_event_name(" + "EVENT_NAME VARCHAR(128) not null," + "COUNT_STAR BIGINT unsigned not null," + "SUM_TIMER_WAIT BIGINT unsigned not null," + "MIN_TIMER_WAIT BIGINT unsigned not null," + "AVG_TIMER_WAIT BIGINT unsigned not null," + "MAX_TIMER_WAIT BIGINT unsigned not null)") } }; PFS_engine_table* diff --git a/storage/perfschema/table_esgs_global_by_event_name.h b/storage/perfschema/table_esgs_global_by_event_name.h index a9c1456e9b1..e6e23bf4515 100644 --- a/storage/perfschema/table_esgs_global_by_event_name.h +++ b/storage/perfschema/table_esgs_global_by_event_name.h @@ -76,8 +76,6 @@ protected: private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_esgs_global_by_event_name m_row; diff --git a/storage/perfschema/table_esms_by_account_by_event_name.cc b/storage/perfschema/table_esms_by_account_by_event_name.cc index 436056ef30b..b08c68a7000 100644 --- a/storage/perfschema/table_esms_by_account_by_event_name.cc +++ b/storage/perfschema/table_esms_by_account_by_event_name.cc @@ -29,149 +29,6 @@ THR_LOCK table_esms_by_account_by_event_name::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("USER") }, - { C_STRING_WITH_LEN("char(16)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("HOST") }, - { C_STRING_WITH_LEN("char(60)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_STAR") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_LOCK_TIME") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_WARNINGS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_ROWS_AFFECTED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_ROWS_SENT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_ROWS_EXAMINED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_CREATED_TMP_DISK_TABLES") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_CREATED_TMP_TABLES") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_FULL_JOIN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_FULL_RANGE_JOIN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_RANGE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_RANGE_CHECK") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_SCAN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SORT_MERGE_PASSES") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SORT_RANGE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SORT_ROWS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SORT_SCAN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_NO_INDEX_USED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_NO_GOOD_INDEX_USED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_esms_by_account_by_event_name::m_field_def= -{ 27, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_esms_by_account_by_event_name::m_share= { @@ -184,8 +41,34 @@ table_esms_by_account_by_event_name::m_share= 1000, /* records */ sizeof(pos_esms_by_account_by_event_name), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE events_statements_summary_by_account_by_event_name(" + "USER CHAR(16) collate utf8_bin default null," + "HOST CHAR(60) collate utf8_bin default null," + "EVENT_NAME VARCHAR(128) not null," + "COUNT_STAR BIGINT unsigned not null," + "SUM_TIMER_WAIT BIGINT unsigned not null," + "MIN_TIMER_WAIT BIGINT unsigned not null," + "AVG_TIMER_WAIT BIGINT unsigned not null," + "MAX_TIMER_WAIT BIGINT unsigned not null," + "SUM_LOCK_TIME BIGINT unsigned not null," + "SUM_ERRORS BIGINT unsigned not null," + "SUM_WARNINGS BIGINT unsigned not null," + "SUM_ROWS_AFFECTED BIGINT unsigned not null," + "SUM_ROWS_SENT BIGINT unsigned not null," + "SUM_ROWS_EXAMINED BIGINT unsigned not null," + "SUM_CREATED_TMP_DISK_TABLES BIGINT unsigned not null," + "SUM_CREATED_TMP_TABLES BIGINT unsigned not null," + "SUM_SELECT_FULL_JOIN BIGINT unsigned not null," + "SUM_SELECT_FULL_RANGE_JOIN BIGINT unsigned not null," + "SUM_SELECT_RANGE BIGINT unsigned not null," + "SUM_SELECT_RANGE_CHECK BIGINT unsigned not null," + "SUM_SELECT_SCAN BIGINT unsigned not null," + "SUM_SORT_MERGE_PASSES BIGINT unsigned not null," + "SUM_SORT_RANGE BIGINT unsigned not null," + "SUM_SORT_ROWS BIGINT unsigned not null," + "SUM_SORT_SCAN BIGINT unsigned not null," + "SUM_NO_INDEX_USED BIGINT unsigned not null," + "SUM_NO_GOOD_INDEX_USED BIGINT unsigned not null)") } }; PFS_engine_table* diff --git a/storage/perfschema/table_esms_by_account_by_event_name.h b/storage/perfschema/table_esms_by_account_by_event_name.h index 23168d03cd3..4e3097ef363 100644 --- a/storage/perfschema/table_esms_by_account_by_event_name.h +++ b/storage/perfschema/table_esms_by_account_by_event_name.h @@ -108,8 +108,6 @@ protected: private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_esms_by_account_by_event_name m_row; diff --git a/storage/perfschema/table_esms_by_digest.cc b/storage/perfschema/table_esms_by_digest.cc index 80fa4077281..88860a77c5d 100644 --- a/storage/perfschema/table_esms_by_digest.cc +++ b/storage/perfschema/table_esms_by_digest.cc @@ -33,159 +33,6 @@ THR_LOCK table_esms_by_digest::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("SCHEMA_NAME") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("DIGEST") }, - { C_STRING_WITH_LEN("varchar(32)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("DIGEST_TEXT") }, - { C_STRING_WITH_LEN("longtext") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_STAR") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_LOCK_TIME") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_WARNINGS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_ROWS_AFFECTED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_ROWS_SENT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_ROWS_EXAMINED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_CREATED_TMP_DISK_TABLES") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_CREATED_TMP_TABLES") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_FULL_JOIN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_FULL_RANGE_JOIN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_RANGE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_RANGE_CHECK") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_SCAN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SORT_MERGE_PASSES") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SORT_RANGE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SORT_ROWS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SORT_SCAN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_NO_INDEX_USED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_NO_GOOD_INDEX_USED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("FIRST_SEEN") }, - { C_STRING_WITH_LEN("timestamp") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("LAST_SEEN") }, - { C_STRING_WITH_LEN("timestamp") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_esms_by_digest::m_field_def= -{ 29, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_esms_by_digest::m_share= { @@ -198,8 +45,36 @@ table_esms_by_digest::m_share= 1000, /* records */ sizeof(PFS_simple_index), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE events_statements_summary_by_digest(" + "SCHEMA_NAME VARCHAR(64)," + "DIGEST VARCHAR(32)," + "DIGEST_TEXT LONGTEXT," + "COUNT_STAR BIGINT unsigned not null," + "SUM_TIMER_WAIT BIGINT unsigned not null," + "MIN_TIMER_WAIT BIGINT unsigned not null," + "AVG_TIMER_WAIT BIGINT unsigned not null," + "MAX_TIMER_WAIT BIGINT unsigned not null," + "SUM_LOCK_TIME BIGINT unsigned not null," + "SUM_ERRORS BIGINT unsigned not null," + "SUM_WARNINGS BIGINT unsigned not null," + "SUM_ROWS_AFFECTED BIGINT unsigned not null," + "SUM_ROWS_SENT BIGINT unsigned not null," + "SUM_ROWS_EXAMINED BIGINT unsigned not null," + "SUM_CREATED_TMP_DISK_TABLES BIGINT unsigned not null," + "SUM_CREATED_TMP_TABLES BIGINT unsigned not null," + "SUM_SELECT_FULL_JOIN BIGINT unsigned not null," + "SUM_SELECT_FULL_RANGE_JOIN BIGINT unsigned not null," + "SUM_SELECT_RANGE BIGINT unsigned not null," + "SUM_SELECT_RANGE_CHECK BIGINT unsigned not null," + "SUM_SELECT_SCAN BIGINT unsigned not null," + "SUM_SORT_MERGE_PASSES BIGINT unsigned not null," + "SUM_SORT_RANGE BIGINT unsigned not null," + "SUM_SORT_ROWS BIGINT unsigned not null," + "SUM_SORT_SCAN BIGINT unsigned not null," + "SUM_NO_INDEX_USED BIGINT unsigned not null," + "SUM_NO_GOOD_INDEX_USED BIGINT unsigned not null," + "FIRST_SEEN TIMESTAMP(0) NOT NULL default 0," + "LAST_SEEN TIMESTAMP(0) NOT NULL default 0)") } }; PFS_engine_table* diff --git a/storage/perfschema/table_esms_by_digest.h b/storage/perfschema/table_esms_by_digest.h index 5df8ec69633..196a89fcd09 100644 --- a/storage/perfschema/table_esms_by_digest.h +++ b/storage/perfschema/table_esms_by_digest.h @@ -78,8 +78,6 @@ protected: private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_esms_by_digest m_row; diff --git a/storage/perfschema/table_esms_by_host_by_event_name.cc b/storage/perfschema/table_esms_by_host_by_event_name.cc index 2cbe70d5ae4..78381cc8a4f 100644 --- a/storage/perfschema/table_esms_by_host_by_event_name.cc +++ b/storage/perfschema/table_esms_by_host_by_event_name.cc @@ -30,144 +30,6 @@ THR_LOCK table_esms_by_host_by_event_name::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("HOST") }, - { C_STRING_WITH_LEN("char(60)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_STAR") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_LOCK_TIME") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_WARNINGS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_ROWS_AFFECTED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_ROWS_SENT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_ROWS_EXAMINED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_CREATED_TMP_DISK_TABLES") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_CREATED_TMP_TABLES") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_FULL_JOIN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_FULL_RANGE_JOIN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_RANGE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_RANGE_CHECK") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_SCAN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SORT_MERGE_PASSES") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SORT_RANGE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SORT_ROWS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SORT_SCAN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_NO_INDEX_USED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_NO_GOOD_INDEX_USED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_esms_by_host_by_event_name::m_field_def= -{ 26, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_esms_by_host_by_event_name::m_share= { @@ -180,8 +42,33 @@ table_esms_by_host_by_event_name::m_share= 1000, /* records */ sizeof(pos_esms_by_host_by_event_name), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE events_statements_summary_by_host_by_event_name(" + "HOST CHAR(60) collate utf8_bin default null," + "EVENT_NAME VARCHAR(128) not null," + "COUNT_STAR BIGINT unsigned not null," + "SUM_TIMER_WAIT BIGINT unsigned not null," + "MIN_TIMER_WAIT BIGINT unsigned not null," + "AVG_TIMER_WAIT BIGINT unsigned not null," + "MAX_TIMER_WAIT BIGINT unsigned not null," + "SUM_LOCK_TIME BIGINT unsigned not null," + "SUM_ERRORS BIGINT unsigned not null," + "SUM_WARNINGS BIGINT unsigned not null," + "SUM_ROWS_AFFECTED BIGINT unsigned not null," + "SUM_ROWS_SENT BIGINT unsigned not null," + "SUM_ROWS_EXAMINED BIGINT unsigned not null," + "SUM_CREATED_TMP_DISK_TABLES BIGINT unsigned not null," + "SUM_CREATED_TMP_TABLES BIGINT unsigned not null," + "SUM_SELECT_FULL_JOIN BIGINT unsigned not null," + "SUM_SELECT_FULL_RANGE_JOIN BIGINT unsigned not null," + "SUM_SELECT_RANGE BIGINT unsigned not null," + "SUM_SELECT_RANGE_CHECK BIGINT unsigned not null," + "SUM_SELECT_SCAN BIGINT unsigned not null," + "SUM_SORT_MERGE_PASSES BIGINT unsigned not null," + "SUM_SORT_RANGE BIGINT unsigned not null," + "SUM_SORT_ROWS BIGINT unsigned not null," + "SUM_SORT_SCAN BIGINT unsigned not null," + "SUM_NO_INDEX_USED BIGINT unsigned not null," + "SUM_NO_GOOD_INDEX_USED BIGINT unsigned not null)") } }; PFS_engine_table* diff --git a/storage/perfschema/table_esms_by_host_by_event_name.h b/storage/perfschema/table_esms_by_host_by_event_name.h index c28f17a4473..e1a6535d77f 100644 --- a/storage/perfschema/table_esms_by_host_by_event_name.h +++ b/storage/perfschema/table_esms_by_host_by_event_name.h @@ -108,8 +108,6 @@ protected: private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_esms_by_host_by_event_name m_row; diff --git a/storage/perfschema/table_esms_by_thread_by_event_name.cc b/storage/perfschema/table_esms_by_thread_by_event_name.cc index 9ab2a814443..56a081218c0 100644 --- a/storage/perfschema/table_esms_by_thread_by_event_name.cc +++ b/storage/perfschema/table_esms_by_thread_by_event_name.cc @@ -29,144 +29,6 @@ THR_LOCK table_esms_by_thread_by_event_name::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("THREAD_ID") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_STAR") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_LOCK_TIME") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_WARNINGS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_ROWS_AFFECTED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_ROWS_SENT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_ROWS_EXAMINED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_CREATED_TMP_DISK_TABLES") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_CREATED_TMP_TABLES") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_FULL_JOIN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_FULL_RANGE_JOIN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_RANGE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_RANGE_CHECK") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_SCAN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SORT_MERGE_PASSES") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SORT_RANGE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SORT_ROWS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SORT_SCAN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_NO_INDEX_USED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_NO_GOOD_INDEX_USED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_esms_by_thread_by_event_name::m_field_def= -{ 26, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_esms_by_thread_by_event_name::m_share= { @@ -179,8 +41,33 @@ table_esms_by_thread_by_event_name::m_share= 1000, /* records */ sizeof(pos_esms_by_thread_by_event_name), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE events_statements_summary_by_thread_by_event_name(" + "THREAD_ID BIGINT unsigned not null," + "EVENT_NAME VARCHAR(128) not null," + "COUNT_STAR BIGINT unsigned not null," + "SUM_TIMER_WAIT BIGINT unsigned not null," + "MIN_TIMER_WAIT BIGINT unsigned not null," + "AVG_TIMER_WAIT BIGINT unsigned not null," + "MAX_TIMER_WAIT BIGINT unsigned not null," + "SUM_LOCK_TIME BIGINT unsigned not null," + "SUM_ERRORS BIGINT unsigned not null," + "SUM_WARNINGS BIGINT unsigned not null," + "SUM_ROWS_AFFECTED BIGINT unsigned not null," + "SUM_ROWS_SENT BIGINT unsigned not null," + "SUM_ROWS_EXAMINED BIGINT unsigned not null," + "SUM_CREATED_TMP_DISK_TABLES BIGINT unsigned not null," + "SUM_CREATED_TMP_TABLES BIGINT unsigned not null," + "SUM_SELECT_FULL_JOIN BIGINT unsigned not null," + "SUM_SELECT_FULL_RANGE_JOIN BIGINT unsigned not null," + "SUM_SELECT_RANGE BIGINT unsigned not null," + "SUM_SELECT_RANGE_CHECK BIGINT unsigned not null," + "SUM_SELECT_SCAN BIGINT unsigned not null," + "SUM_SORT_MERGE_PASSES BIGINT unsigned not null," + "SUM_SORT_RANGE BIGINT unsigned not null," + "SUM_SORT_ROWS BIGINT unsigned not null," + "SUM_SORT_SCAN BIGINT unsigned not null," + "SUM_NO_INDEX_USED BIGINT unsigned not null," + "SUM_NO_GOOD_INDEX_USED BIGINT unsigned not null)") } }; PFS_engine_table* diff --git a/storage/perfschema/table_esms_by_thread_by_event_name.h b/storage/perfschema/table_esms_by_thread_by_event_name.h index 9fb9f7c58dc..32554c3a2f8 100644 --- a/storage/perfschema/table_esms_by_thread_by_event_name.h +++ b/storage/perfschema/table_esms_by_thread_by_event_name.h @@ -112,8 +112,6 @@ protected: private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_esms_by_thread_by_event_name m_row; diff --git a/storage/perfschema/table_esms_by_user_by_event_name.cc b/storage/perfschema/table_esms_by_user_by_event_name.cc index 6b55fb82814..7e0fce7cafc 100644 --- a/storage/perfschema/table_esms_by_user_by_event_name.cc +++ b/storage/perfschema/table_esms_by_user_by_event_name.cc @@ -30,144 +30,6 @@ THR_LOCK table_esms_by_user_by_event_name::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("USER") }, - { C_STRING_WITH_LEN("char(16)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_STAR") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_LOCK_TIME") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_WARNINGS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_ROWS_AFFECTED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_ROWS_SENT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_ROWS_EXAMINED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_CREATED_TMP_DISK_TABLES") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_CREATED_TMP_TABLES") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_FULL_JOIN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_FULL_RANGE_JOIN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_RANGE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_RANGE_CHECK") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_SCAN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SORT_MERGE_PASSES") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SORT_RANGE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SORT_ROWS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SORT_SCAN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_NO_INDEX_USED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_NO_GOOD_INDEX_USED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_esms_by_user_by_event_name::m_field_def= -{ 26, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_esms_by_user_by_event_name::m_share= { @@ -180,8 +42,33 @@ table_esms_by_user_by_event_name::m_share= 1000, /* records */ sizeof(pos_esms_by_user_by_event_name), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE events_statements_summary_by_user_by_event_name(" + "USER CHAR(16) collate utf8_bin default null," + "EVENT_NAME VARCHAR(128) not null," + "COUNT_STAR BIGINT unsigned not null," + "SUM_TIMER_WAIT BIGINT unsigned not null," + "MIN_TIMER_WAIT BIGINT unsigned not null," + "AVG_TIMER_WAIT BIGINT unsigned not null," + "MAX_TIMER_WAIT BIGINT unsigned not null," + "SUM_LOCK_TIME BIGINT unsigned not null," + "SUM_ERRORS BIGINT unsigned not null," + "SUM_WARNINGS BIGINT unsigned not null," + "SUM_ROWS_AFFECTED BIGINT unsigned not null," + "SUM_ROWS_SENT BIGINT unsigned not null," + "SUM_ROWS_EXAMINED BIGINT unsigned not null," + "SUM_CREATED_TMP_DISK_TABLES BIGINT unsigned not null," + "SUM_CREATED_TMP_TABLES BIGINT unsigned not null," + "SUM_SELECT_FULL_JOIN BIGINT unsigned not null," + "SUM_SELECT_FULL_RANGE_JOIN BIGINT unsigned not null," + "SUM_SELECT_RANGE BIGINT unsigned not null," + "SUM_SELECT_RANGE_CHECK BIGINT unsigned not null," + "SUM_SELECT_SCAN BIGINT unsigned not null," + "SUM_SORT_MERGE_PASSES BIGINT unsigned not null," + "SUM_SORT_RANGE BIGINT unsigned not null," + "SUM_SORT_ROWS BIGINT unsigned not null," + "SUM_SORT_SCAN BIGINT unsigned not null," + "SUM_NO_INDEX_USED BIGINT unsigned not null," + "SUM_NO_GOOD_INDEX_USED BIGINT unsigned not null)") } }; PFS_engine_table* diff --git a/storage/perfschema/table_esms_by_user_by_event_name.h b/storage/perfschema/table_esms_by_user_by_event_name.h index 6dc481d3273..beba70459d7 100644 --- a/storage/perfschema/table_esms_by_user_by_event_name.h +++ b/storage/perfschema/table_esms_by_user_by_event_name.h @@ -108,8 +108,6 @@ protected: private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_esms_by_user_by_event_name m_row; diff --git a/storage/perfschema/table_esms_global_by_event_name.cc b/storage/perfschema/table_esms_global_by_event_name.cc index e1b65559642..1e9f8f99159 100644 --- a/storage/perfschema/table_esms_global_by_event_name.cc +++ b/storage/perfschema/table_esms_global_by_event_name.cc @@ -31,139 +31,6 @@ THR_LOCK table_esms_global_by_event_name::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_STAR") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_LOCK_TIME") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_WARNINGS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_ROWS_AFFECTED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_ROWS_SENT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_ROWS_EXAMINED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_CREATED_TMP_DISK_TABLES") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_CREATED_TMP_TABLES") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_FULL_JOIN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_FULL_RANGE_JOIN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_RANGE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_RANGE_CHECK") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SELECT_SCAN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SORT_MERGE_PASSES") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SORT_RANGE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SORT_ROWS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_SORT_SCAN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_NO_INDEX_USED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_NO_GOOD_INDEX_USED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_esms_global_by_event_name::m_field_def= -{ 25, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_esms_global_by_event_name::m_share= { @@ -176,8 +43,32 @@ table_esms_global_by_event_name::m_share= 1000, /* records */ sizeof(PFS_simple_index), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE events_statements_summary_global_by_event_name(" + "EVENT_NAME VARCHAR(128) not null," + "COUNT_STAR BIGINT unsigned not null," + "SUM_TIMER_WAIT BIGINT unsigned not null," + "MIN_TIMER_WAIT BIGINT unsigned not null," + "AVG_TIMER_WAIT BIGINT unsigned not null," + "MAX_TIMER_WAIT BIGINT unsigned not null," + "SUM_LOCK_TIME BIGINT unsigned not null," + "SUM_ERRORS BIGINT unsigned not null," + "SUM_WARNINGS BIGINT unsigned not null," + "SUM_ROWS_AFFECTED BIGINT unsigned not null," + "SUM_ROWS_SENT BIGINT unsigned not null," + "SUM_ROWS_EXAMINED BIGINT unsigned not null," + "SUM_CREATED_TMP_DISK_TABLES BIGINT unsigned not null," + "SUM_CREATED_TMP_TABLES BIGINT unsigned not null," + "SUM_SELECT_FULL_JOIN BIGINT unsigned not null," + "SUM_SELECT_FULL_RANGE_JOIN BIGINT unsigned not null," + "SUM_SELECT_RANGE BIGINT unsigned not null," + "SUM_SELECT_RANGE_CHECK BIGINT unsigned not null," + "SUM_SELECT_SCAN BIGINT unsigned not null," + "SUM_SORT_MERGE_PASSES BIGINT unsigned not null," + "SUM_SORT_RANGE BIGINT unsigned not null," + "SUM_SORT_ROWS BIGINT unsigned not null," + "SUM_SORT_SCAN BIGINT unsigned not null," + "SUM_NO_INDEX_USED BIGINT unsigned not null," + "SUM_NO_GOOD_INDEX_USED BIGINT unsigned not null)") } }; PFS_engine_table* diff --git a/storage/perfschema/table_esms_global_by_event_name.h b/storage/perfschema/table_esms_global_by_event_name.h index ed07e2b9062..14435fb6087 100644 --- a/storage/perfschema/table_esms_global_by_event_name.h +++ b/storage/perfschema/table_esms_global_by_event_name.h @@ -76,8 +76,6 @@ protected: private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_esms_global_by_event_name m_row; diff --git a/storage/perfschema/table_events_stages.cc b/storage/perfschema/table_events_stages.cc index 08a977987dd..f98ff60d569 100644 --- a/storage/perfschema/table_events_stages.cc +++ b/storage/perfschema/table_events_stages.cc @@ -28,64 +28,6 @@ THR_LOCK table_events_stages_current::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("THREAD_ID") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("EVENT_ID") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("END_EVENT_ID") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SOURCE") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("TIMER_START") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("TIMER_END") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("NESTING_EVENT_ID") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("NESTING_EVENT_TYPE") }, - { C_STRING_WITH_LEN("enum(\'STATEMENT\',\'STAGE\',\'WAIT\'") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_events_stages_current::m_field_def= -{10 , field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_events_stages_current::m_share= { @@ -98,8 +40,17 @@ table_events_stages_current::m_share= 1000, /* records */ sizeof(PFS_simple_index), /* ref length */ &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE events_stages_current(" + "THREAD_ID BIGINT unsigned not null," + "EVENT_ID BIGINT unsigned not null," + "END_EVENT_ID BIGINT unsigned," + "EVENT_NAME VARCHAR(128) not null," + "SOURCE VARCHAR(64)," + "TIMER_START BIGINT unsigned," + "TIMER_END BIGINT unsigned," + "TIMER_WAIT BIGINT unsigned," + "NESTING_EVENT_ID BIGINT unsigned," + "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT'))") } }; THR_LOCK table_events_stages_history::m_table_lock; @@ -116,8 +67,17 @@ table_events_stages_history::m_share= 1000, /* records */ sizeof(pos_events_stages_history), /* ref length */ &m_table_lock, - &table_events_stages_current::m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE events_stages_history(" + "THREAD_ID BIGINT unsigned not null," + "EVENT_ID BIGINT unsigned not null," + "END_EVENT_ID BIGINT unsigned," + "EVENT_NAME VARCHAR(128) not null," + "SOURCE VARCHAR(64)," + "TIMER_START BIGINT unsigned," + "TIMER_END BIGINT unsigned," + "TIMER_WAIT BIGINT unsigned," + "NESTING_EVENT_ID BIGINT unsigned," + "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT'))") } }; THR_LOCK table_events_stages_history_long::m_table_lock; @@ -134,8 +94,17 @@ table_events_stages_history_long::m_share= 10000, /* records */ sizeof(PFS_simple_index), /* ref length */ &m_table_lock, - &table_events_stages_current::m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE events_stages_history_long(" + "THREAD_ID BIGINT unsigned not null," + "EVENT_ID BIGINT unsigned not null," + "END_EVENT_ID BIGINT unsigned," + "EVENT_NAME VARCHAR(128) not null," + "SOURCE VARCHAR(64)," + "TIMER_START BIGINT unsigned," + "TIMER_END BIGINT unsigned," + "TIMER_WAIT BIGINT unsigned," + "NESTING_EVENT_ID BIGINT unsigned," + "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT'))") } }; table_events_stages_common::table_events_stages_common diff --git a/storage/perfschema/table_events_stages.h b/storage/perfschema/table_events_stages.h index 09c555c80fd..2568a090aa3 100644 --- a/storage/perfschema/table_events_stages.h +++ b/storage/perfschema/table_events_stages.h @@ -133,12 +133,6 @@ private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** - Fields definition. - Also used by table_events_stages_history - and table_events_stages_history_long. - */ - static TABLE_FIELD_DEF m_field_def; /** Current position. */ PFS_simple_index m_pos; diff --git a/storage/perfschema/table_events_statements.cc b/storage/perfschema/table_events_statements.cc index 96a79eecd00..c6d0bc2e24e 100644 --- a/storage/perfschema/table_events_statements.cc +++ b/storage/perfschema/table_events_statements.cc @@ -31,214 +31,6 @@ THR_LOCK table_events_statements_current::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("THREAD_ID") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("EVENT_ID") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("END_EVENT_ID") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SOURCE") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("TIMER_START") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("TIMER_END") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("LOCK_TIME") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SQL_TEXT") }, - { C_STRING_WITH_LEN("longtext") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("DIGEST") }, - { C_STRING_WITH_LEN("varchar(32)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("DIGEST_TEXT") }, - { C_STRING_WITH_LEN("longtext") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("CURRENT_SCHEMA") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OBJECT_TYPE") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OBJECT_SCHEMA") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OBJECT_NAME") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OBJECT_INSTANCE_BEGIN") }, - { C_STRING_WITH_LEN("bigint") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MYSQL_ERRNO") }, - { C_STRING_WITH_LEN("int(11)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("RETURNED_SQLSTATE") }, - { C_STRING_WITH_LEN("varchar(5)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MESSAGE_TEXT") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("ERRORS") }, - { C_STRING_WITH_LEN("bigint") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("WARNINGS") }, - { C_STRING_WITH_LEN("bigint") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("ROWS_AFFECTED") }, - { C_STRING_WITH_LEN("bigint") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("ROWS_SENT") }, - { C_STRING_WITH_LEN("bigint") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("ROWS_EXAMINED") }, - { C_STRING_WITH_LEN("bigint") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("CREATED_TMP_DISK_TABLES") }, - { C_STRING_WITH_LEN("bigint") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("CREATED_TMP_TABLES") }, - { C_STRING_WITH_LEN("bigint") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SELECT_FULL_JOIN") }, - { C_STRING_WITH_LEN("bigint") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SELECT_FULL_RANGE_JOIN") }, - { C_STRING_WITH_LEN("bigint") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SELECT_RANGE") }, - { C_STRING_WITH_LEN("bigint") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SELECT_RANGE_CHECK") }, - { C_STRING_WITH_LEN("bigint") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SELECT_SCAN") }, - { C_STRING_WITH_LEN("bigint") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SORT_MERGE_PASSES") }, - { C_STRING_WITH_LEN("bigint") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SORT_RANGE") }, - { C_STRING_WITH_LEN("bigint") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SORT_ROWS") }, - { C_STRING_WITH_LEN("bigint") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SORT_SCAN") }, - { C_STRING_WITH_LEN("bigint") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("NO_INDEX_USED") }, - { C_STRING_WITH_LEN("bigint") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("NO_GOOD_INDEX_USED") }, - { C_STRING_WITH_LEN("bigint") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("NESTING_EVENT_ID") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("NESTING_EVENT_TYPE") }, - { C_STRING_WITH_LEN("enum(\'STATEMENT\',\'STAGE\',\'WAIT\'") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_events_statements_current::m_field_def= -{40 , field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_events_statements_current::m_share= { @@ -251,8 +43,47 @@ table_events_statements_current::m_share= 1000, /* records */ sizeof(PFS_simple_index), /* ref length */ &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE events_statements_current(" + "THREAD_ID BIGINT unsigned not null," + "EVENT_ID BIGINT unsigned not null," + "END_EVENT_ID BIGINT unsigned," + "EVENT_NAME VARCHAR(128) not null," + "SOURCE VARCHAR(64)," + "TIMER_START BIGINT unsigned," + "TIMER_END BIGINT unsigned," + "TIMER_WAIT BIGINT unsigned," + "LOCK_TIME bigint unsigned not null," + "SQL_TEXT LONGTEXT," + "DIGEST VARCHAR(32)," + "DIGEST_TEXT LONGTEXT," + "CURRENT_SCHEMA VARCHAR(64)," + "OBJECT_TYPE VARCHAR(64)," + "OBJECT_SCHEMA VARCHAR(64)," + "OBJECT_NAME VARCHAR(64)," + "OBJECT_INSTANCE_BEGIN BIGINT unsigned," + "MYSQL_ERRNO INTEGER," + "RETURNED_SQLSTATE VARCHAR(5)," + "MESSAGE_TEXT VARCHAR(128)," + "ERRORS BIGINT unsigned not null," + "WARNINGS BIGINT unsigned not null," + "ROWS_AFFECTED BIGINT unsigned not null," + "ROWS_SENT BIGINT unsigned not null," + "ROWS_EXAMINED BIGINT unsigned not null," + "CREATED_TMP_DISK_TABLES BIGINT unsigned not null," + "CREATED_TMP_TABLES BIGINT unsigned not null," + "SELECT_FULL_JOIN BIGINT unsigned not null," + "SELECT_FULL_RANGE_JOIN BIGINT unsigned not null," + "SELECT_RANGE BIGINT unsigned not null," + "SELECT_RANGE_CHECK BIGINT unsigned not null," + "SELECT_SCAN BIGINT unsigned not null," + "SORT_MERGE_PASSES BIGINT unsigned not null," + "SORT_RANGE BIGINT unsigned not null," + "SORT_ROWS BIGINT unsigned not null," + "SORT_SCAN BIGINT unsigned not null," + "NO_INDEX_USED BIGINT unsigned not null," + "NO_GOOD_INDEX_USED BIGINT unsigned not null," + "NESTING_EVENT_ID BIGINT unsigned," + "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT'))") } }; THR_LOCK table_events_statements_history::m_table_lock; @@ -269,8 +100,47 @@ table_events_statements_history::m_share= 1000, /* records */ sizeof(pos_events_statements_history), /* ref length */ &m_table_lock, - &table_events_statements_current::m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE events_statements_history(" + "THREAD_ID BIGINT unsigned not null," + "EVENT_ID BIGINT unsigned not null," + "END_EVENT_ID BIGINT unsigned," + "EVENT_NAME VARCHAR(128) not null," + "SOURCE VARCHAR(64)," + "TIMER_START BIGINT unsigned," + "TIMER_END BIGINT unsigned," + "TIMER_WAIT BIGINT unsigned," + "LOCK_TIME bigint unsigned not null," + "SQL_TEXT LONGTEXT," + "DIGEST VARCHAR(32)," + "DIGEST_TEXT LONGTEXT," + "CURRENT_SCHEMA VARCHAR(64)," + "OBJECT_TYPE VARCHAR(64)," + "OBJECT_SCHEMA VARCHAR(64)," + "OBJECT_NAME VARCHAR(64)," + "OBJECT_INSTANCE_BEGIN BIGINT unsigned," + "MYSQL_ERRNO INTEGER," + "RETURNED_SQLSTATE VARCHAR(5)," + "MESSAGE_TEXT VARCHAR(128)," + "ERRORS BIGINT unsigned not null," + "WARNINGS BIGINT unsigned not null," + "ROWS_AFFECTED BIGINT unsigned not null," + "ROWS_SENT BIGINT unsigned not null," + "ROWS_EXAMINED BIGINT unsigned not null," + "CREATED_TMP_DISK_TABLES BIGINT unsigned not null," + "CREATED_TMP_TABLES BIGINT unsigned not null," + "SELECT_FULL_JOIN BIGINT unsigned not null," + "SELECT_FULL_RANGE_JOIN BIGINT unsigned not null," + "SELECT_RANGE BIGINT unsigned not null," + "SELECT_RANGE_CHECK BIGINT unsigned not null," + "SELECT_SCAN BIGINT unsigned not null," + "SORT_MERGE_PASSES BIGINT unsigned not null," + "SORT_RANGE BIGINT unsigned not null," + "SORT_ROWS BIGINT unsigned not null," + "SORT_SCAN BIGINT unsigned not null," + "NO_INDEX_USED BIGINT unsigned not null," + "NO_GOOD_INDEX_USED BIGINT unsigned not null," + "NESTING_EVENT_ID BIGINT unsigned," + "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT'))") } }; THR_LOCK table_events_statements_history_long::m_table_lock; @@ -287,8 +157,47 @@ table_events_statements_history_long::m_share= 10000, /* records */ sizeof(PFS_simple_index), /* ref length */ &m_table_lock, - &table_events_statements_current::m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE events_statements_history_long(" + "THREAD_ID BIGINT unsigned not null," + "EVENT_ID BIGINT unsigned not null," + "END_EVENT_ID BIGINT unsigned," + "EVENT_NAME VARCHAR(128) not null," + "SOURCE VARCHAR(64)," + "TIMER_START BIGINT unsigned," + "TIMER_END BIGINT unsigned," + "TIMER_WAIT BIGINT unsigned," + "LOCK_TIME bigint unsigned not null," + "SQL_TEXT LONGTEXT," + "DIGEST VARCHAR(32)," + "DIGEST_TEXT LONGTEXT," + "CURRENT_SCHEMA VARCHAR(64)," + "OBJECT_TYPE VARCHAR(64)," + "OBJECT_SCHEMA VARCHAR(64)," + "OBJECT_NAME VARCHAR(64)," + "OBJECT_INSTANCE_BEGIN BIGINT unsigned," + "MYSQL_ERRNO INTEGER," + "RETURNED_SQLSTATE VARCHAR(5)," + "MESSAGE_TEXT VARCHAR(128)," + "ERRORS BIGINT unsigned not null," + "WARNINGS BIGINT unsigned not null," + "ROWS_AFFECTED BIGINT unsigned not null," + "ROWS_SENT BIGINT unsigned not null," + "ROWS_EXAMINED BIGINT unsigned not null," + "CREATED_TMP_DISK_TABLES BIGINT unsigned not null," + "CREATED_TMP_TABLES BIGINT unsigned not null," + "SELECT_FULL_JOIN BIGINT unsigned not null," + "SELECT_FULL_RANGE_JOIN BIGINT unsigned not null," + "SELECT_RANGE BIGINT unsigned not null," + "SELECT_RANGE_CHECK BIGINT unsigned not null," + "SELECT_SCAN BIGINT unsigned not null," + "SORT_MERGE_PASSES BIGINT unsigned not null," + "SORT_RANGE BIGINT unsigned not null," + "SORT_ROWS BIGINT unsigned not null," + "SORT_SCAN BIGINT unsigned not null," + "NO_INDEX_USED BIGINT unsigned not null," + "NO_GOOD_INDEX_USED BIGINT unsigned not null," + "NESTING_EVENT_ID BIGINT unsigned," + "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT'))") } }; table_events_statements_common::table_events_statements_common diff --git a/storage/perfschema/table_events_statements.h b/storage/perfschema/table_events_statements.h index e33c6b505bd..e80a67c1b71 100644 --- a/storage/perfschema/table_events_statements.h +++ b/storage/perfschema/table_events_statements.h @@ -212,12 +212,6 @@ private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** - Fields definition. - Also used by table_events_statements_history - and table_events_statements_history_long. - */ - static TABLE_FIELD_DEF m_field_def; void make_row(PFS_thread* pfs_thread, PFS_events_statements *statement); diff --git a/storage/perfschema/table_events_waits.cc b/storage/perfschema/table_events_waits.cc index 35b90816713..8e2d0064538 100644 --- a/storage/perfschema/table_events_waits.cc +++ b/storage/perfschema/table_events_waits.cc @@ -30,109 +30,6 @@ THR_LOCK table_events_waits_current::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("THREAD_ID") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("EVENT_ID") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("END_EVENT_ID") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SOURCE") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("TIMER_START") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("TIMER_END") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SPINS") }, - { C_STRING_WITH_LEN("int(10)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OBJECT_SCHEMA") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OBJECT_NAME") }, - { C_STRING_WITH_LEN("varchar(512)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("INDEX_NAME") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OBJECT_TYPE") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OBJECT_INSTANCE_BEGIN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("NESTING_EVENT_ID") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("NESTING_EVENT_TYPE") }, - { C_STRING_WITH_LEN("enum(\'STATEMENT\',\'STAGE\',\'WAIT\'") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OPERATION") }, - { C_STRING_WITH_LEN("varchar(32)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("NUMBER_OF_BYTES") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("FLAGS") }, - { C_STRING_WITH_LEN("int(10)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_events_waits_current::m_field_def= -{ 19, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_events_waits_current::m_share= { @@ -145,8 +42,26 @@ table_events_waits_current::m_share= 1000, /* records */ sizeof(pos_events_waits_current), /* ref length */ &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE events_waits_current(" + "THREAD_ID BIGINT unsigned not null," + "EVENT_ID BIGINT unsigned not null," + "END_EVENT_ID BIGINT unsigned," + "EVENT_NAME VARCHAR(128) not null," + "SOURCE VARCHAR(64)," + "TIMER_START BIGINT unsigned," + "TIMER_END BIGINT unsigned," + "TIMER_WAIT BIGINT unsigned," + "SPINS INTEGER unsigned," + "OBJECT_SCHEMA VARCHAR(64)," + "OBJECT_NAME VARCHAR(512)," + "INDEX_NAME VARCHAR(64)," + "OBJECT_TYPE VARCHAR(64)," + "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null," + "NESTING_EVENT_ID BIGINT unsigned," + "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT')," + "OPERATION VARCHAR(32) not null," + "NUMBER_OF_BYTES BIGINT," + "FLAGS INTEGER unsigned)") } }; THR_LOCK table_events_waits_history::m_table_lock; @@ -163,8 +78,26 @@ table_events_waits_history::m_share= 1000, /* records */ sizeof(pos_events_waits_history), /* ref length */ &m_table_lock, - &table_events_waits_current::m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE events_waits_history(" + "THREAD_ID BIGINT unsigned not null," + "EVENT_ID BIGINT unsigned not null," + "END_EVENT_ID BIGINT unsigned," + "EVENT_NAME VARCHAR(128) not null," + "SOURCE VARCHAR(64)," + "TIMER_START BIGINT unsigned," + "TIMER_END BIGINT unsigned," + "TIMER_WAIT BIGINT unsigned," + "SPINS INTEGER unsigned," + "OBJECT_SCHEMA VARCHAR(64)," + "OBJECT_NAME VARCHAR(512)," + "INDEX_NAME VARCHAR(64)," + "OBJECT_TYPE VARCHAR(64)," + "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null," + "NESTING_EVENT_ID BIGINT unsigned," + "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT')," + "OPERATION VARCHAR(32) not null," + "NUMBER_OF_BYTES BIGINT," + "FLAGS INTEGER unsigned)") } }; THR_LOCK table_events_waits_history_long::m_table_lock; @@ -181,8 +114,26 @@ table_events_waits_history_long::m_share= 10000, /* records */ sizeof(PFS_simple_index), /* ref length */ &m_table_lock, - &table_events_waits_current::m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE events_waits_history_long(" + "THREAD_ID BIGINT unsigned not null," + "EVENT_ID BIGINT unsigned not null," + "END_EVENT_ID BIGINT unsigned," + "EVENT_NAME VARCHAR(128) not null," + "SOURCE VARCHAR(64)," + "TIMER_START BIGINT unsigned," + "TIMER_END BIGINT unsigned," + "TIMER_WAIT BIGINT unsigned," + "SPINS INTEGER unsigned," + "OBJECT_SCHEMA VARCHAR(64)," + "OBJECT_NAME VARCHAR(512)," + "INDEX_NAME VARCHAR(64)," + "OBJECT_TYPE VARCHAR(64)," + "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null," + "NESTING_EVENT_ID BIGINT unsigned," + "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT')," + "OPERATION VARCHAR(32) not null," + "NUMBER_OF_BYTES BIGINT," + "FLAGS INTEGER unsigned)") } }; table_events_waits_common::table_events_waits_common diff --git a/storage/perfschema/table_events_waits.h b/storage/perfschema/table_events_waits.h index 065bf95e5a6..60657278191 100644 --- a/storage/perfschema/table_events_waits.h +++ b/storage/perfschema/table_events_waits.h @@ -182,12 +182,6 @@ private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** - Fields definition. - Also used by table_events_waits_history - and table_events_waits_history_long. - */ - static TABLE_FIELD_DEF m_field_def; /** Current position. */ pos_events_waits_current m_pos; diff --git a/storage/perfschema/table_events_waits_summary.cc b/storage/perfschema/table_events_waits_summary.cc index a7130c14a29..516b271669d 100644 --- a/storage/perfschema/table_events_waits_summary.cc +++ b/storage/perfschema/table_events_waits_summary.cc @@ -28,49 +28,6 @@ THR_LOCK table_events_waits_summary_by_instance::m_table_lock; -static const TABLE_FIELD_TYPE ews_by_instance_field_types[]= -{ - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OBJECT_INSTANCE_BEGIN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_STAR") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_events_waits_summary_by_instance::m_field_def= -{ 7, ews_by_instance_field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_events_waits_summary_by_instance::m_share= { @@ -83,8 +40,14 @@ table_events_waits_summary_by_instance::m_share= 1000, /* records */ sizeof(pos_all_instr), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE events_waits_summary_by_instance(" + "EVENT_NAME VARCHAR(128) not null," + "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null," + "COUNT_STAR BIGINT unsigned not null," + "SUM_TIMER_WAIT BIGINT unsigned not null," + "MIN_TIMER_WAIT BIGINT unsigned not null," + "AVG_TIMER_WAIT BIGINT unsigned not null," + "MAX_TIMER_WAIT BIGINT unsigned not null)") } }; PFS_engine_table* table_events_waits_summary_by_instance::create(void) diff --git a/storage/perfschema/table_events_waits_summary.h b/storage/perfschema/table_events_waits_summary.h index 7463ace3eb6..9d3a28816e3 100644 --- a/storage/perfschema/table_events_waits_summary.h +++ b/storage/perfschema/table_events_waits_summary.h @@ -79,8 +79,6 @@ public: private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_events_waits_summary_by_instance m_row; diff --git a/storage/perfschema/table_ews_by_account_by_event_name.cc b/storage/perfschema/table_ews_by_account_by_event_name.cc index 251fbc74536..7f79feca9d3 100644 --- a/storage/perfschema/table_ews_by_account_by_event_name.cc +++ b/storage/perfschema/table_ews_by_account_by_event_name.cc @@ -29,54 +29,6 @@ THR_LOCK table_ews_by_account_by_event_name::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("USER") }, - { C_STRING_WITH_LEN("char(16)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("HOST") }, - { C_STRING_WITH_LEN("char(60)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_STAR") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_ews_by_account_by_event_name::m_field_def= -{ 8, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_ews_by_account_by_event_name::m_share= { @@ -89,8 +41,15 @@ table_ews_by_account_by_event_name::m_share= 1000, /* records */ sizeof(pos_ews_by_account_by_event_name), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE events_waits_summary_by_account_by_event_name(" + "USER CHAR(16) collate utf8_bin default null," + "HOST CHAR(60) collate utf8_bin default null," + "EVENT_NAME VARCHAR(128) not null," + "COUNT_STAR BIGINT unsigned not null," + "SUM_TIMER_WAIT BIGINT unsigned not null," + "MIN_TIMER_WAIT BIGINT unsigned not null," + "AVG_TIMER_WAIT BIGINT unsigned not null," + "MAX_TIMER_WAIT BIGINT unsigned not null)") } }; PFS_engine_table* diff --git a/storage/perfschema/table_ews_by_account_by_event_name.h b/storage/perfschema/table_ews_by_account_by_event_name.h index 8ccfee599eb..40283c30ccb 100644 --- a/storage/perfschema/table_ews_by_account_by_event_name.h +++ b/storage/perfschema/table_ews_by_account_by_event_name.h @@ -119,8 +119,6 @@ protected: private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_ews_by_account_by_event_name m_row; diff --git a/storage/perfschema/table_ews_by_host_by_event_name.cc b/storage/perfschema/table_ews_by_host_by_event_name.cc index 38f94ebc11b..61ac7848cf4 100644 --- a/storage/perfschema/table_ews_by_host_by_event_name.cc +++ b/storage/perfschema/table_ews_by_host_by_event_name.cc @@ -30,49 +30,6 @@ THR_LOCK table_ews_by_host_by_event_name::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("HOST") }, - { C_STRING_WITH_LEN("char(60)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_STAR") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_ews_by_host_by_event_name::m_field_def= -{ 7, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_ews_by_host_by_event_name::m_share= { @@ -85,8 +42,14 @@ table_ews_by_host_by_event_name::m_share= 1000, /* records */ sizeof(pos_ews_by_host_by_event_name), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE events_waits_summary_by_host_by_event_name(" + "HOST CHAR(60) collate utf8_bin default null," + "EVENT_NAME VARCHAR(128) not null," + "COUNT_STAR BIGINT unsigned not null," + "SUM_TIMER_WAIT BIGINT unsigned not null," + "MIN_TIMER_WAIT BIGINT unsigned not null," + "AVG_TIMER_WAIT BIGINT unsigned not null," + "MAX_TIMER_WAIT BIGINT unsigned not null)") } }; PFS_engine_table* diff --git a/storage/perfschema/table_ews_by_host_by_event_name.h b/storage/perfschema/table_ews_by_host_by_event_name.h index 124b121e8d2..c93afafd0ef 100644 --- a/storage/perfschema/table_ews_by_host_by_event_name.h +++ b/storage/perfschema/table_ews_by_host_by_event_name.h @@ -119,8 +119,6 @@ protected: private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_ews_by_host_by_event_name m_row; diff --git a/storage/perfschema/table_ews_by_thread_by_event_name.cc b/storage/perfschema/table_ews_by_thread_by_event_name.cc index 3f21b0625d3..833cdb3df7e 100644 --- a/storage/perfschema/table_ews_by_thread_by_event_name.cc +++ b/storage/perfschema/table_ews_by_thread_by_event_name.cc @@ -29,49 +29,6 @@ THR_LOCK table_ews_by_thread_by_event_name::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("THREAD_ID") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_STAR") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_ews_by_thread_by_event_name::m_field_def= -{ 7, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_ews_by_thread_by_event_name::m_share= { @@ -84,8 +41,14 @@ table_ews_by_thread_by_event_name::m_share= 1000, /* records */ sizeof(pos_ews_by_thread_by_event_name), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE events_waits_summary_by_thread_by_event_name(" + "THREAD_ID BIGINT unsigned not null," + "EVENT_NAME VARCHAR(128) not null," + "COUNT_STAR BIGINT unsigned not null," + "SUM_TIMER_WAIT BIGINT unsigned not null," + "MIN_TIMER_WAIT BIGINT unsigned not null," + "AVG_TIMER_WAIT BIGINT unsigned not null," + "MAX_TIMER_WAIT BIGINT unsigned not null)") } }; PFS_engine_table* diff --git a/storage/perfschema/table_ews_by_thread_by_event_name.h b/storage/perfschema/table_ews_by_thread_by_event_name.h index 989356be646..c584b507d46 100644 --- a/storage/perfschema/table_ews_by_thread_by_event_name.h +++ b/storage/perfschema/table_ews_by_thread_by_event_name.h @@ -118,8 +118,6 @@ protected: private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_ews_by_thread_by_event_name m_row; diff --git a/storage/perfschema/table_ews_by_user_by_event_name.cc b/storage/perfschema/table_ews_by_user_by_event_name.cc index b8365064a26..82d4768293e 100644 --- a/storage/perfschema/table_ews_by_user_by_event_name.cc +++ b/storage/perfschema/table_ews_by_user_by_event_name.cc @@ -30,49 +30,6 @@ THR_LOCK table_ews_by_user_by_event_name::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("USER") }, - { C_STRING_WITH_LEN("char(16)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_STAR") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_ews_by_user_by_event_name::m_field_def= -{ 7, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_ews_by_user_by_event_name::m_share= { @@ -85,8 +42,14 @@ table_ews_by_user_by_event_name::m_share= 1000, /* records */ sizeof(pos_ews_by_user_by_event_name), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE events_waits_summary_by_user_by_event_name(" + "USER CHAR(16) collate utf8_bin default null," + "EVENT_NAME VARCHAR(128) not null," + "COUNT_STAR BIGINT unsigned not null," + "SUM_TIMER_WAIT BIGINT unsigned not null," + "MIN_TIMER_WAIT BIGINT unsigned not null," + "AVG_TIMER_WAIT BIGINT unsigned not null," + "MAX_TIMER_WAIT BIGINT unsigned not null)") } }; PFS_engine_table* diff --git a/storage/perfschema/table_ews_by_user_by_event_name.h b/storage/perfschema/table_ews_by_user_by_event_name.h index 123ee2349ae..4fe4613206f 100644 --- a/storage/perfschema/table_ews_by_user_by_event_name.h +++ b/storage/perfschema/table_ews_by_user_by_event_name.h @@ -119,8 +119,6 @@ protected: private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_ews_by_user_by_event_name m_row; diff --git a/storage/perfschema/table_ews_global_by_event_name.cc b/storage/perfschema/table_ews_global_by_event_name.cc index bc5c3780ecf..ebd855f9109 100644 --- a/storage/perfschema/table_ews_global_by_event_name.cc +++ b/storage/perfschema/table_ews_global_by_event_name.cc @@ -31,44 +31,6 @@ THR_LOCK table_ews_global_by_event_name::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_STAR") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_ews_global_by_event_name::m_field_def= -{ 6, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_ews_global_by_event_name::m_share= { @@ -81,8 +43,13 @@ table_ews_global_by_event_name::m_share= 1000, /* records */ sizeof(pos_ews_global_by_event_name), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE events_waits_summary_global_by_event_name(" + "EVENT_NAME VARCHAR(128) not null," + "COUNT_STAR BIGINT unsigned not null," + "SUM_TIMER_WAIT BIGINT unsigned not null," + "MIN_TIMER_WAIT BIGINT unsigned not null," + "AVG_TIMER_WAIT BIGINT unsigned not null," + "MAX_TIMER_WAIT BIGINT unsigned not null)") } }; PFS_engine_table* diff --git a/storage/perfschema/table_ews_global_by_event_name.h b/storage/perfschema/table_ews_global_by_event_name.h index a118e536b6a..538f1f1fb8a 100644 --- a/storage/perfschema/table_ews_global_by_event_name.h +++ b/storage/perfschema/table_ews_global_by_event_name.h @@ -111,8 +111,6 @@ protected: private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_ews_global_by_event_name m_row; diff --git a/storage/perfschema/table_file_instances.cc b/storage/perfschema/table_file_instances.cc index 5b13210c004..4b5ecf3cb39 100644 --- a/storage/perfschema/table_file_instances.cc +++ b/storage/perfschema/table_file_instances.cc @@ -28,29 +28,6 @@ THR_LOCK table_file_instances::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("FILE_NAME") }, - { C_STRING_WITH_LEN("varchar(512)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OPEN_COUNT") }, - { C_STRING_WITH_LEN("int(10)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_file_instances::m_field_def= -{ 3, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_file_instances::m_share= { @@ -63,8 +40,10 @@ table_file_instances::m_share= 1000, /* records */ sizeof(PFS_simple_index), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE file_instances(" + "FILE_NAME VARCHAR(512) not null," + "EVENT_NAME VARCHAR(128) not null," + "OPEN_COUNT INTEGER unsigned not null)") } }; PFS_engine_table* table_file_instances::create(void) diff --git a/storage/perfschema/table_file_instances.h b/storage/perfschema/table_file_instances.h index f7ec16715f3..988c03bcb5f 100644 --- a/storage/perfschema/table_file_instances.h +++ b/storage/perfschema/table_file_instances.h @@ -73,8 +73,6 @@ private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_file_instances m_row; diff --git a/storage/perfschema/table_file_summary.cc b/storage/perfschema/table_file_summary.cc deleted file mode 100644 index 104fa0fbd36..00000000000 --- a/storage/perfschema/table_file_summary.cc +++ /dev/null @@ -1,372 +0,0 @@ -/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ - -/** - @file storage/perfschema/table_file_summary.cc - Table FILE_SUMMARY_BY_xxx (implementation). -*/ - -#include "my_global.h" -#include "my_pthread.h" -#include "pfs_instr_class.h" -#include "pfs_column_types.h" -#include "pfs_column_values.h" -#include "table_file_summary.h" -#include "pfs_global.h" - -THR_LOCK table_file_summary_by_event_name::m_table_lock; - -static const TABLE_FIELD_TYPE fs_by_event_name_field_types[]= -{ - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_NUMBER_OF_BYTES_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_NUMBER_OF_BYTES_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_file_summary_by_event_name::m_field_def= -{ 5, fs_by_event_name_field_types, 0, (uint*) 0 }; - -PFS_engine_table_share -table_file_summary_by_event_name::m_share= -{ - { C_STRING_WITH_LEN("file_summary_by_event_name") }, - &pfs_truncatable_acl, - &table_file_summary_by_event_name::create, - NULL, /* write_row */ - table_file_summary_by_event_name::delete_all_rows, - 1000, /* records */ - sizeof(PFS_simple_index), - &m_table_lock, - &m_field_def, - false /* checked */ -}; - -PFS_engine_table* table_file_summary_by_event_name::create(void) -{ - return new table_file_summary_by_event_name(); -} - -int table_file_summary_by_event_name::delete_all_rows(void) -{ - reset_file_class_io(); - return 0; -} - -table_file_summary_by_event_name::table_file_summary_by_event_name() - : PFS_engine_table(&m_share, &m_pos), - m_pos(1), m_next_pos(1) -{} - -void table_file_summary_by_event_name::reset_position(void) -{ - m_pos.m_index= 1; - m_next_pos.m_index= 1; -} - -int table_file_summary_by_event_name::rnd_next(void) -{ - PFS_file_class *file_class; - - m_pos.set_at(&m_next_pos); - - file_class= find_file_class(m_pos.m_index); - if (file_class) - { - make_row(file_class); - m_next_pos.set_after(&m_pos); - return 0; - } - - return HA_ERR_END_OF_FILE; -} - -int table_file_summary_by_event_name::rnd_pos(const void *pos) -{ - PFS_file_class *file_class; - - set_position(pos); - - file_class= find_file_class(m_pos.m_index); - if (file_class) - { - make_row(file_class); - return 0; - } - - return HA_ERR_RECORD_DELETED; -} - -/** - Build a row. - @param klass the file class the cursor is reading -*/ -void table_file_summary_by_event_name::make_row(PFS_file_class *klass) -{ - m_row.m_name= &klass->m_name[0]; - m_row.m_name_length= klass->m_name_length; - m_row.m_file_stat= klass->m_file_stat; -} - -int table_file_summary_by_event_name::read_row_values(TABLE *table, - unsigned char *, - Field **fields, - bool read_all) -{ - Field *f; - - /* Set the null bits */ - DBUG_ASSERT(table->s->null_bytes == 0); - - /* The row always exists for classes */ - - for (; (f= *fields) ; fields++) - { - if (read_all || bitmap_is_set(table->read_set, f->field_index)) - { - switch(f->field_index) - { - case 0: /* NAME */ - set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length); - break; - case 1: /* COUNT_READ */ - set_field_ulonglong(f, m_row.m_file_stat.m_count_read); - break; - case 2: /* COUNT_WRITE */ - set_field_ulonglong(f, m_row.m_file_stat.m_count_write); - break; - case 3: /* READ_BYTES */ - set_field_ulonglong(f, m_row.m_file_stat.m_read_bytes); - break; - case 4: /* WRITE_BYTES */ - set_field_ulonglong(f, m_row.m_file_stat.m_write_bytes); - break; - default: - DBUG_ASSERT(false); - } - } - } - - return 0; -} - -THR_LOCK table_file_summary_by_instance::m_table_lock; - -static const TABLE_FIELD_TYPE fs_by_instance_field_types[]= -{ - { - { C_STRING_WITH_LEN("FILE_NAME") }, - { C_STRING_WITH_LEN("varchar(512)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_NUMBER_OF_BYTES_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_NUMBER_OF_BYTES_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_file_summary_by_instance::m_field_def= -{ 6, fs_by_instance_field_types, 0, (uint*) 0 }; - -PFS_engine_table_share -table_file_summary_by_instance::m_share= -{ - { C_STRING_WITH_LEN("file_summary_by_instance") }, - &pfs_truncatable_acl, - &table_file_summary_by_instance::create, - NULL, /* write_row */ - table_file_summary_by_instance::delete_all_rows, - 1000, /* records */ - sizeof(PFS_simple_index), - &m_table_lock, - &m_field_def, - false /* checked */ -}; - -PFS_engine_table* table_file_summary_by_instance::create(void) -{ - return new table_file_summary_by_instance(); -} - -int table_file_summary_by_instance::delete_all_rows(void) -{ - reset_file_instance_io(); - return 0; -} - -table_file_summary_by_instance::table_file_summary_by_instance() - : PFS_engine_table(&m_share, &m_pos), - m_row_exists(false), m_pos(0), m_next_pos(0) -{} - -void table_file_summary_by_instance::reset_position(void) -{ - m_pos.m_index= 0; - m_next_pos.m_index= 0; -} - -int table_file_summary_by_instance::rnd_next(void) -{ - PFS_file *pfs; - - for (m_pos.set_at(&m_next_pos); - m_pos.m_index < file_max; - m_pos.next()) - { - pfs= &file_array[m_pos.m_index]; - if (pfs->m_lock.is_populated()) - { - make_row(pfs); - m_next_pos.set_after(&m_pos); - return 0; - } - } - - return HA_ERR_END_OF_FILE; -} - -int table_file_summary_by_instance::rnd_pos(const void *pos) -{ - PFS_file *pfs; - - set_position(pos); - DBUG_ASSERT(m_pos.m_index < file_max); - pfs= &file_array[m_pos.m_index]; - - if (! pfs->m_lock.is_populated()) - return HA_ERR_RECORD_DELETED; - - make_row(pfs); - return 0; -} - -/** - Build a row. - @param pfs the file the cursor is reading -*/ -void table_file_summary_by_instance::make_row(PFS_file *pfs) -{ - pfs_lock lock; - PFS_file_class *safe_class; - - m_row_exists= false; - - /* Protect this reader against a file delete */ - pfs->m_lock.begin_optimistic_lock(&lock); - - safe_class= sanitize_file_class(pfs->m_class); - if (unlikely(safe_class == NULL)) - return; - - m_row.m_filename= pfs->m_filename; - m_row.m_filename_length= pfs->m_filename_length; - m_row.m_name= safe_class->m_name; - m_row.m_name_length= safe_class->m_name_length; - m_row.m_file_stat= pfs->m_file_stat; - - if (pfs->m_lock.end_optimistic_lock(&lock)) - m_row_exists= true; -} - -int table_file_summary_by_instance::read_row_values(TABLE *table, - unsigned char *, - Field **fields, - bool read_all) -{ - Field *f; - - if (unlikely(! m_row_exists)) - return HA_ERR_RECORD_DELETED; - - /* Set the null bits */ - DBUG_ASSERT(table->s->null_bytes == 0); - - for (; (f= *fields) ; fields++) - { - if (read_all || bitmap_is_set(table->read_set, f->field_index)) - { - switch(f->field_index) - { - case 0: /* FILENAME */ - set_field_varchar_utf8(f, m_row.m_filename, m_row.m_filename_length); - break; - case 1: /* NAME */ - set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length); - break; - case 2: /* COUNT_READ */ - set_field_ulonglong(f, m_row.m_file_stat.m_count_read); - break; - case 3: /* COUNT_WRITE */ - set_field_ulonglong(f, m_row.m_file_stat.m_count_write); - break; - case 4: /* READ_BYTES */ - set_field_ulonglong(f, m_row.m_file_stat.m_read_bytes); - break; - case 5: /* WRITE_BYTES */ - set_field_ulonglong(f, m_row.m_file_stat.m_write_bytes); - break; - default: - DBUG_ASSERT(false); - } - } - } - - return 0; -} - diff --git a/storage/perfschema/table_file_summary.h b/storage/perfschema/table_file_summary.h deleted file mode 100644 index 92837189f1f..00000000000 --- a/storage/perfschema/table_file_summary.h +++ /dev/null @@ -1,151 +0,0 @@ -/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ - -#ifndef TABLE_FILE_SUMMARY_H -#define TABLE_FILE_SUMMARY_H - -/** - @file storage/perfschema/table_file_summary.h - Table FILE_SUMMARY_BY_xxx (declarations). -*/ - -#include "pfs_column_types.h" -#include "pfs_engine_table.h" -#include "pfs_instr_class.h" -#include "pfs_instr.h" - -/** - @addtogroup Performance_schema_tables - @{ -*/ - -/** A row of PERFORMANCE_SCHEMA.FILE_SUMMARY_BY_EVENT_NAME. */ -struct row_file_summary_by_event_name -{ - /** Column EVENT_NAME. */ - const char *m_name; - /** Length in bytes of @c m_name. */ - uint m_name_length; - /** - Columns COUNT_READ, COUNT_WRITE, - SUM_NUMBER_OF_BYTES_READ, SUM_NUMBER_OF_BYTES_WRITE. - */ - PFS_file_stat m_file_stat; -}; - -/** Table PERFORMANCE_SCHEMA.FILE_SUMMARY_BY_EVENT_NAME. */ -class table_file_summary_by_event_name : public PFS_engine_table -{ -public: - /** Table share */ - static PFS_engine_table_share m_share; - static PFS_engine_table* create(); - static int delete_all_rows(); - - virtual int rnd_next(); - virtual int rnd_pos(const void *pos); - virtual void reset_position(void); - -protected: - void make_row(PFS_file_class *klass); - - virtual int read_row_values(TABLE *table, - unsigned char *buf, - Field **fields, - bool read_all); - - table_file_summary_by_event_name(); - -public: - ~table_file_summary_by_event_name() - {} - -private: - /** Table share lock. */ - static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; - - /** Current row. */ - row_file_summary_by_event_name m_row; - /** Current position. */ - PFS_simple_index m_pos; - /** Next position. */ - PFS_simple_index m_next_pos; -}; - -/** A row of PERFORMANCE_SCHEMA.FILE_SUMMARY_BY_INSTANCE. */ -struct row_file_summary_by_instance -{ - /** Column FILE_NAME. */ - const char *m_filename; - /** Length in bytes of @c m_filename. */ - uint m_filename_length; - /** Column EVENT_NAME. */ - const char *m_name; - /** Length in bytes of @c m_name. */ - uint m_name_length; - /** - Columns COUNT_READ, COUNT_WRITE, - SUM_NUMBER_OF_BYTES_READ, SUM_NUMBER_OF_BYTES_WRITE. - */ - PFS_file_stat m_file_stat; -}; - -/** Table PERFORMANCE_SCHEMA.FILE_UMMARY_BY_INSTANCE. */ -class table_file_summary_by_instance : public PFS_engine_table -{ -public: - /** Table share */ - static PFS_engine_table_share m_share; - static PFS_engine_table* create(); - static int delete_all_rows(); - - virtual int rnd_next(); - virtual int rnd_pos(const void *pos); - virtual void reset_position(void); - -protected: - void make_row(PFS_file *pfs); - - virtual int read_row_values(TABLE *table, - unsigned char *buf, - Field **fields, - bool read_all); - - table_file_summary_by_instance(); - -public: - ~table_file_summary_by_instance() - {} - -private: - /** Table share lock. */ - static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; - - /** Current row. */ - row_file_summary_by_instance m_row; - /** True is the current row exists. */ - bool m_row_exists; - /** Current position. */ - PFS_simple_index m_pos; - /** Next position. */ - PFS_simple_index m_next_pos; -}; - -/** @} */ -#endif diff --git a/storage/perfschema/table_file_summary_by_event_name.cc b/storage/perfschema/table_file_summary_by_event_name.cc index 33bee172806..2e46c7c13ec 100644 --- a/storage/perfschema/table_file_summary_by_event_name.cc +++ b/storage/perfschema/table_file_summary_by_event_name.cc @@ -29,135 +29,6 @@ THR_LOCK table_file_summary_by_event_name::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_STAR") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - - /** Read */ - { - { C_STRING_WITH_LEN("COUNT_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_NUMBER_OF_BYTES_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - - /** Write */ - { - { C_STRING_WITH_LEN("COUNT_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_NUMBER_OF_BYTES_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - - /** Misc */ - { - { C_STRING_WITH_LEN("COUNT_MISC") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_MISC") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_MISC") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_MISC") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_MISC") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_file_summary_by_event_name::m_field_def= -{ 23, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_file_summary_by_event_name::m_share= { @@ -170,8 +41,30 @@ table_file_summary_by_event_name::m_share= 1000, /* records */ sizeof(PFS_simple_index), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE file_summary_by_event_name(" + "EVENT_NAME VARCHAR(128) not null," + "COUNT_STAR BIGINT unsigned not null," + "SUM_TIMER_WAIT BIGINT unsigned not null," + "MIN_TIMER_WAIT BIGINT unsigned not null," + "AVG_TIMER_WAIT BIGINT unsigned not null," + "MAX_TIMER_WAIT BIGINT unsigned not null," + "COUNT_READ BIGINT unsigned not null," + "SUM_TIMER_READ BIGINT unsigned not null," + "MIN_TIMER_READ BIGINT unsigned not null," + "AVG_TIMER_READ BIGINT unsigned not null," + "MAX_TIMER_READ BIGINT unsigned not null," + "SUM_NUMBER_OF_BYTES_READ BIGINT not null," + "COUNT_WRITE BIGINT unsigned not null," + "SUM_TIMER_WRITE BIGINT unsigned not null," + "MIN_TIMER_WRITE BIGINT unsigned not null," + "AVG_TIMER_WRITE BIGINT unsigned not null," + "MAX_TIMER_WRITE BIGINT unsigned not null," + "SUM_NUMBER_OF_BYTES_WRITE BIGINT not null," + "COUNT_MISC BIGINT unsigned not null," + "SUM_TIMER_MISC BIGINT unsigned not null," + "MIN_TIMER_MISC BIGINT unsigned not null," + "AVG_TIMER_MISC BIGINT unsigned not null," + "MAX_TIMER_MISC BIGINT unsigned not null)") } }; PFS_engine_table* table_file_summary_by_event_name::create(void) diff --git a/storage/perfschema/table_file_summary_by_event_name.h b/storage/perfschema/table_file_summary_by_event_name.h index 8a51dffad65..2c6f3b26950 100644 --- a/storage/perfschema/table_file_summary_by_event_name.h +++ b/storage/perfschema/table_file_summary_by_event_name.h @@ -74,8 +74,6 @@ private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_file_summary_by_event_name m_row; diff --git a/storage/perfschema/table_file_summary_by_instance.cc b/storage/perfschema/table_file_summary_by_instance.cc index c0bf1c29307..c69aa641a3c 100644 --- a/storage/perfschema/table_file_summary_by_instance.cc +++ b/storage/perfschema/table_file_summary_by_instance.cc @@ -28,145 +28,6 @@ THR_LOCK table_file_summary_by_instance::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("FILE_NAME") }, - { C_STRING_WITH_LEN("varchar(512)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OBJECT_INSTANCE_BEGIN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_STAR") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - - /** Read */ - { - { C_STRING_WITH_LEN("COUNT_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_NUMBER_OF_BYTES_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - - /** Write */ - { - { C_STRING_WITH_LEN("COUNT_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_NUMBER_OF_BYTES_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - - /** Misc */ - { - { C_STRING_WITH_LEN("COUNT_MISC") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_MISC") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_MISC") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_MISC") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_MISC") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_file_summary_by_instance::m_field_def= -{ 25, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_file_summary_by_instance::m_share= { @@ -179,8 +40,32 @@ table_file_summary_by_instance::m_share= 1000, /* records */ sizeof(PFS_simple_index), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE file_summary_by_instance(" + "FILE_NAME VARCHAR(512) not null," + "EVENT_NAME VARCHAR(128) not null," + "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null," + "COUNT_STAR BIGINT unsigned not null," + "SUM_TIMER_WAIT BIGINT unsigned not null," + "MIN_TIMER_WAIT BIGINT unsigned not null," + "AVG_TIMER_WAIT BIGINT unsigned not null," + "MAX_TIMER_WAIT BIGINT unsigned not null," + "COUNT_READ BIGINT unsigned not null," + "SUM_TIMER_READ BIGINT unsigned not null," + "MIN_TIMER_READ BIGINT unsigned not null," + "AVG_TIMER_READ BIGINT unsigned not null," + "MAX_TIMER_READ BIGINT unsigned not null," + "SUM_NUMBER_OF_BYTES_READ BIGINT not null," + "COUNT_WRITE BIGINT unsigned not null," + "SUM_TIMER_WRITE BIGINT unsigned not null," + "MIN_TIMER_WRITE BIGINT unsigned not null," + "AVG_TIMER_WRITE BIGINT unsigned not null," + "MAX_TIMER_WRITE BIGINT unsigned not null," + "SUM_NUMBER_OF_BYTES_WRITE BIGINT not null," + "COUNT_MISC BIGINT unsigned not null," + "SUM_TIMER_MISC BIGINT unsigned not null," + "MIN_TIMER_MISC BIGINT unsigned not null," + "AVG_TIMER_MISC BIGINT unsigned not null," + "MAX_TIMER_MISC BIGINT unsigned not null)") } }; PFS_engine_table* table_file_summary_by_instance::create(void) diff --git a/storage/perfschema/table_file_summary_by_instance.h b/storage/perfschema/table_file_summary_by_instance.h index d9f406966db..4bc1f9a76da 100644 --- a/storage/perfschema/table_file_summary_by_instance.h +++ b/storage/perfschema/table_file_summary_by_instance.h @@ -82,8 +82,6 @@ private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_file_summary_by_instance m_row; diff --git a/storage/perfschema/table_host_cache.cc b/storage/perfschema/table_host_cache.cc index 70efcd46bbf..df13207e578 100644 --- a/storage/perfschema/table_host_cache.cc +++ b/storage/perfschema/table_host_cache.cc @@ -25,159 +25,6 @@ THR_LOCK table_host_cache::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("IP") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("HOST") }, - { C_STRING_WITH_LEN("varchar(255)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("HOST_VALIDATED") }, - { C_STRING_WITH_LEN("enum(\'YES\',\'NO\')") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_CONNECT_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_HOST_BLOCKED_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_NAMEINFO_TRANSIENT_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_NAMEINFO_PERMANENT_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_FORMAT_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_ADDRINFO_TRANSIENT_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_ADDRINFO_PERMANENT_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_FCRDNS_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_HOST_ACL_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_NO_AUTH_PLUGIN_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_AUTH_PLUGIN_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_HANDSHAKE_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_PROXY_USER_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_PROXY_USER_ACL_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_AUTHENTICATION_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_SSL_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_MAX_USER_CONNECTIONS_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_MAX_USER_CONNECTIONS_PER_HOUR_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_DEFAULT_DATABASE_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_INIT_CONNECT_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_LOCAL_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_UNKNOWN_ERRORS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("FIRST_SEEN") }, - { C_STRING_WITH_LEN("timestamp") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("LAST_SEEN") }, - { C_STRING_WITH_LEN("timestamp") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("FIRST_ERROR_SEEN") }, - { C_STRING_WITH_LEN("timestamp") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("LAST_ERROR_SEEN") }, - { C_STRING_WITH_LEN("timestamp") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_host_cache::m_field_def= -{ 29, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_host_cache::m_share= { @@ -190,8 +37,36 @@ table_host_cache::m_share= 1000, /* records */ sizeof(PFS_simple_index), /* ref length */ &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE host_cache(" + "IP VARCHAR(64) not null," + "HOST VARCHAR(255) collate utf8_bin," + "HOST_VALIDATED ENUM ('YES', 'NO') not null," + "SUM_CONNECT_ERRORS BIGINT not null," + "COUNT_HOST_BLOCKED_ERRORS BIGINT not null," + "COUNT_NAMEINFO_TRANSIENT_ERRORS BIGINT not null," + "COUNT_NAMEINFO_PERMANENT_ERRORS BIGINT not null," + "COUNT_FORMAT_ERRORS BIGINT not null," + "COUNT_ADDRINFO_TRANSIENT_ERRORS BIGINT not null," + "COUNT_ADDRINFO_PERMANENT_ERRORS BIGINT not null," + "COUNT_FCRDNS_ERRORS BIGINT not null," + "COUNT_HOST_ACL_ERRORS BIGINT not null," + "COUNT_NO_AUTH_PLUGIN_ERRORS BIGINT not null," + "COUNT_AUTH_PLUGIN_ERRORS BIGINT not null," + "COUNT_HANDSHAKE_ERRORS BIGINT not null," + "COUNT_PROXY_USER_ERRORS BIGINT not null," + "COUNT_PROXY_USER_ACL_ERRORS BIGINT not null," + "COUNT_AUTHENTICATION_ERRORS BIGINT not null," + "COUNT_SSL_ERRORS BIGINT not null," + "COUNT_MAX_USER_CONNECTIONS_ERRORS BIGINT not null," + "COUNT_MAX_USER_CONNECTIONS_PER_HOUR_ERRORS BIGINT not null," + "COUNT_DEFAULT_DATABASE_ERRORS BIGINT not null," + "COUNT_INIT_CONNECT_ERRORS BIGINT not null," + "COUNT_LOCAL_ERRORS BIGINT not null," + "COUNT_UNKNOWN_ERRORS BIGINT not null," + "FIRST_SEEN TIMESTAMP(0) NOT NULL default 0," + "LAST_SEEN TIMESTAMP(0) NOT NULL default 0," + "FIRST_ERROR_SEEN TIMESTAMP(0) null default 0," + "LAST_ERROR_SEEN TIMESTAMP(0) null default 0)") } }; PFS_engine_table* table_host_cache::create(void) diff --git a/storage/perfschema/table_host_cache.h b/storage/perfschema/table_host_cache.h index 74795707ac1..6a100cc4f55 100644 --- a/storage/perfschema/table_host_cache.h +++ b/storage/perfschema/table_host_cache.h @@ -127,8 +127,6 @@ private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; row_host_cache *m_all_rows; uint m_row_count; diff --git a/storage/perfschema/table_hosts.cc b/storage/perfschema/table_hosts.cc index c91193ea83e..8ddc34f5728 100644 --- a/storage/perfschema/table_hosts.cc +++ b/storage/perfschema/table_hosts.cc @@ -24,29 +24,6 @@ THR_LOCK table_hosts::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("HOST") }, - { C_STRING_WITH_LEN("char(60)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("CURRENT_CONNECTIONS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("TOTAL_CONNECTIONS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_hosts::m_field_def= -{ 3, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_hosts::m_share= { @@ -59,8 +36,10 @@ table_hosts::m_share= 1000, /* records */ sizeof(PFS_simple_index), /* ref length */ &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE hosts(" + "HOST CHAR(60) collate utf8_bin default null," + "CURRENT_CONNECTIONS bigint not null," + "TOTAL_CONNECTIONS bigint not null)") } }; PFS_engine_table* table_hosts::create() diff --git a/storage/perfschema/table_hosts.h b/storage/perfschema/table_hosts.h index 6fdbf1bb0d9..9f44dd3381b 100644 --- a/storage/perfschema/table_hosts.h +++ b/storage/perfschema/table_hosts.h @@ -67,8 +67,6 @@ private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_hosts m_row; diff --git a/storage/perfschema/table_os_global_by_type.cc b/storage/perfschema/table_os_global_by_type.cc index f6c9a85a95d..2f7bf5ec5e1 100644 --- a/storage/perfschema/table_os_global_by_type.cc +++ b/storage/perfschema/table_os_global_by_type.cc @@ -28,54 +28,6 @@ THR_LOCK table_os_global_by_type::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("OBJECT_TYPE") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OBJECT_SCHEMA") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OBJECT_NAME") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_STAR") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_os_global_by_type::m_field_def= -{ 8, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_os_global_by_type::m_share= { @@ -88,8 +40,15 @@ table_os_global_by_type::m_share= 1000, /* records */ sizeof(pos_os_global_by_type), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE objects_summary_global_by_type(" + "OBJECT_TYPE VARCHAR(64)," + "OBJECT_SCHEMA VARCHAR(64)," + "OBJECT_NAME VARCHAR(64)," + "COUNT_STAR BIGINT unsigned not null," + "SUM_TIMER_WAIT BIGINT unsigned not null," + "MIN_TIMER_WAIT BIGINT unsigned not null," + "AVG_TIMER_WAIT BIGINT unsigned not null," + "MAX_TIMER_WAIT BIGINT unsigned not null)") } }; PFS_engine_table* diff --git a/storage/perfschema/table_os_global_by_type.h b/storage/perfschema/table_os_global_by_type.h index 888e3760488..7968b85aec4 100644 --- a/storage/perfschema/table_os_global_by_type.h +++ b/storage/perfschema/table_os_global_by_type.h @@ -112,8 +112,6 @@ protected: private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_os_global_by_type m_row; diff --git a/storage/perfschema/table_performance_timers.cc b/storage/perfschema/table_performance_timers.cc index 473ea8b82cf..780d507a64b 100644 --- a/storage/perfschema/table_performance_timers.cc +++ b/storage/perfschema/table_performance_timers.cc @@ -26,35 +26,6 @@ THR_LOCK table_performance_timers::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("TIMER_NAME") }, - { C_STRING_WITH_LEN("enum(\'CYCLE\',\'NANOSECOND\',\'MICROSECOND\'," - "\'MILLISECOND\',\'TICK\')") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("TIMER_FREQUENCY") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("TIMER_RESOLUTION") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("TIMER_OVERHEAD") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_performance_timers::m_field_def= -{ 4, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_performance_timers::m_share= { @@ -67,8 +38,11 @@ table_performance_timers::m_share= COUNT_TIMER_NAME, /* records */ sizeof(PFS_simple_index), /* ref length */ &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE performance_timers(" + "TIMER_NAME ENUM ('CYCLE', 'NANOSECOND', 'MICROSECOND', 'MILLISECOND', 'TICK') not null," + "TIMER_FREQUENCY BIGINT," + "TIMER_RESOLUTION BIGINT," + "TIMER_OVERHEAD BIGINT)") } }; PFS_engine_table* table_performance_timers::create(void) diff --git a/storage/perfschema/table_performance_timers.h b/storage/perfschema/table_performance_timers.h index dbd47665ff6..79e9f54636d 100644 --- a/storage/perfschema/table_performance_timers.h +++ b/storage/perfschema/table_performance_timers.h @@ -70,8 +70,6 @@ public: private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_performance_timers *m_row; diff --git a/storage/perfschema/table_session_account_connect_attrs.cc b/storage/perfschema/table_session_account_connect_attrs.cc index 4a3fcc22341..2aed519a903 100644 --- a/storage/perfschema/table_session_account_connect_attrs.cc +++ b/storage/perfschema/table_session_account_connect_attrs.cc @@ -29,8 +29,12 @@ table_session_account_connect_attrs::m_share= 1000, /* records */ sizeof(pos_connect_attr_by_thread_by_attr), /* ref length */ &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE session_account_connect_attrs(" + "PROCESSLIST_ID INT NOT NULL," + "ATTR_NAME VARCHAR(32) NOT NULL," + "ATTR_VALUE VARCHAR(1024)," + "ORDINAL_POSITION INT" + ") CHARACTER SET utf8 COLLATE utf8_bin") } }; PFS_engine_table* table_session_account_connect_attrs::create() diff --git a/storage/perfschema/table_session_connect.cc b/storage/perfschema/table_session_connect.cc index df3337b284c..a5c557baeb2 100644 --- a/storage/perfschema/table_session_connect.cc +++ b/storage/perfschema/table_session_connect.cc @@ -15,33 +15,6 @@ #include "table_session_connect.h" -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("PROCESSLIST_ID") }, - { C_STRING_WITH_LEN("int(11)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("ATTR_NAME") }, - { C_STRING_WITH_LEN("varchar(32)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("ATTR_VALUE") }, - { C_STRING_WITH_LEN("varchar(1024)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("ORDINAL_POSITION") }, - { C_STRING_WITH_LEN("int(11)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF table_session_connect::m_field_def= -{ 4, field_types, 0, (uint*) 0 }; - table_session_connect::table_session_connect(const PFS_engine_table_share *share) : cursor_by_thread_connect_attr(share) { diff --git a/storage/perfschema/table_session_connect.h b/storage/perfschema/table_session_connect.h index e6faa283e42..7e06f8a3d24 100644 --- a/storage/perfschema/table_session_connect.h +++ b/storage/perfschema/table_session_connect.h @@ -66,8 +66,6 @@ protected: virtual int read_row_values(TABLE *table, unsigned char *buf, Field **fields, bool read_all); protected: - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_session_connect_attrs m_row; /** Safe copy of @c PFS_thread::m_session_connect_attrs. */ diff --git a/storage/perfschema/table_session_connect_attrs.cc b/storage/perfschema/table_session_connect_attrs.cc index 9e1804b7294..840167a40e9 100644 --- a/storage/perfschema/table_session_connect_attrs.cc +++ b/storage/perfschema/table_session_connect_attrs.cc @@ -29,8 +29,12 @@ table_session_connect_attrs::m_share= 1000, /* records */ sizeof(pos_connect_attr_by_thread_by_attr), /* ref length */ &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE session_connect_attrs(" + "PROCESSLIST_ID INT NOT NULL," + "ATTR_NAME VARCHAR(32) NOT NULL," + "ATTR_VALUE VARCHAR(1024)," + "ORDINAL_POSITION INT" + ") CHARACTER SET utf8 COLLATE utf8_bin") } }; PFS_engine_table* table_session_connect_attrs::create() diff --git a/storage/perfschema/table_setup_actors.cc b/storage/perfschema/table_setup_actors.cc index a73ec452980..c82d67fba2d 100644 --- a/storage/perfschema/table_setup_actors.cc +++ b/storage/perfschema/table_setup_actors.cc @@ -29,29 +29,6 @@ THR_LOCK table_setup_actors::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("HOST") }, - { C_STRING_WITH_LEN("char(60)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("USER") }, - { C_STRING_WITH_LEN("char(16)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("ROLE") }, - { C_STRING_WITH_LEN("char(16)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_setup_actors::m_field_def= -{ 3, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_setup_actors::m_share= { @@ -64,8 +41,10 @@ table_setup_actors::m_share= 1000, /* records */ sizeof(PFS_simple_index), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE setup_actors(" + "HOST CHAR(60) collate utf8_bin default '%' not null," + "USER CHAR(16) collate utf8_bin default '%' not null," + "ROLE CHAR(16) collate utf8_bin default '%' not null)") } }; PFS_engine_table* table_setup_actors::create() diff --git a/storage/perfschema/table_setup_actors.h b/storage/perfschema/table_setup_actors.h index be3ab1bdf0d..2a9395dfac7 100644 --- a/storage/perfschema/table_setup_actors.h +++ b/storage/perfschema/table_setup_actors.h @@ -89,8 +89,6 @@ private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_setup_actors m_row; diff --git a/storage/perfschema/table_setup_consumers.cc b/storage/perfschema/table_setup_consumers.cc index 563307f97ad..c09853ffeca 100644 --- a/storage/perfschema/table_setup_consumers.cc +++ b/storage/perfschema/table_setup_consumers.cc @@ -92,24 +92,6 @@ static row_setup_consumers all_setup_consumers_data[COUNT_SETUP_CONSUMERS]= THR_LOCK table_setup_consumers::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("NAME") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("ENABLED") }, - { C_STRING_WITH_LEN("enum(\'YES\',\'NO\')") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_setup_consumers::m_field_def= -{ 2, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_setup_consumers::m_share= { @@ -122,8 +104,9 @@ table_setup_consumers::m_share= COUNT_SETUP_CONSUMERS, /* records */ sizeof(PFS_simple_index), /* ref length */ &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE setup_consumers(" + "NAME VARCHAR(64) not null," + "ENABLED ENUM ('YES', 'NO') not null)") } }; PFS_engine_table* table_setup_consumers::create(void) diff --git a/storage/perfschema/table_setup_consumers.h b/storage/perfschema/table_setup_consumers.h index bc7e9d553bb..e59033c0ad1 100644 --- a/storage/perfschema/table_setup_consumers.h +++ b/storage/perfschema/table_setup_consumers.h @@ -72,8 +72,6 @@ public: private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_setup_consumers *m_row; diff --git a/storage/perfschema/table_setup_instruments.cc b/storage/perfschema/table_setup_instruments.cc index 060857c3a38..d911128ce94 100644 --- a/storage/perfschema/table_setup_instruments.cc +++ b/storage/perfschema/table_setup_instruments.cc @@ -30,29 +30,6 @@ THR_LOCK table_setup_instruments::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("ENABLED") }, - { C_STRING_WITH_LEN("enum(\'YES\',\'NO\')") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("TIMED") }, - { C_STRING_WITH_LEN("enum(\'YES\',\'NO\')") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_setup_instruments::m_field_def= -{ 3, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_setup_instruments::m_share= { @@ -65,8 +42,10 @@ table_setup_instruments::m_share= 1000, /* records */ sizeof(pos_setup_instruments), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE setup_instruments(" + "NAME VARCHAR(128) not null," + "ENABLED ENUM ('YES', 'NO') not null," + "TIMED ENUM ('YES', 'NO') not null)") } }; PFS_engine_table* table_setup_instruments::create(void) diff --git a/storage/perfschema/table_setup_instruments.h b/storage/perfschema/table_setup_instruments.h index cb4c6a06de1..2e70a528bbd 100644 --- a/storage/perfschema/table_setup_instruments.h +++ b/storage/perfschema/table_setup_instruments.h @@ -106,8 +106,6 @@ private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_setup_instruments m_row; diff --git a/storage/perfschema/table_setup_objects.cc b/storage/perfschema/table_setup_objects.cc index 4753285d277..5321271a62d 100644 --- a/storage/perfschema/table_setup_objects.cc +++ b/storage/perfschema/table_setup_objects.cc @@ -30,39 +30,6 @@ THR_LOCK table_setup_objects::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("OBJECT_TYPE") }, - { C_STRING_WITH_LEN("enum(\'TABLE\')") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OBJECT_SCHEMA") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OBJECT_NAME") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("ENABLED") }, - { C_STRING_WITH_LEN("enum(\'YES\',\'NO\')") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("TIMED") }, - { C_STRING_WITH_LEN("enum(\'YES\',\'NO\')") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_setup_objects::m_field_def= -{ 5, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_setup_objects::m_share= { @@ -75,8 +42,12 @@ table_setup_objects::m_share= 1000, /* records */ sizeof(PFS_simple_index), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE setup_objects(" + "OBJECT_TYPE ENUM ('TABLE') not null default 'TABLE'," + "OBJECT_SCHEMA VARCHAR(64) default '%'," + "OBJECT_NAME VARCHAR(64) not null default '%'," + "ENABLED ENUM ('YES', 'NO') not null default 'YES'," + "TIMED ENUM ('YES', 'NO') not null default 'YES')") } }; int update_derived_flags() diff --git a/storage/perfschema/table_setup_objects.h b/storage/perfschema/table_setup_objects.h index 4b31fa6a8a6..55423ffd90f 100644 --- a/storage/perfschema/table_setup_objects.h +++ b/storage/perfschema/table_setup_objects.h @@ -92,8 +92,6 @@ private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_setup_objects m_row; diff --git a/storage/perfschema/table_setup_timers.cc b/storage/perfschema/table_setup_timers.cc index 1176f1f34b1..911fa121e06 100644 --- a/storage/perfschema/table_setup_timers.cc +++ b/storage/perfschema/table_setup_timers.cc @@ -48,25 +48,6 @@ static row_setup_timers all_setup_timers_data[COUNT_SETUP_TIMERS]= THR_LOCK table_setup_timers::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("NAME") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("TIMER_NAME") }, - { C_STRING_WITH_LEN("enum(\'CYCLE\',\'NANOSECOND\',\'MICROSECOND\'," - "\'MILLISECOND\',\'TICK\')") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_setup_timers::m_field_def= -{ 2, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_setup_timers::m_share= { @@ -79,8 +60,9 @@ table_setup_timers::m_share= COUNT_SETUP_TIMERS, sizeof(PFS_simple_index), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE setup_timers(" + "NAME VARCHAR(64) not null," + "TIMER_NAME ENUM ('CYCLE', 'NANOSECOND', 'MICROSECOND', 'MILLISECOND', 'TICK') not null)") } }; PFS_engine_table* table_setup_timers::create(void) diff --git a/storage/perfschema/table_setup_timers.h b/storage/perfschema/table_setup_timers.h index a81e6fefaaf..46af68bb9e3 100644 --- a/storage/perfschema/table_setup_timers.h +++ b/storage/perfschema/table_setup_timers.h @@ -70,8 +70,6 @@ public: private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_setup_timers *m_row; diff --git a/storage/perfschema/table_socket_instances.cc b/storage/perfschema/table_socket_instances.cc index 6dfea0bf8be..e47a97c90b0 100644 --- a/storage/perfschema/table_socket_instances.cc +++ b/storage/perfschema/table_socket_instances.cc @@ -28,49 +28,6 @@ THR_LOCK table_socket_instances::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OBJECT_INSTANCE_BEGIN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("THREAD_ID") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SOCKET_ID") }, - { C_STRING_WITH_LEN("int(11)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("IP") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("PORT") }, - { C_STRING_WITH_LEN("int(11)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("STATE") }, - { C_STRING_WITH_LEN("enum('IDLE','ACTIVE')") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_socket_instances::m_field_def= -{ 7, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_socket_instances::m_share= { @@ -83,8 +40,14 @@ table_socket_instances::m_share= 1000, /* records */ sizeof(PFS_simple_index), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE socket_instances(" + "EVENT_NAME VARCHAR(128) not null," + "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null," + "THREAD_ID BIGINT unsigned," + "SOCKET_ID INTEGER not null," + "IP VARCHAR(64) not null," + "PORT INTEGER not null," + "STATE ENUM('IDLE','ACTIVE') not null)") } }; PFS_engine_table* table_socket_instances::create(void) diff --git a/storage/perfschema/table_socket_instances.h b/storage/perfschema/table_socket_instances.h index 080f11c1ba8..76ed8c47559 100644 --- a/storage/perfschema/table_socket_instances.h +++ b/storage/perfschema/table_socket_instances.h @@ -85,8 +85,6 @@ private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_socket_instances m_row; diff --git a/storage/perfschema/table_socket_summary_by_event_name.cc b/storage/perfschema/table_socket_summary_by_event_name.cc index 07bc9c9389a..512fe8e41d3 100644 --- a/storage/perfschema/table_socket_summary_by_event_name.cc +++ b/storage/perfschema/table_socket_summary_by_event_name.cc @@ -29,135 +29,6 @@ THR_LOCK table_socket_summary_by_event_name::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_STAR") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - - /** Read */ - { - { C_STRING_WITH_LEN("COUNT_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_NUMBER_OF_BYTES_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - - /** Write */ - { - { C_STRING_WITH_LEN("COUNT_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_NUMBER_OF_BYTES_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - - /** Misc */ - { - { C_STRING_WITH_LEN("COUNT_MISC") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_MISC") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_MISC") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_MISC") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_MISC") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_socket_summary_by_event_name::m_field_def= -{ 23, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_socket_summary_by_event_name::m_share= { @@ -170,8 +41,30 @@ table_socket_summary_by_event_name::m_share= 1000, /* records */ sizeof(PFS_simple_index), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE socket_summary_by_event_name(" + "EVENT_NAME VARCHAR(128) not null," + "COUNT_STAR BIGINT unsigned not null," + "SUM_TIMER_WAIT BIGINT unsigned not null," + "MIN_TIMER_WAIT BIGINT unsigned not null," + "AVG_TIMER_WAIT BIGINT unsigned not null," + "MAX_TIMER_WAIT BIGINT unsigned not null," + "COUNT_READ BIGINT unsigned not null," + "SUM_TIMER_READ BIGINT unsigned not null," + "MIN_TIMER_READ BIGINT unsigned not null," + "AVG_TIMER_READ BIGINT unsigned not null," + "MAX_TIMER_READ BIGINT unsigned not null," + "SUM_NUMBER_OF_BYTES_READ BIGINT unsigned not null," + "COUNT_WRITE BIGINT unsigned not null," + "SUM_TIMER_WRITE BIGINT unsigned not null," + "MIN_TIMER_WRITE BIGINT unsigned not null," + "AVG_TIMER_WRITE BIGINT unsigned not null," + "MAX_TIMER_WRITE BIGINT unsigned not null," + "SUM_NUMBER_OF_BYTES_WRITE BIGINT unsigned not null," + "COUNT_MISC BIGINT unsigned not null," + "SUM_TIMER_MISC BIGINT unsigned not null," + "MIN_TIMER_MISC BIGINT unsigned not null," + "AVG_TIMER_MISC BIGINT unsigned not null," + "MAX_TIMER_MISC BIGINT unsigned not null)") } }; PFS_engine_table* table_socket_summary_by_event_name::create(void) diff --git a/storage/perfschema/table_socket_summary_by_event_name.h b/storage/perfschema/table_socket_summary_by_event_name.h index b34bed41f83..72a1e54fa99 100644 --- a/storage/perfschema/table_socket_summary_by_event_name.h +++ b/storage/perfschema/table_socket_summary_by_event_name.h @@ -75,8 +75,6 @@ private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_socket_summary_by_event_name m_row; diff --git a/storage/perfschema/table_socket_summary_by_instance.cc b/storage/perfschema/table_socket_summary_by_instance.cc index 3d092b9b1d0..4ab600d8c4e 100644 --- a/storage/perfschema/table_socket_summary_by_instance.cc +++ b/storage/perfschema/table_socket_summary_by_instance.cc @@ -28,140 +28,6 @@ THR_LOCK table_socket_summary_by_instance::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OBJECT_INSTANCE_BEGIN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_STAR") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - - /** Read */ - { - { C_STRING_WITH_LEN("COUNT_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_NUMBER_OF_BYTES_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - - /** Write */ - { - { C_STRING_WITH_LEN("COUNT_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_NUMBER_OF_BYTES_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - - /** Misc */ - { - { C_STRING_WITH_LEN("COUNT_MISC") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_MISC") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_MISC") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_MISC") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_MISC") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_socket_summary_by_instance::m_field_def= -{ 24, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_socket_summary_by_instance::m_share= { @@ -174,8 +40,31 @@ table_socket_summary_by_instance::m_share= 1000, /* records */ sizeof(PFS_simple_index), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE socket_summary_by_instance(" + "EVENT_NAME VARCHAR(128) not null," + "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null," + "COUNT_STAR BIGINT unsigned not null," + "SUM_TIMER_WAIT BIGINT unsigned not null," + "MIN_TIMER_WAIT BIGINT unsigned not null," + "AVG_TIMER_WAIT BIGINT unsigned not null," + "MAX_TIMER_WAIT BIGINT unsigned not null," + "COUNT_READ BIGINT unsigned not null," + "SUM_TIMER_READ BIGINT unsigned not null," + "MIN_TIMER_READ BIGINT unsigned not null," + "AVG_TIMER_READ BIGINT unsigned not null," + "MAX_TIMER_READ BIGINT unsigned not null," + "SUM_NUMBER_OF_BYTES_READ BIGINT unsigned not null," + "COUNT_WRITE BIGINT unsigned not null," + "SUM_TIMER_WRITE BIGINT unsigned not null," + "MIN_TIMER_WRITE BIGINT unsigned not null," + "AVG_TIMER_WRITE BIGINT unsigned not null," + "MAX_TIMER_WRITE BIGINT unsigned not null," + "SUM_NUMBER_OF_BYTES_WRITE BIGINT unsigned not null," + "COUNT_MISC BIGINT unsigned not null," + "SUM_TIMER_MISC BIGINT unsigned not null," + "MIN_TIMER_MISC BIGINT unsigned not null," + "AVG_TIMER_MISC BIGINT unsigned not null," + "MAX_TIMER_MISC BIGINT unsigned not null)") } }; PFS_engine_table* table_socket_summary_by_instance::create(void) diff --git a/storage/perfschema/table_socket_summary_by_instance.h b/storage/perfschema/table_socket_summary_by_instance.h index f4c8ea41d8c..949e99bfef9 100644 --- a/storage/perfschema/table_socket_summary_by_instance.h +++ b/storage/perfschema/table_socket_summary_by_instance.h @@ -78,8 +78,6 @@ private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_socket_summary_by_instance m_row; diff --git a/storage/perfschema/table_sync_instances.cc b/storage/perfschema/table_sync_instances.cc index 9b53eb3ce57..4bf5ae66938 100644 --- a/storage/perfschema/table_sync_instances.cc +++ b/storage/perfschema/table_sync_instances.cc @@ -29,29 +29,6 @@ THR_LOCK table_mutex_instances::m_table_lock; -static const TABLE_FIELD_TYPE mutex_field_types[]= -{ - { - { C_STRING_WITH_LEN("NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OBJECT_INSTANCE_BEGIN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("LOCKED_BY_THREAD_ID") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_mutex_instances::m_field_def= -{ 3, mutex_field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_mutex_instances::m_share= { @@ -64,8 +41,10 @@ table_mutex_instances::m_share= 1000, /* records */ sizeof(PFS_simple_index), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE mutex_instances(" + "NAME VARCHAR(128) not null," + "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null," + "LOCKED_BY_THREAD_ID BIGINT unsigned)") } }; PFS_engine_table* table_mutex_instances::create(void) @@ -193,34 +172,6 @@ int table_mutex_instances::read_row_values(TABLE *table, THR_LOCK table_rwlock_instances::m_table_lock; -static const TABLE_FIELD_TYPE rwlock_field_types[]= -{ - { - { C_STRING_WITH_LEN("NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OBJECT_INSTANCE_BEGIN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("WRITE_LOCKED_BY_THREAD_ID") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("READ_LOCKED_BY_COUNT") }, - { C_STRING_WITH_LEN("int(10)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_rwlock_instances::m_field_def= -{ 4, rwlock_field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_rwlock_instances::m_share= { @@ -233,8 +184,11 @@ table_rwlock_instances::m_share= 1000, /* records */ sizeof(PFS_simple_index), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE rwlock_instances(" + "NAME VARCHAR(128) not null," + "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null," + "WRITE_LOCKED_BY_THREAD_ID BIGINT unsigned," + "READ_LOCKED_BY_COUNT INTEGER unsigned not null)") } }; PFS_engine_table* table_rwlock_instances::create(void) @@ -369,24 +323,6 @@ int table_rwlock_instances::read_row_values(TABLE *table, THR_LOCK table_cond_instances::m_table_lock; -static const TABLE_FIELD_TYPE cond_field_types[]= -{ - { - { C_STRING_WITH_LEN("NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OBJECT_INSTANCE_BEGIN") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_cond_instances::m_field_def= -{ 2, cond_field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_cond_instances::m_share= { @@ -399,8 +335,9 @@ table_cond_instances::m_share= 1000, /* records */ sizeof(PFS_simple_index), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE cond_instances(" + "NAME VARCHAR(128) not null," + "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null)") } }; PFS_engine_table* table_cond_instances::create(void) diff --git a/storage/perfschema/table_sync_instances.h b/storage/perfschema/table_sync_instances.h index ff7b2765a11..da459268599 100644 --- a/storage/perfschema/table_sync_instances.h +++ b/storage/perfschema/table_sync_instances.h @@ -77,8 +77,6 @@ private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_mutex_instances m_row; @@ -136,8 +134,6 @@ private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_rwlock_instances m_row; @@ -189,8 +185,6 @@ private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_cond_instances m_row; diff --git a/storage/perfschema/table_threads.cc b/storage/perfschema/table_threads.cc index 1fd2486589c..5c78b567b8c 100644 --- a/storage/perfschema/table_threads.cc +++ b/storage/perfschema/table_threads.cc @@ -22,84 +22,6 @@ THR_LOCK table_threads::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("THREAD_ID") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("TYPE") }, - { C_STRING_WITH_LEN("varchar(10)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("PROCESSLIST_ID") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("PROCESSLIST_USER") }, - { C_STRING_WITH_LEN("varchar(16)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("PROCESSLIST_HOST") }, - { C_STRING_WITH_LEN("varchar(60)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("PROCESSLIST_DB") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("PROCESSLIST_COMMAND") }, - { C_STRING_WITH_LEN("varchar(16)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("PROCESSLIST_TIME") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("PROCESSLIST_STATE") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("PROCESSLIST_INFO") }, - { C_STRING_WITH_LEN("longtext") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("PARENT_THREAD_ID") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("ROLE") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("INSTRUMENTED") }, - { C_STRING_WITH_LEN("enum(\'YES\',\'NO\')") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_threads::m_field_def= -{ 14, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_threads::m_share= { @@ -112,8 +34,21 @@ table_threads::m_share= 1000, /* records */ sizeof(PFS_simple_index), /* ref length */ &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE threads(" + "THREAD_ID BIGINT unsigned not null," + "NAME VARCHAR(128) not null," + "TYPE VARCHAR(10) not null," + "PROCESSLIST_ID BIGINT unsigned," + "PROCESSLIST_USER VARCHAR(16)," + "PROCESSLIST_HOST VARCHAR(60)," + "PROCESSLIST_DB VARCHAR(64)," + "PROCESSLIST_COMMAND VARCHAR(16)," + "PROCESSLIST_TIME BIGINT," + "PROCESSLIST_STATE VARCHAR(64)," + "PROCESSLIST_INFO LONGTEXT," + "PARENT_THREAD_ID BIGINT unsigned," + "ROLE VARCHAR(64)," + "INSTRUMENTED ENUM ('YES', 'NO') not null)") } }; PFS_engine_table* table_threads::create() diff --git a/storage/perfschema/table_threads.h b/storage/perfschema/table_threads.h index bce45c0cbce..10afbe14e74 100644 --- a/storage/perfschema/table_threads.h +++ b/storage/perfschema/table_threads.h @@ -102,8 +102,6 @@ private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_threads m_row; diff --git a/storage/perfschema/table_tiws_by_index_usage.cc b/storage/perfschema/table_tiws_by_index_usage.cc index 5f6d0cd2b5a..382b2f86b97 100644 --- a/storage/perfschema/table_tiws_by_index_usage.cc +++ b/storage/perfschema/table_tiws_by_index_usage.cc @@ -29,209 +29,6 @@ THR_LOCK table_tiws_by_index_usage::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("OBJECT_TYPE") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OBJECT_SCHEMA") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OBJECT_NAME") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("INDEX_NAME") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_STAR") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_FETCH") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_FETCH") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_FETCH") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_FETCH") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_FETCH") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_INSERT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_INSERT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_INSERT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_INSERT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_INSERT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_UPDATE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_UPDATE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_UPDATE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_UPDATE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_UPDATE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_DELETE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_DELETE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_DELETE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_DELETE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_DELETE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_tiws_by_index_usage::m_field_def= -{ 39, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_tiws_by_index_usage::m_share= { @@ -244,8 +41,46 @@ table_tiws_by_index_usage::m_share= 1000, /* records */ sizeof(pos_tiws_by_index_usage), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE table_io_waits_summary_by_index_usage(" + "OBJECT_TYPE VARCHAR(64)," + "OBJECT_SCHEMA VARCHAR(64)," + "OBJECT_NAME VARCHAR(64)," + "INDEX_NAME VARCHAR(64)," + "COUNT_STAR BIGINT unsigned not null," + "SUM_TIMER_WAIT BIGINT unsigned not null," + "MIN_TIMER_WAIT BIGINT unsigned not null," + "AVG_TIMER_WAIT BIGINT unsigned not null," + "MAX_TIMER_WAIT BIGINT unsigned not null," + "COUNT_READ BIGINT unsigned not null," + "SUM_TIMER_READ BIGINT unsigned not null," + "MIN_TIMER_READ BIGINT unsigned not null," + "AVG_TIMER_READ BIGINT unsigned not null," + "MAX_TIMER_READ BIGINT unsigned not null," + "COUNT_WRITE BIGINT unsigned not null," + "SUM_TIMER_WRITE BIGINT unsigned not null," + "MIN_TIMER_WRITE BIGINT unsigned not null," + "AVG_TIMER_WRITE BIGINT unsigned not null," + "MAX_TIMER_WRITE BIGINT unsigned not null," + "COUNT_FETCH BIGINT unsigned not null," + "SUM_TIMER_FETCH BIGINT unsigned not null," + "MIN_TIMER_FETCH BIGINT unsigned not null," + "AVG_TIMER_FETCH BIGINT unsigned not null," + "MAX_TIMER_FETCH BIGINT unsigned not null," + "COUNT_INSERT BIGINT unsigned not null," + "SUM_TIMER_INSERT BIGINT unsigned not null," + "MIN_TIMER_INSERT BIGINT unsigned not null," + "AVG_TIMER_INSERT BIGINT unsigned not null," + "MAX_TIMER_INSERT BIGINT unsigned not null," + "COUNT_UPDATE BIGINT unsigned not null," + "SUM_TIMER_UPDATE BIGINT unsigned not null," + "MIN_TIMER_UPDATE BIGINT unsigned not null," + "AVG_TIMER_UPDATE BIGINT unsigned not null," + "MAX_TIMER_UPDATE BIGINT unsigned not null," + "COUNT_DELETE BIGINT unsigned not null," + "SUM_TIMER_DELETE BIGINT unsigned not null," + "MIN_TIMER_DELETE BIGINT unsigned not null," + "AVG_TIMER_DELETE BIGINT unsigned not null," + "MAX_TIMER_DELETE BIGINT unsigned not null)") } }; PFS_engine_table* diff --git a/storage/perfschema/table_tiws_by_index_usage.h b/storage/perfschema/table_tiws_by_index_usage.h index b5f589d0cea..1528de2fe15 100644 --- a/storage/perfschema/table_tiws_by_index_usage.h +++ b/storage/perfschema/table_tiws_by_index_usage.h @@ -106,8 +106,6 @@ protected: private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_tiws_by_index_usage m_row; diff --git a/storage/perfschema/table_tiws_by_table.cc b/storage/perfschema/table_tiws_by_table.cc index 7eeebccb8a9..ab1e9b115d6 100644 --- a/storage/perfschema/table_tiws_by_table.cc +++ b/storage/perfschema/table_tiws_by_table.cc @@ -29,204 +29,6 @@ THR_LOCK table_tiws_by_table::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("OBJECT_TYPE") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OBJECT_SCHEMA") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OBJECT_NAME") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_STAR") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_FETCH") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_FETCH") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_FETCH") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_FETCH") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_FETCH") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_INSERT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_INSERT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_INSERT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_INSERT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_INSERT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_UPDATE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_UPDATE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_UPDATE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_UPDATE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_UPDATE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_DELETE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_DELETE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_DELETE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_DELETE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_DELETE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_tiws_by_table::m_field_def= -{ 38, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_tiws_by_table::m_share= { @@ -239,8 +41,45 @@ table_tiws_by_table::m_share= 1000, /* records */ sizeof(PFS_simple_index), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE table_io_waits_summary_by_table(" + "OBJECT_TYPE VARCHAR(64)," + "OBJECT_SCHEMA VARCHAR(64)," + "OBJECT_NAME VARCHAR(64)," + "COUNT_STAR BIGINT unsigned not null," + "SUM_TIMER_WAIT BIGINT unsigned not null," + "MIN_TIMER_WAIT BIGINT unsigned not null," + "AVG_TIMER_WAIT BIGINT unsigned not null," + "MAX_TIMER_WAIT BIGINT unsigned not null," + "COUNT_READ BIGINT unsigned not null," + "SUM_TIMER_READ BIGINT unsigned not null," + "MIN_TIMER_READ BIGINT unsigned not null," + "AVG_TIMER_READ BIGINT unsigned not null," + "MAX_TIMER_READ BIGINT unsigned not null," + "COUNT_WRITE BIGINT unsigned not null," + "SUM_TIMER_WRITE BIGINT unsigned not null," + "MIN_TIMER_WRITE BIGINT unsigned not null," + "AVG_TIMER_WRITE BIGINT unsigned not null," + "MAX_TIMER_WRITE BIGINT unsigned not null," + "COUNT_FETCH BIGINT unsigned not null," + "SUM_TIMER_FETCH BIGINT unsigned not null," + "MIN_TIMER_FETCH BIGINT unsigned not null," + "AVG_TIMER_FETCH BIGINT unsigned not null," + "MAX_TIMER_FETCH BIGINT unsigned not null," + "COUNT_INSERT BIGINT unsigned not null," + "SUM_TIMER_INSERT BIGINT unsigned not null," + "MIN_TIMER_INSERT BIGINT unsigned not null," + "AVG_TIMER_INSERT BIGINT unsigned not null," + "MAX_TIMER_INSERT BIGINT unsigned not null," + "COUNT_UPDATE BIGINT unsigned not null," + "SUM_TIMER_UPDATE BIGINT unsigned not null," + "MIN_TIMER_UPDATE BIGINT unsigned not null," + "AVG_TIMER_UPDATE BIGINT unsigned not null," + "MAX_TIMER_UPDATE BIGINT unsigned not null," + "COUNT_DELETE BIGINT unsigned not null," + "SUM_TIMER_DELETE BIGINT unsigned not null," + "MIN_TIMER_DELETE BIGINT unsigned not null," + "AVG_TIMER_DELETE BIGINT unsigned not null," + "MAX_TIMER_DELETE BIGINT unsigned not null)") } }; PFS_engine_table* diff --git a/storage/perfschema/table_tiws_by_table.h b/storage/perfschema/table_tiws_by_table.h index ea52b5297d7..d11043188eb 100644 --- a/storage/perfschema/table_tiws_by_table.h +++ b/storage/perfschema/table_tiws_by_table.h @@ -76,8 +76,6 @@ protected: private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_tiws_by_table m_row; diff --git a/storage/perfschema/table_tlws_by_table.cc b/storage/perfschema/table_tlws_by_table.cc index 6537e709549..bae120248ad 100644 --- a/storage/perfschema/table_tlws_by_table.cc +++ b/storage/perfschema/table_tlws_by_table.cc @@ -29,379 +29,6 @@ THR_LOCK table_tlws_by_table::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("OBJECT_TYPE") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OBJECT_SCHEMA") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("OBJECT_NAME") }, - { C_STRING_WITH_LEN("varchar(64)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_STAR") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_READ") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_READ_NORMAL") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_READ_NORMAL") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_READ_NORMAL") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_READ_NORMAL") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_READ_NORMAL") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_READ_WITH_SHARED_LOCKS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_READ_WITH_SHARED_LOCKS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_READ_WITH_SHARED_LOCKS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_READ_WITH_SHARED_LOCKS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_READ_WITH_SHARED_LOCKS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_READ_HIGH_PRIORITY") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_READ_HIGH_PRIORITY") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_READ_HIGH_PRIORITY") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_READ_HIGH_PRIORITY") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_READ_HIGH_PRIORITY") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_READ_NO_INSERT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_READ_NO_INSERT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_READ_NO_INSERT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_READ_NO_INSERT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_READ_NO_INSERT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_READ_EXTERNAL") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_READ_EXTERNAL") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_READ_EXTERNAL") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_READ_EXTERNAL") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_READ_EXTERNAL") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_WRITE_ALLOW_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WRITE_ALLOW_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WRITE_ALLOW_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WRITE_ALLOW_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WRITE_ALLOW_WRITE") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_WRITE_CONCURRENT_INSERT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WRITE_CONCURRENT_INSERT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WRITE_CONCURRENT_INSERT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WRITE_CONCURRENT_INSERT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WRITE_CONCURRENT_INSERT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_WRITE_DELAYED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WRITE_DELAYED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WRITE_DELAYED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WRITE_DELAYED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WRITE_DELAYED") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_WRITE_LOW_PRIORITY") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WRITE_LOW_PRIORITY") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WRITE_LOW_PRIORITY") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WRITE_LOW_PRIORITY") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WRITE_LOW_PRIORITY") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_WRITE_NORMAL") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WRITE_NORMAL") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WRITE_NORMAL") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WRITE_NORMAL") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WRITE_NORMAL") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_WRITE_EXTERNAL") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WRITE_EXTERNAL") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WRITE_EXTERNAL") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WRITE_EXTERNAL") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WRITE_EXTERNAL") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_tlws_by_table::m_field_def= -{ 73, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_tlws_by_table::m_share= { @@ -414,8 +41,80 @@ table_tlws_by_table::m_share= 1000, /* records */ sizeof(PFS_simple_index), &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE table_lock_waits_summary_by_table(" + "OBJECT_TYPE VARCHAR(64)," + "OBJECT_SCHEMA VARCHAR(64)," + "OBJECT_NAME VARCHAR(64)," + "COUNT_STAR BIGINT unsigned not null," + "SUM_TIMER_WAIT BIGINT unsigned not null," + "MIN_TIMER_WAIT BIGINT unsigned not null," + "AVG_TIMER_WAIT BIGINT unsigned not null," + "MAX_TIMER_WAIT BIGINT unsigned not null," + "COUNT_READ BIGINT unsigned not null," + "SUM_TIMER_READ BIGINT unsigned not null," + "MIN_TIMER_READ BIGINT unsigned not null," + "AVG_TIMER_READ BIGINT unsigned not null," + "MAX_TIMER_READ BIGINT unsigned not null," + "COUNT_WRITE BIGINT unsigned not null," + "SUM_TIMER_WRITE BIGINT unsigned not null," + "MIN_TIMER_WRITE BIGINT unsigned not null," + "AVG_TIMER_WRITE BIGINT unsigned not null," + "MAX_TIMER_WRITE BIGINT unsigned not null," + "COUNT_READ_NORMAL BIGINT unsigned not null," + "SUM_TIMER_READ_NORMAL BIGINT unsigned not null," + "MIN_TIMER_READ_NORMAL BIGINT unsigned not null," + "AVG_TIMER_READ_NORMAL BIGINT unsigned not null," + "MAX_TIMER_READ_NORMAL BIGINT unsigned not null," + "COUNT_READ_WITH_SHARED_LOCKS BIGINT unsigned not null," + "SUM_TIMER_READ_WITH_SHARED_LOCKS BIGINT unsigned not null," + "MIN_TIMER_READ_WITH_SHARED_LOCKS BIGINT unsigned not null," + "AVG_TIMER_READ_WITH_SHARED_LOCKS BIGINT unsigned not null," + "MAX_TIMER_READ_WITH_SHARED_LOCKS BIGINT unsigned not null," + "COUNT_READ_HIGH_PRIORITY BIGINT unsigned not null," + "SUM_TIMER_READ_HIGH_PRIORITY BIGINT unsigned not null," + "MIN_TIMER_READ_HIGH_PRIORITY BIGINT unsigned not null," + "AVG_TIMER_READ_HIGH_PRIORITY BIGINT unsigned not null," + "MAX_TIMER_READ_HIGH_PRIORITY BIGINT unsigned not null," + "COUNT_READ_NO_INSERT BIGINT unsigned not null," + "SUM_TIMER_READ_NO_INSERT BIGINT unsigned not null," + "MIN_TIMER_READ_NO_INSERT BIGINT unsigned not null," + "AVG_TIMER_READ_NO_INSERT BIGINT unsigned not null," + "MAX_TIMER_READ_NO_INSERT BIGINT unsigned not null," + "COUNT_READ_EXTERNAL BIGINT unsigned not null," + "SUM_TIMER_READ_EXTERNAL BIGINT unsigned not null," + "MIN_TIMER_READ_EXTERNAL BIGINT unsigned not null," + "AVG_TIMER_READ_EXTERNAL BIGINT unsigned not null," + "MAX_TIMER_READ_EXTERNAL BIGINT unsigned not null," + "COUNT_WRITE_ALLOW_WRITE BIGINT unsigned not null," + "SUM_TIMER_WRITE_ALLOW_WRITE BIGINT unsigned not null," + "MIN_TIMER_WRITE_ALLOW_WRITE BIGINT unsigned not null," + "AVG_TIMER_WRITE_ALLOW_WRITE BIGINT unsigned not null," + "MAX_TIMER_WRITE_ALLOW_WRITE BIGINT unsigned not null," + "COUNT_WRITE_CONCURRENT_INSERT BIGINT unsigned not null," + "SUM_TIMER_WRITE_CONCURRENT_INSERT BIGINT unsigned not null," + "MIN_TIMER_WRITE_CONCURRENT_INSERT BIGINT unsigned not null," + "AVG_TIMER_WRITE_CONCURRENT_INSERT BIGINT unsigned not null," + "MAX_TIMER_WRITE_CONCURRENT_INSERT BIGINT unsigned not null," + "COUNT_WRITE_DELAYED BIGINT unsigned not null," + "SUM_TIMER_WRITE_DELAYED BIGINT unsigned not null," + "MIN_TIMER_WRITE_DELAYED BIGINT unsigned not null," + "AVG_TIMER_WRITE_DELAYED BIGINT unsigned not null," + "MAX_TIMER_WRITE_DELAYED BIGINT unsigned not null," + "COUNT_WRITE_LOW_PRIORITY BIGINT unsigned not null," + "SUM_TIMER_WRITE_LOW_PRIORITY BIGINT unsigned not null," + "MIN_TIMER_WRITE_LOW_PRIORITY BIGINT unsigned not null," + "AVG_TIMER_WRITE_LOW_PRIORITY BIGINT unsigned not null," + "MAX_TIMER_WRITE_LOW_PRIORITY BIGINT unsigned not null," + "COUNT_WRITE_NORMAL BIGINT unsigned not null," + "SUM_TIMER_WRITE_NORMAL BIGINT unsigned not null," + "MIN_TIMER_WRITE_NORMAL BIGINT unsigned not null," + "AVG_TIMER_WRITE_NORMAL BIGINT unsigned not null," + "MAX_TIMER_WRITE_NORMAL BIGINT unsigned not null," + "COUNT_WRITE_EXTERNAL BIGINT unsigned not null," + "SUM_TIMER_WRITE_EXTERNAL BIGINT unsigned not null," + "MIN_TIMER_WRITE_EXTERNAL BIGINT unsigned not null," + "AVG_TIMER_WRITE_EXTERNAL BIGINT unsigned not null," + "MAX_TIMER_WRITE_EXTERNAL BIGINT unsigned not null)") } }; PFS_engine_table* diff --git a/storage/perfschema/table_tlws_by_table.h b/storage/perfschema/table_tlws_by_table.h index fc396447bcf..f5bf6a99f46 100644 --- a/storage/perfschema/table_tlws_by_table.h +++ b/storage/perfschema/table_tlws_by_table.h @@ -76,8 +76,6 @@ protected: private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_tlws_by_table m_row; diff --git a/storage/perfschema/table_users.cc b/storage/perfschema/table_users.cc index 1f6b861342d..134ebb08d26 100644 --- a/storage/perfschema/table_users.cc +++ b/storage/perfschema/table_users.cc @@ -24,29 +24,6 @@ THR_LOCK table_users::m_table_lock; -static const TABLE_FIELD_TYPE field_types[]= -{ - { - { C_STRING_WITH_LEN("USER") }, - { C_STRING_WITH_LEN("char(16)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("CURRENT_CONNECTIONS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("TOTAL_CONNECTIONS") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_users::m_field_def= -{ 3, field_types, 0, (uint*) 0 }; - PFS_engine_table_share table_users::m_share= { @@ -59,8 +36,10 @@ table_users::m_share= 1000, /* records */ sizeof(PFS_simple_index), /* ref length */ &m_table_lock, - &m_field_def, - false /* checked */ + { C_STRING_WITH_LEN("CREATE TABLE users(" + "USER CHAR(16) collate utf8_bin default null," + "CURRENT_CONNECTIONS bigint not null," + "TOTAL_CONNECTIONS bigint not null)") } }; PFS_engine_table* table_users::create() diff --git a/storage/perfschema/table_users.h b/storage/perfschema/table_users.h index 94ea44832d1..5d673cbda9c 100644 --- a/storage/perfschema/table_users.h +++ b/storage/perfschema/table_users.h @@ -67,8 +67,6 @@ private: /** Table share lock. */ static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; /** Current row. */ row_users m_row; From 21b4dec072b194eaa6d97a8917c1bf5d7434c99d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Thu, 21 Aug 2014 16:08:51 +0300 Subject: [PATCH 011/153] Review fixes. --- include/thr_lock.h | 24 +- include/wsrep.h | 58 ++ mysys/my_default.c | 2 +- mysys/my_static.c | 4 + mysys/mysys_priv.h | 2 + mysys/thr_lock.c | 56 +- scripts/wsrep_sst_common | 4 +- scripts/wsrep_sst_common.sh | 4 +- scripts/wsrep_sst_mysqldump | 7 +- scripts/wsrep_sst_mysqldump.sh | 7 +- sql/events.cc | 3 +- sql/ha_partition.cc | 5 +- sql/handler.cc | 142 ++--- sql/handler.h | 1 - sql/item_func.cc | 14 +- sql/lock.cc | 60 +- sql/log.cc | 290 +++------ sql/log.h | 27 +- sql/log_event.cc | 171 ++--- sql/log_event.h | 7 +- sql/mdl.cc | 93 ++- sql/mdl.h | 8 +- sql/mysqld.cc | 641 +++---------------- sql/mysqld.h | 9 +- sql/protocol.cc | 10 +- sql/rpl_record.cc | 33 +- sql/slave.cc | 19 +- sql/sp.cc | 39 +- sql/sp.h | 15 + sql/sql_acl.cc | 33 +- sql/sql_admin.cc | 3 +- sql/sql_alter.cc | 6 +- sql/sql_base.cc | 31 +- sql/sql_class.cc | 279 +------- sql/sql_class.h | 26 +- sql/sql_connect.cc | 6 +- sql/sql_delete.cc | 29 +- sql/sql_insert.cc | 57 +- sql/sql_lex.cc | 4 +- sql/sql_parse.cc | 253 +++----- sql/sql_parse.h | 17 - sql/sql_partition_admin.cc | 23 +- sql/sql_plugin.cc | 22 +- sql/sql_prepare.cc | 36 +- sql/sql_repl.cc | 10 +- sql/sql_show.cc | 10 +- sql/sql_table.cc | 76 +-- sql/sql_trigger.cc | 60 +- sql/sql_truncate.cc | 2 - sql/sql_update.cc | 23 +- sql/sys_vars.cc | 2 - sql/table.cc | 2 - sql/transaction.cc | 42 +- sql/tztime.cc | 3 +- sql/wsrep_binlog.cc | 8 +- sql/wsrep_hton.cc | 2 +- sql/wsrep_mysqld.cc | 880 +++++++++++++++++++++++++- sql/wsrep_mysqld.h | 57 +- sql/wsrep_sst.h | 2 +- sql/wsrep_thd.h | 2 +- sql/wsrep_var.h | 2 +- storage/innobase/handler/ha_innodb.cc | 52 +- 62 files changed, 1811 insertions(+), 2004 deletions(-) create mode 100644 include/wsrep.h diff --git a/include/thr_lock.h b/include/thr_lock.h index f05db666da9..2561709285f 100644 --- a/include/thr_lock.h +++ b/include/thr_lock.h @@ -20,16 +20,6 @@ #ifdef __cplusplus extern "C" { #endif -#ifdef WITH_WSREP -#include - typedef my_bool (* wsrep_thd_is_brute_force_fun)(void *, my_bool); - typedef int (* wsrep_abort_thd_fun)(void *, void *, my_bool); - typedef int (* wsrep_on_fun)(void *); - void wsrep_thr_lock_init( - wsrep_thd_is_brute_force_fun bf_fun, wsrep_abort_thd_fun abort_fun, - my_bool debug, my_bool convert_LOCK_to_trx, wsrep_on_fun on_fun); -#endif - #include #include @@ -104,10 +94,7 @@ typedef struct st_thr_lock_info { pthread_t thread; my_thread_id thread_id; -#ifdef WITH_WSREP void *mysql_thd; // THD pointer - my_bool in_lock_tables; // true, if inside locking session -#endif } THR_LOCK_INFO; @@ -177,6 +164,17 @@ my_bool thr_reschedule_write_lock(THR_LOCK_DATA *data, ulong lock_wait_timeout); void thr_set_lock_wait_callback(void (*before_wait)(void), void (*after_wait)(void)); + +#ifdef WITH_WSREP +#include + typedef my_bool (* wsrep_thd_is_brute_force_fun)(void *, my_bool); + typedef int (* wsrep_abort_thd_fun)(void *, void *, my_bool); + typedef int (* wsrep_on_fun)(void *); + void wsrep_thr_lock_init( + wsrep_thd_is_brute_force_fun bf_fun, wsrep_abort_thd_fun abort_fun, + my_bool debug, my_bool convert_LOCK_to_trx, wsrep_on_fun on_fun); +#endif + #ifdef __cplusplus } #endif diff --git a/include/wsrep.h b/include/wsrep.h new file mode 100644 index 00000000000..c261d9c4b5f --- /dev/null +++ b/include/wsrep.h @@ -0,0 +1,58 @@ +/* Copyright 2014 Codership Oy & SkySQL Ab + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef WSREP_INCLUDED +#define WSERP_INCLUDED + +#ifdef WITH_WSREP +#define IF_WSREP(A,B) A +#define DBUG_ASSERT_IF_WSREP(A) DBUG_ASSERT(A) + +#if !defined(EMBEDDED_LIBRARY) +#define WSREP_FORMAT(my_format) \ + ((wsrep_forced_binlog_format != BINLOG_FORMAT_UNSPEC) ? \ + wsrep_forced_binlog_format : my_format) +#else +#define WSREP_FORMAT(my_format) my_format +#endif /* && !EMBEDDED_LIBRARY */ + +#define WSREP_MYSQL_DB (char *)"mysql" +#define WSREP_TO_ISOLATION_BEGIN(db_, table_, table_list_) \ + if (WSREP_ON && WSREP(thd) && wsrep_to_isolation_begin(thd, db_, table_, table_list_)) \ + goto error; + +#define WSREP_TO_ISOLATION_END \ + if (WSREP_ON && (WSREP(thd) || (thd && thd->wsrep_exec_mode==TOTAL_ORDER))) \ + wsrep_to_isolation_end(thd); + +#define WSREP_DEBUG(...) \ + if (wsrep_debug) WSREP_LOG(sql_print_information, ##__VA_ARGS__) +#define WSREP_INFO(...) WSREP_LOG(sql_print_information, ##__VA_ARGS__) +#define WSREP_WARN(...) WSREP_LOG(sql_print_warning, ##__VA_ARGS__) +#define WSREP_ERROR(...) WSREP_LOG(sql_print_error, ##__VA_ARGS__) + +#else +#define IF_WSREP(A,B) B +#define DBUG_ASSERT_IF_WSREP(A) +#define WSREP_DEBUG(...) +#define WSREP_INFO(...) +#define WSREP_WARN(...) +#define WSREP_ERROR(...) +#define WSREP_FORMAT(my_format) my_format +#define WSREP_TO_ISOLATION_BEGIN(db_, table_, table_list_) +#define WSREP_TO_ISOLATION_END +#endif + +#endif /* WSERP_INCLUDED */ diff --git a/mysys/my_default.c b/mysys/my_default.c index 4721382acc2..1a29fd87a34 100644 --- a/mysys/my_default.c +++ b/mysys/my_default.c @@ -813,7 +813,7 @@ static int search_default_file_with_ext(Process_option_func opt_handler, #ifdef WITH_WSREP /* make sure we do this only once - for top-level file */ if ('\0' == wsrep_defaults_file[0]) - strncpy(wsrep_defaults_file, name, sizeof(wsrep_defaults_file) - 1); + strmake(wsrep_defaults_file, name, sizeof(wsrep_defaults_file) - 1); #endif /* WITH_WSREP */ while (mysql_file_fgets(buff, sizeof(buff) - 1, fp)) diff --git a/mysys/my_static.c b/mysys/my_static.c index 84d2dc64fc6..4c977837e05 100644 --- a/mysys/my_static.c +++ b/mysys/my_static.c @@ -68,6 +68,10 @@ uint my_large_page_size= 0; int volatile my_have_got_alarm=0; /* declare variable to reset */ ulong my_time_to_wait_for_lock=2; /* In seconds */ +#ifdef WITH_WSREP +my_bool mysys_wsrep= 0; +#endif + /* from errors.c */ #ifdef SHARED_LIBRARY const char *globerrs[GLOBERRS]; /* my_error_messages is here */ diff --git a/mysys/mysys_priv.h b/mysys/mysys_priv.h index 9c6855bb92f..80c6a981db2 100644 --- a/mysys/mysys_priv.h +++ b/mysys/mysys_priv.h @@ -62,6 +62,8 @@ extern mysql_mutex_t THR_LOCK_malloc, THR_LOCK_open, THR_LOCK_keycache; extern mysql_mutex_t THR_LOCK_lock, THR_LOCK_net; extern mysql_mutex_t THR_LOCK_charset; +extern my_bool mysys_wsrep; + #include #ifdef HAVE_PSI_INTERFACE diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index 80a43974324..acc7d718546 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -683,10 +683,10 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, * This needs an condition to check for bf locks first. * TODO: we still have a debug fprintf, this should be removed */ -static inline my_bool +static my_bool wsrep_break_lock( THR_LOCK_DATA *data, struct st_lock_list *lock_queue1, - struct st_lock_list *lock_queue2, struct st_lock_list *wait_queue) + struct st_lock_list *wait_queue) { if (wsrep_on(data->owner->mysql_thd) && wsrep_thd_is_brute_force && @@ -698,7 +698,7 @@ wsrep_break_lock( we know that this conflicting lock must be read lock and furthermore, lock holder is read-only. It is safe to wait for him. */ -#ifdef TODO +#ifdef TODO_WHEN_LOCK_TABLES_IS_A_TRANSACTION if (wsrep_convert_LOCK_to_trx && (THD*)(data->owner->mysql_thd)->in_lock_tables) { @@ -727,22 +727,6 @@ wsrep_break_lock( return FALSE; } } - for (holder=(lock_queue2) ? lock_queue2->data : NULL; - holder; - holder=holder->next) - { - if (!wsrep_thd_is_brute_force(holder->owner->mysql_thd, TRUE)) - { - wsrep_abort_thd(data->owner->mysql_thd, - holder->owner->mysql_thd, FALSE); - } - else - { - if (wsrep_debug) - fprintf(stderr,"WSREP wsrep_break_lock skipping BF lock conflict\n"); - return FALSE; - } - } /* Add our lock to the head of the wait queue */ if (*(wait_queue->last)==wait_queue->data) @@ -846,14 +830,6 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) } if (lock->write.data->type == TL_WRITE_ONLY) { -#ifdef WITH_WSREP - if (wsrep_break_lock(data, &lock->write, NULL, &lock->read_wait)) - { - wsrep_lock_inserted= TRUE; - goto wsrep_read_wait; - } -#endif - /* We are not allowed to get a READ lock in this case */ data->type=TL_UNLOCK; result= THR_LOCK_ABORTED; /* Can't wait for this one */ @@ -882,7 +858,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) In the latter case we should yield the lock to the writer. */ #ifdef WITH_WSREP - if (wsrep_break_lock(data, &lock->write, NULL, &lock->read_wait)) + if (mysys_wsrep && wsrep_break_lock(data, &lock->write, &lock->read_wait)) { wsrep_lock_inserted= TRUE; } @@ -897,25 +873,12 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) { if (lock->write.data && lock->write.data->type == TL_WRITE_ONLY) { -#ifdef WITH_WSREP - if (wsrep_break_lock(data, &lock->write, NULL, &lock->write_wait)) - { - wsrep_lock_inserted=TRUE; - goto wsrep_write_wait; - } -#endif data->type=TL_UNLOCK; result= THR_LOCK_ABORTED; /* Can't wait for this one */ goto end; } if (lock->write.data || lock->read.data) { -#ifdef WITH_WSREP - if (wsrep_break_lock(data, &lock->write, NULL, &lock->write_wait)) - { - goto end; - } -#endif /* Add delayed write lock to write_wait queue, and return at once */ (*lock->write_wait.last)=data; data->prev=lock->write_wait.last; @@ -940,13 +903,6 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) /* Allow lock owner to bypass TL_WRITE_ONLY. */ if (!thr_lock_owner_equal(data->owner, lock->write.data->owner)) { -#ifdef WITH_WSREP - if (wsrep_break_lock(data, &lock->write, NULL, &lock->write_wait)) - { - wsrep_lock_inserted=TRUE; - goto wsrep_write_wait; - } -#endif /* We are not allowed to get a lock in this case */ data->type=TL_UNLOCK; result= THR_LOCK_ABORTED; /* Can't wait for this one */ @@ -1051,7 +1007,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) lock->read.data->owner->thread_id, data->type)); } #ifdef WITH_WSREP - if (wsrep_break_lock(data, &lock->write, NULL, &lock->write_wait)) + if (mysys_wsrep && wsrep_break_lock(data, &lock->write, &lock->write_wait)) { wsrep_lock_inserted= TRUE; } @@ -1063,7 +1019,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) } /* Can't get lock yet; Wait for it */ #ifdef WITH_WSREP - if (wsrep_on(data->owner->mysql_thd) && wsrep_lock_inserted) + if (mysys_wsrep && wsrep_lock_inserted && wsrep_on(data->owner->mysql_thd)) DBUG_RETURN(wait_for_lock(wait_queue, data, 1, lock_wait_timeout)); #endif result= wait_for_lock(wait_queue, data, 0, lock_wait_timeout); diff --git a/scripts/wsrep_sst_common b/scripts/wsrep_sst_common index 333d9dfab9a..88f5d80f53a 100755 --- a/scripts/wsrep_sst_common +++ b/scripts/wsrep_sst_common @@ -94,7 +94,7 @@ done readonly WSREP_SST_OPT_BYPASS readonly WSREP_SST_OPT_BINLOG -# For Bug:1200727 +# State Snapshot Transfer authentication password was displayed in the ps output. Bug fixed #1200727. if my_print_defaults -c $WSREP_SST_OPT_CONF sst | grep -q "wsrep_sst_auth";then if [ -z "$WSREP_SST_OPT_AUTH" -o "$WSREP_SST_OPT_AUTH" = "(null)" ];then WSREP_SST_OPT_AUTH=$(my_print_defaults -c $WSREP_SST_OPT_CONF sst | grep -- "--wsrep_sst_auth" | cut -d= -f2) @@ -114,7 +114,7 @@ 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 + echo "$tst WSREP_SST: " >&2 } wsrep_log_error() diff --git a/scripts/wsrep_sst_common.sh b/scripts/wsrep_sst_common.sh index 333d9dfab9a..88f5d80f53a 100644 --- a/scripts/wsrep_sst_common.sh +++ b/scripts/wsrep_sst_common.sh @@ -94,7 +94,7 @@ done readonly WSREP_SST_OPT_BYPASS readonly WSREP_SST_OPT_BINLOG -# For Bug:1200727 +# State Snapshot Transfer authentication password was displayed in the ps output. Bug fixed #1200727. if my_print_defaults -c $WSREP_SST_OPT_CONF sst | grep -q "wsrep_sst_auth";then if [ -z "$WSREP_SST_OPT_AUTH" -o "$WSREP_SST_OPT_AUTH" = "(null)" ];then WSREP_SST_OPT_AUTH=$(my_print_defaults -c $WSREP_SST_OPT_CONF sst | grep -- "--wsrep_sst_auth" | cut -d= -f2) @@ -114,7 +114,7 @@ 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 + echo "$tst WSREP_SST: " >&2 } wsrep_log_error() diff --git a/scripts/wsrep_sst_mysqldump b/scripts/wsrep_sst_mysqldump index 3fce316f379..d4093dbcaef 100755 --- a/scripts/wsrep_sst_mysqldump +++ b/scripts/wsrep_sst_mysqldump @@ -24,11 +24,10 @@ WSREP_SST_OPT_CONF="" . $(dirname $0)/wsrep_sst_common EINVAL=22 +PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin local_ip() { - PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin - [ "$1" = "127.0.0.1" ] && return 0 [ "$1" = "localhost" ] && return 0 [ "$1" = "$(hostname -s)" ] && return 0 @@ -58,10 +57,10 @@ then fi # Check client version -if ! mysql --version | grep 'Distrib 10.0' >/dev/null +if ! mysql --version | grep 'Distrib 10' >/dev/null then mysql --version >&2 - wsrep_log_error "this operation requires MySQL client version 10.0.x" + wsrep_log_error "this operation requires MySQL client version 10 or newer" exit $EINVAL fi diff --git a/scripts/wsrep_sst_mysqldump.sh b/scripts/wsrep_sst_mysqldump.sh index 3fce316f379..d4093dbcaef 100644 --- a/scripts/wsrep_sst_mysqldump.sh +++ b/scripts/wsrep_sst_mysqldump.sh @@ -24,11 +24,10 @@ WSREP_SST_OPT_CONF="" . $(dirname $0)/wsrep_sst_common EINVAL=22 +PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin local_ip() { - PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin - [ "$1" = "127.0.0.1" ] && return 0 [ "$1" = "localhost" ] && return 0 [ "$1" = "$(hostname -s)" ] && return 0 @@ -58,10 +57,10 @@ then fi # Check client version -if ! mysql --version | grep 'Distrib 10.0' >/dev/null +if ! mysql --version | grep 'Distrib 10' >/dev/null then mysql --version >&2 - wsrep_log_error "this operation requires MySQL client version 10.0.x" + wsrep_log_error "this operation requires MySQL client version 10 or newer" exit $EINVAL fi diff --git a/sql/events.cc b/sql/events.cc index a14f1a6c384..5a5a8893f5e 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -1190,7 +1190,8 @@ end: #ifdef WITH_WSREP int wsrep_create_event_query(THD *thd, uchar** buf, size_t* buf_len) { - String log_query; + char buffer[1024]; + String log_query(buffer, sizeof(buffer), &my_charset_bin); if (create_query_string(thd, &log_query)) { diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 3ddd668fd12..23af3825756 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -386,14 +386,17 @@ const char *ha_partition::table_type() const // we can do this since we only support a single engine type return m_file[0]->table_type(); } + + #if defined(WITH_WSREP) && !defined(EMBEDDED_LIBRARY) int ha_partition::wsrep_db_type() const { // we can do this since we only support a single engine type - return ha_legacy_type(m_file[0]->ht); + return partition_ht()->db_type; } #endif /* WITH_WSREP && !EMBEDDED_LIBRARY */ + /* Destructor method diff --git a/sql/handler.cc b/sql/handler.cc index 2b91428460b..2bc6858df48 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -50,9 +50,9 @@ #include "../storage/maria/ha_maria.h" #endif -#ifdef WITH_WSREP #include "wsrep_mysqld.h" -#endif +#include "wsrep.h" + /* While we have legacy_db_type, we have this array to check for dups and to find handlerton from legacy_db_type. @@ -1169,26 +1169,24 @@ int ha_prepare(THD *thd) if ((err= ht->prepare(ht, thd, all))) { #ifdef WITH_WSREP - if (WSREP(thd) && ht->db_type== DB_TYPE_WSREP) + if (ht == wsrep_hton) { - error= 1; - /* avoid sending error, if we need to replay */ + error= 1; + /* avoid sending error, if we need to replay */ if (thd->wsrep_conflict_state!= MUST_REPLAY) { my_error(ER_LOCK_DEADLOCK, MYF(0), err); } } else +#endif { /* not wsrep hton, bail to native mysql behavior */ -#endif - my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); - ha_rollback_trans(thd, all); - error=1; - break; -#ifdef WITH_WSREP + my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); + ha_rollback_trans(thd, all); + error=1; + break; } -#endif } } else @@ -1386,13 +1384,9 @@ int ha_commit_trans(THD *thd, bool all) mdl_request.init(MDL_key::COMMIT, "", "", MDL_INTENTION_EXCLUSIVE, MDL_EXPLICIT); -#ifdef WITH_WSREP - if (!WSREP(thd) && + if (IF_WSREP(!WSREP(thd),1) && thd->mdl_context.acquire_lock(&mdl_request, -#else - if (thd->mdl_context.acquire_lock(&mdl_request, -#endif /* WITH_WSREP */ - thd->variables.lock_wait_timeout)) + thd->variables.lock_wait_timeout)) { ha_rollback_trans(thd, all); thd->wakeup_subsequent_commits(1); @@ -1439,15 +1433,13 @@ int ha_commit_trans(THD *thd, bool all) err= ht->prepare(ht, thd, all); status_var_increment(thd->status_var.ha_prepare_count); if (err) -#ifdef WITH_WSREP { - if (WSREP(thd) && ht->db_type== DB_TYPE_WSREP) +#ifdef WITH_WSREP + if (ht == wsrep_hton) { - error= 1; - switch (err) - { + switch (err) { case WSREP_TRX_SIZE_EXCEEDED: - /* give user size exeeded erro from wsrep_api.h */ + /* give user size exeeded error from wsrep_api.h */ my_error(ER_ERROR_DURING_COMMIT, MYF(0), WSREP_SIZE_EXCEEDED); break; case WSREP_TRX_CERT_FAIL: @@ -1458,15 +1450,11 @@ int ha_commit_trans(THD *thd, bool all) my_error(ER_LOCK_DEADLOCK, MYF(0), err); } } + goto err; } - else - /* not wsrep hton, bail to native mysql behavior */ #endif /* WITH_WSREP */ my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); -#ifdef WITH_WSREP } -#endif /* WITH_WSREP */ - if (err) goto err; @@ -1477,12 +1465,13 @@ int ha_commit_trans(THD *thd, bool all) DBUG_EXECUTE_IF("crash_commit_after_prepare", DBUG_SUICIDE();); #ifdef WITH_WSREP - if (!error && wsrep_is_wsrep_xid(&thd->transaction.xid_state.xid)) + if (!error && WSREP_ON && wsrep_is_wsrep_xid(&thd->transaction.xid_state.xid)) { // xid was rewritten by wsrep xid= wsrep_xid_seqno(&thd->transaction.xid_state.xid); } #endif // WITH_WSREP + if (!is_real_trans) { error= commit_one_phase_2(thd, all, trans, is_real_trans); @@ -1859,13 +1848,10 @@ static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin, got, hton_name(hton)->str); for (int i=0; i < got; i ++) { -#ifdef WITH_WSREP - my_xid x=(wsrep_is_wsrep_xid(&info->list[i]) ? - wsrep_xid_seqno(&info->list[i]) : - info->list[i].get_my_xid()); -#else - my_xid x=info->list[i].get_my_xid(); -#endif /* WITH_WSREP */ + my_xid x= IF_WSREP(WSREP_ON && wsrep_is_wsrep_xid(&info->list[i]) ? + wsrep_xid_seqno(&info->list[i]) : + info->list[i].get_my_xid(), + info->list[i].get_my_xid()); if (!x) // not "mine" - that is generated by external TM { #ifndef DBUG_OFF @@ -3150,15 +3136,12 @@ int handler::update_auto_increment() variables->auto_increment_increment); auto_inc_intervals_count++; /* Row-based replication does not need to store intervals in binlog */ -#ifdef WITH_WSREP - if (((WSREP(thd) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()) && - !thd->is_current_stmt_binlog_format_row()) -#else - if (mysql_bin_log.is_open() && !thd->is_current_stmt_binlog_format_row()) -#endif /* WITH_WSREP */ - thd->auto_inc_intervals_in_cur_stmt_for_binlog.append(auto_inc_interval_for_cur_row.minimum(), - auto_inc_interval_for_cur_row.values(), - variables->auto_increment_increment); + if (IF_WSREP((WSREP(thd) && (wsrep_emulate_bin_log || mysql_bin_log.is_open())), mysql_bin_log.is_open()) + && !thd->is_current_stmt_binlog_format_row()) + thd->auto_inc_intervals_in_cur_stmt_for_binlog. + append(auto_inc_interval_for_cur_row.minimum(), + auto_inc_interval_for_cur_row.values(), + variables->auto_increment_increment); } /* @@ -5776,13 +5759,9 @@ static bool check_table_binlog_row_based(THD *thd, TABLE *table) return (thd->is_current_stmt_binlog_format_row() && table->s->cached_row_logging_check && (thd->variables.option_bits & OPTION_BIN_LOG) && -#ifdef WITH_WSREP /* applier and replayer should not binlog */ - ((WSREP_EMULATE_BINLOG(thd) && (thd->wsrep_exec_mode != REPL_RECV)) || + (IF_WSREP((WSREP_EMULATE_BINLOG(thd) && (thd->wsrep_exec_mode != REPL_RECV)),0) || mysql_bin_log.is_open())); -#else - mysql_bin_log.is_open()); -#endif } @@ -5884,14 +5863,9 @@ static int binlog_log_row(TABLE* table, #ifdef WITH_WSREP /* only InnoDB tables will be replicated through binlog emulation */ - if (WSREP_EMULATE_BINLOG(thd) && - table->file->ht->db_type != DB_TYPE_INNODB && - !(table->file->ht->db_type == DB_TYPE_PARTITION_DB && - (((ha_partition*)(table->file))->wsrep_db_type() == DB_TYPE_INNODB))) - // !strcmp(table->file->table_type(), "InnoDB")) - { + if (WSREP_ON && WSREP_EMULATE_BINLOG(thd) && + table->file->partition_ht()->db_type != DB_TYPE_INNODB) return 0; - } #endif /* WITH_WSREP */ if (check_table_binlog_row_based(thd, table)) { @@ -6240,46 +6214,58 @@ void handler::set_lock_type(enum thr_lock_type lock) int ha_wsrep_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal) { DBUG_ENTER("ha_wsrep_abort_transaction"); - if (!WSREP(bf_thd) && + if (!WSREP(bf_thd) && !(wsrep_OSU_method_options == WSREP_OSU_RSU && bf_thd->wsrep_exec_mode == TOTAL_ORDER)) { DBUG_RETURN(0); } - handlerton *hton= installed_htons[DB_TYPE_INNODB]; - if (hton && hton->wsrep_abort_transaction) - { - hton->wsrep_abort_transaction(hton, bf_thd, victim_thd, signal); - } - else - { - WSREP_WARN("cannot abort InnoDB transaction"); - } + THD_TRANS *trans= &victim_thd->transaction.all; + Ha_trx_info *ha_info= trans->ha_list, *ha_info_next; + for (; ha_info; ha_info= ha_info_next) + { + handlerton *hton= ha_info->ht(); + if (!hton->wsrep_abort_transaction) + { + WSREP_WARN("cannot abort WRESP transaction"); + } + else + hton->wsrep_abort_transaction(hton, bf_thd, victim_thd, signal); + ha_info_next= ha_info->next(); + ha_info->reset(); /* keep it conveniently zero-filled */ + } DBUG_RETURN(0); } void ha_wsrep_fake_trx_id(THD *thd) { DBUG_ENTER("ha_wsrep_fake_trx_id"); - if (!WSREP(thd)) + if (!WSREP(thd)) { DBUG_VOID_RETURN; } - handlerton *hton= installed_htons[DB_TYPE_INNODB]; - if (hton && hton->wsrep_fake_trx_id) - { - hton->wsrep_fake_trx_id(hton, thd); - } - else - { - WSREP_WARN("cannot get fake InnoDB transaction ID"); - } + THD_TRANS *trans= &thd->transaction.all; + Ha_trx_info *ha_info= trans->ha_list, *ha_info_next; + for (; ha_info; ha_info= ha_info_next) + { + handlerton *hton= ha_info->ht(); + if (!hton->wsrep_fake_trx_id) + { + WSREP_WARN("cannot get fake InnoDB transaction ID"); + } + else + hton->wsrep_fake_trx_id(hton, thd); + ha_info_next= ha_info->next(); + ha_info->reset(); /* keep it conveniently zero-filled */ + } DBUG_VOID_RETURN; } #endif /* WITH_WSREP */ + + #ifdef TRANS_LOG_MGM_EXAMPLE_CODE /* Example of transaction log management functions based on assumption that logs diff --git a/sql/handler.h b/sql/handler.h index 15382b5979b..9622cef3a11 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -439,7 +439,6 @@ enum legacy_db_type DB_TYPE_BINLOG=21, DB_TYPE_PBXT=23, DB_TYPE_PERFORMANCE_SCHEMA=28, - DB_TYPE_WSREP=41, DB_TYPE_ARIA=42, DB_TYPE_TOKUDB=43, DB_TYPE_FIRST_DYNAMIC=44, diff --git a/sql/item_func.cc b/sql/item_func.cc index ccb7ec56021..13803cff2d6 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2769,7 +2769,19 @@ void Item_func_rand::seed_random(Item *arg) TODO: do not do reinit 'rand' for every execute of PS/SP if args[0] is a constant. */ - uint32 tmp= (uint32) arg->val_int(); + uint32 tmp; +#ifdef WITH_WSREP + if (WSREP(current_thd)) + { + if (current_thd->wsrep_exec_mode==REPL_RECV) + tmp= current_thd->wsrep_rand; + else + tmp= current_thd->wsrep_rand= (uint32) arg->val_int(); + } + else +#endif /* WITH_WSREP */ + tmp= (uint32) arg->val_int(); + my_rnd_init(rand, (uint32) (tmp*0x10001L+55555555L), (uint32) (tmp*0x10000001L)); } diff --git a/sql/lock.cc b/sql/lock.cc index 7d2cddc9b78..a74a12c41c3 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -83,10 +83,7 @@ #include "sql_acl.h" // SUPER_ACL #include #include - -#ifdef WITH_WSREP #include "wsrep_mysqld.h" -#endif /* WITH_WSREP */ /** @defgroup Locking Locking @@ -318,9 +315,6 @@ bool mysql_lock_tables(THD *thd, MYSQL_LOCK *sql_lock, uint flags) /* Copy the lock data array. thr_multi_lock() reorders its contents. */ memmove(sql_lock->locks + sql_lock->lock_count, sql_lock->locks, sql_lock->lock_count * sizeof(*sql_lock->locks)); -#ifdef WITH_WSREP - thd->lock_info.in_lock_tables= thd->in_lock_tables; -#endif /* Lock on the copied half of the lock data array. */ rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks + @@ -332,26 +326,21 @@ bool mysql_lock_tables(THD *thd, MYSQL_LOCK *sql_lock, uint flags) end: THD_STAGE_INFO(thd, stage_after_table_lock); -#ifdef WITH_WSREP - thd_proc_info(thd, "mysql_lock_tables(): unlocking tables II"); -#else /* WITH_WSREP */ - thd_proc_info(thd, 0); -#endif /* WITH_WSREP */ if (thd->killed) { thd->send_kill_message(); if (!rc) + { mysql_unlock_tables(thd, sql_lock, 0); + THD_STAGE_INFO(thd, stage_after_table_lock); + } rc= 1; } else if (rc > 1) my_error(rc, MYF(0)); thd->set_time_after_lock(); -#ifdef WITH_WSREP - thd_proc_info(thd, "exit mysqld_lock_tables()"); -#endif /* WITH_WSREP */ DBUG_RETURN(rc); } @@ -396,6 +385,8 @@ static int lock_external(THD *thd, TABLE **tables, uint count) void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock) { DBUG_ENTER("mysql_unlock_tables"); + THD_STAGE_INFO(thd, stage_unlocking_tables); + if (sql_lock->table_count) unlock_external(thd, sql_lock->table, sql_lock->table_count); if (sql_lock->lock_count) @@ -1069,8 +1060,11 @@ void Global_read_lock::unlock_global_read_lock(THD *thd) thd->mdl_context.release_lock(m_mdl_blocks_commits_lock); m_mdl_blocks_commits_lock= NULL; #ifdef WITH_WSREP - wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED; - wsrep->resume(wsrep); + if (WSREP_ON) + { + wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED; + wsrep->resume(wsrep); + } #endif /* WITH_WSREP */ } thd->mdl_context.release_lock(m_mdl_global_shared_lock); @@ -1105,8 +1099,11 @@ bool Global_read_lock::make_global_read_lock_block_commit(THD *thd) make_global_read_lock_block_commit(), do nothing. */ + if (m_state != GRL_ACQUIRED) + DBUG_RETURN(0); + #ifdef WITH_WSREP - if (m_mdl_blocks_commits_lock) + if (WSREP_ON && m_mdl_blocks_commits_lock) { WSREP_DEBUG("GRL was in block commit mode when entering " "make_global_read_lock_block_commit"); @@ -1114,13 +1111,9 @@ bool Global_read_lock::make_global_read_lock_block_commit(THD *thd) m_mdl_blocks_commits_lock= NULL; wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED; wsrep->resume(wsrep); - m_state= GRL_ACQUIRED; } #endif /* WITH_WSREP */ - if (m_state != GRL_ACQUIRED) - DBUG_RETURN(0); - mdl_request.init(MDL_key::COMMIT, "", "", MDL_SHARED, MDL_EXPLICIT); if (thd->mdl_context.acquire_lock(&mdl_request, @@ -1131,19 +1124,22 @@ bool Global_read_lock::make_global_read_lock_block_commit(THD *thd) m_state= GRL_ACQUIRED_AND_BLOCKS_COMMIT; #ifdef WITH_WSREP - long long ret = wsrep->pause(wsrep); - if (ret >= 0) + if (WSREP_ON) { - wsrep_locked_seqno= ret; - } - else if (ret != -ENOSYS) /* -ENOSYS - no provider */ - { - WSREP_ERROR("Failed to pause provider: %lld (%s)", -ret, strerror(-ret)); + long long ret = wsrep->pause(wsrep); + if (ret >= 0) + { + wsrep_locked_seqno= ret; + } + else if (ret != -ENOSYS) /* -ENOSYS - no provider */ + { + WSREP_ERROR("Failed to pause provider: %lld (%s)", -ret, strerror(-ret)); - /* m_mdl_blocks_commits_lock is always NULL here */ - wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED; - my_error(ER_LOCK_DEADLOCK, MYF(0)); - DBUG_RETURN(TRUE); + DBUG_ASSERT(m_mdl_blocks_commits_lock == NULL); + wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED; + my_error(ER_LOCK_DEADLOCK, MYF(0)); + DBUG_RETURN(TRUE); + } } #endif /* WITH_WSREP */ DBUG_RETURN(FALSE); diff --git a/sql/log.cc b/sql/log.cc index 35bb0ffa0c9..1901efbb6bc 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -52,12 +52,11 @@ #include "sql_plugin.h" #include "rpl_handler.h" -#ifdef WITH_WSREP #include "wsrep_mysqld.h" -#endif /* WITH_WSREP */ #include "debug_sync.h" #include "sql_show.h" #include "my_pthread.h" +#include "wsrep_mysqld.h" /* max size of the log message */ #define MAX_LOG_BUFFER_SIZE 1024 @@ -66,6 +65,7 @@ #define FLAGSTR(V,F) ((V)&(F)?#F" ":"") +handlerton *binlog_hton; LOGGER logger; MYSQL_BIN_LOG mysql_bin_log(&sync_binlog_period); @@ -514,11 +514,6 @@ private: binlog_cache_mngr(const binlog_cache_mngr& info); }; -handlerton *binlog_hton; -#ifdef WITH_WSREP -extern handlerton *wsrep_hton; -#endif - bool LOGGER::is_log_table_enabled(uint log_table_type) { switch (log_table_type) { @@ -532,129 +527,6 @@ bool LOGGER::is_log_table_enabled(uint log_table_type) } } -#ifdef WITH_WSREP -IO_CACHE * get_trans_log(THD * thd) -{ - binlog_cache_mngr *cache_mngr = (binlog_cache_mngr*) - thd_get_ha_data(thd, binlog_hton); - if (cache_mngr) - { - return cache_mngr->get_binlog_cache_log(true); - } - else - { - WSREP_DEBUG("binlog cache not initialized, conn :%ld", thd->thread_id); - return NULL; - } -} - - -bool wsrep_trans_cache_is_empty(THD *thd) -{ - binlog_cache_mngr *const cache_mngr= - (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); - return (!cache_mngr || cache_mngr->trx_cache.empty()); -} - -void thd_binlog_flush_pending_rows_event(THD *thd, bool stmt_end) -{ - thd->binlog_flush_pending_rows_event(stmt_end); -} -void thd_binlog_trx_reset(THD * thd) -{ - /* - todo: fix autocommit select to not call the caller - */ - if (thd_get_ha_data(thd, binlog_hton) != NULL) - { - binlog_cache_mngr *const cache_mngr= - (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); - if (cache_mngr) cache_mngr->reset(false, true); - } - thd->clear_binlog_table_maps(); -} - -void thd_binlog_rollback_stmt(THD * thd) -{ - WSREP_DEBUG("thd_binlog_rollback_stmt :%ld", thd->thread_id); - binlog_cache_mngr *const cache_mngr= - (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); - if (cache_mngr) cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF); -} - -#ifdef REMOVED -/* - Write the contents of a cache to memory buffer. - - This function quite the same as MYSQL_BIN_LOG::write_cache(), - with the exception that here we write in buffer instead of log file. - */ - -int wsrep_write_cache(IO_CACHE *cache, uchar **buf, int *buf_len) -{ - - if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0)) - return ER_ERROR_ON_WRITE; - uint length= my_b_bytes_in_cache(cache); - long long total_length = 0; - uchar *buf_ptr = NULL; - - do - { - /* bail out if buffer grows too large - This is a temporary fix to avoid flooding replication - TODO: remove this check for 0.7.4 release - */ - if (total_length > wsrep_max_ws_size) - { - WSREP_WARN("transaction size limit (%lld) exceeded: %lld", - wsrep_max_ws_size, total_length); - if (reinit_io_cache(cache, WRITE_CACHE, 0, 0, 0)) - { - WSREP_WARN("failed to initialize io-cache"); - } - if (buf_ptr) my_free(*buf); - *buf_len = 0; - return ER_ERROR_ON_WRITE; - } - if (total_length > 0) - { - *buf_len += length; - *buf = (uchar *)my_realloc(*buf, total_length+length, - MYF(MY_ALLOW_ZERO_PTR)); - if (!*buf) - { - WSREP_ERROR("io cache write problem: %d %d", *buf_len, length); - return ER_ERROR_ON_WRITE; - } - buf_ptr = *buf+total_length; - } - else - { - if (buf_ptr != NULL) - { - WSREP_ERROR("io cache alloc error: %d %d", *buf_len, length); - my_free(*buf); - } - if (length > 0) - { - *buf = (uchar *) my_malloc(length, MYF(0)); - buf_ptr = *buf; - *buf_len = length; - } - } - total_length += length; - - memcpy(buf_ptr, cache->read_pos, length); - cache->read_pos=cache->read_end; - } while ((cache->file >= 0) && (length= my_b_fill(cache))); - - return 0; -} -#endif /* REMOVED */ -#endif - - /** Check if a given table is opened log table @@ -1705,11 +1577,8 @@ binlog_trans_log_savepos(THD *thd, my_off_t *pos) DBUG_ENTER("binlog_trans_log_savepos"); DBUG_ASSERT(pos != NULL); binlog_cache_mngr *const cache_mngr= thd->binlog_setup_trx_data(); -#ifdef WITH_WSREP - DBUG_ASSERT((WSREP(thd) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()); -#else - DBUG_ASSERT(mysql_bin_log.is_open()); -#endif + DBUG_ASSERT_IF_WSREP(((WSREP(thd) && wsrep_emulate_bin_log)) || mysql_bin_log.is_open()); + DBUG_ASSERT(IF_WSREP(1, mysql_bin_log.is_open())); *pos= cache_mngr->trx_cache.get_byte_position(); DBUG_PRINT("return", ("*pos: %lu", (ulong) *pos)); DBUG_VOID_RETURN; @@ -1757,16 +1626,8 @@ binlog_trans_log_truncate(THD *thd, my_off_t pos) int binlog_init(void *p) { binlog_hton= (handlerton *)p; -#ifdef WITH_WSREP - if (WSREP_ON) - binlog_hton->state= SHOW_OPTION_YES; - else - { -#endif /* WITH_WSREP */ - binlog_hton->state=opt_bin_log ? SHOW_OPTION_YES : SHOW_OPTION_NO; -#ifdef WITH_WSREP - } -#endif /* WITH_WSREP */ + binlog_hton->state=IF_WSREP(WSREP_ON || opt_bin_log, opt_bin_log) ? + SHOW_OPTION_YES : SHOW_OPTION_NO; binlog_hton->db_type=DB_TYPE_BINLOG; binlog_hton->savepoint_offset= sizeof(my_off_t); binlog_hton->close_connection= binlog_close_connection; @@ -1889,7 +1750,9 @@ binlog_commit_flush_stmt_cache(THD *thd, bool all, #ifdef WITH_WSREP if (thd->wsrep_mysql_replicated > 0) { - WSREP_DEBUG("avoiding binlog_commit_flush_trx_cache: %d", thd->wsrep_mysql_replicated); + DBUG_ASSERT(WSREP_ON); + WSREP_DEBUG("avoiding binlog_commit_flush_trx_cache: %d", + thd->wsrep_mysql_replicated); return 0; } #endif @@ -2077,7 +1940,11 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all) binlog_cache_mngr *const cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); #ifdef WITH_WSREP - if (!cache_mngr) DBUG_RETURN(0); + if (!cache_mngr) + { + DBUG_ASSERT(WSREP(thd)); + DBUG_RETURN(0); + } #endif /* WITH_WSREP */ DBUG_PRINT("debug", @@ -2136,7 +2003,12 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) binlog_cache_mngr *const cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); #ifdef WITH_WSREP - if (!cache_mngr) DBUG_RETURN(0); + if (!cache_mngr) + { + DBUG_ASSERT(WSREP(thd)); + DBUG_RETURN(0); + } + #endif /* WITH_WSREP */ DBUG_PRINT("debug", ("all: %s, all.modified_non_trans_table: %s, stmt.modified_non_trans_table: %s", @@ -2166,12 +2038,8 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) cache_mngr->reset(false, true); DBUG_RETURN(error); } -#ifdef WITH_WSREP - if (!wsrep_emulate_bin_log && + if (IF_WSREP(!wsrep_emulate_bin_log,1) && mysql_bin_log.check_write_error(thd)) -#else - if (mysql_bin_log.check_write_error(thd)) -#endif { /* "all == true" means that a "rollback statement" triggered the error and @@ -2309,13 +2177,15 @@ bool MYSQL_BIN_LOG::check_write_error(THD *thd) static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv) { - DBUG_ENTER("binlog_savepoint_set"); int error= 1; + DBUG_ENTER("binlog_savepoint_set"); + +#ifdef WITH_WSREP + if (wsrep_emulate_bin_log) + DBUG_RETURN(0); +#endif /* WITH_WSREP */ char buf[1024]; -#ifdef WITH_WSREP - if (wsrep_emulate_bin_log) DBUG_RETURN(0); -#endif /* WITH_WSREP */ String log_query(buf, sizeof(buf), &my_charset_bin); if (log_query.copy(STRING_WITH_LEN("SAVEPOINT "), &my_charset_bin) || append_identifier(thd, &log_query, @@ -2352,14 +2222,9 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) non-transactional table. Otherwise, truncate the binlog cache starting from the SAVEPOINT command. */ -#ifdef WITH_WSREP - if (!wsrep_emulate_bin_log && + if (IF_WSREP(!wsrep_emulate_bin_log, 1) && unlikely(trans_has_updated_non_trans_table(thd) || (thd->variables.option_bits & OPTION_KEEP_LOG))) -#else - if (unlikely(trans_has_updated_non_trans_table(thd) || - (thd->variables.option_bits & OPTION_KEEP_LOG))) -#endif { char buf[1024]; String log_query(buf, sizeof(buf), &my_charset_bin); @@ -2373,10 +2238,8 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) DBUG_RETURN(mysql_bin_log.write(&qinfo)); } -#ifdef WITH_WSREP - if (!wsrep_emulate_bin_log) -#endif - binlog_trans_log_truncate(thd, *(my_off_t*)sv); + if (IF_WSREP(!wsrep_emulate_bin_log, 1)) + binlog_trans_log_truncate(thd, *(my_off_t*)sv); DBUG_RETURN(0); } @@ -5505,12 +5368,8 @@ int THD::binlog_write_table_map(TABLE *table, bool is_transactional, is_transactional= 1; /* Pre-conditions */ -#ifdef WITH_WSREP - DBUG_ASSERT(is_current_stmt_binlog_format_row() && - (WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open())); -#else - DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open()); -#endif + DBUG_ASSERT(is_current_stmt_binlog_format_row()); + DBUG_ASSERT(IF_WSREP(WSREP_EMULATE_BINLOG(this), 0) || mysql_bin_log.is_open()); DBUG_ASSERT(table->s->table_map_id != ULONG_MAX); Table_map_log_event @@ -5643,11 +5502,7 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd, bool is_transactional) { DBUG_ENTER("MYSQL_BIN_LOG::flush_and_set_pending_rows_event(event)"); -#ifdef WITH_WSREP - DBUG_ASSERT(WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()); -#else - DBUG_ASSERT(mysql_bin_log.is_open()); -#endif + DBUG_ASSERT(IF_WSREP(WSREP_EMULATE_BINLOG(thd),0) || mysql_bin_log.is_open()); DBUG_PRINT("enter", ("event: 0x%lx", (long) event)); int error= 0; @@ -5973,13 +5828,9 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate) mostly called if is_open() *was* true a few instructions before, but it could have changed since. */ -#ifdef WITH_WSREP /* applier and replayer can skip writing binlog events */ - if ((WSREP_EMULATE_BINLOG(thd) && (thd->wsrep_exec_mode != REPL_RECV)) || - is_open()) -#else - if (likely(is_open())) -#endif + if (IF_WSREP((WSREP_EMULATE_BINLOG(thd) && (thd->wsrep_exec_mode != REPL_RECV)), 0) || + likely(is_open())) { my_off_t UNINIT_VAR(my_org_b_tell); #ifdef HAVE_REPLICATION @@ -6317,14 +6168,16 @@ int MYSQL_BIN_LOG::rotate(bool force_rotate, bool* check_purge) { int error= 0; DBUG_ENTER("MYSQL_BIN_LOG::rotate"); + #ifdef WITH_WSREP - if (WSREP_ON && wsrep_to_isolation) - { - *check_purge= false; - WSREP_DEBUG("avoiding binlog rotate due to TO isolation: %d", - wsrep_to_isolation); - DBUG_RETURN(0); - } + if (wsrep_to_isolation) + { + DBUG_ASSERT(WSREP_ON); + *check_purge= false; + WSREP_DEBUG("avoiding binlog rotate due to TO isolation: %d", + wsrep_to_isolation); + DBUG_RETURN(0); + } #endif //todo: fix the macro def and restore safe_mutex_assert_owner(&LOCK_log); @@ -6873,8 +6726,10 @@ MYSQL_BIN_LOG::write_transaction_to_binlog(THD *thd, DBUG_ENTER("MYSQL_BIN_LOG::write_transaction_to_binlog"); #ifdef WITH_WSREP - if (wsrep_emulate_bin_log) DBUG_RETURN(0); + if (wsrep_emulate_bin_log) + DBUG_RETURN(0); #endif /* WITH_WSREP */ + entry.thd= thd; entry.cache_mngr= cache_mngr; entry.error= 0; @@ -9020,14 +8875,10 @@ TC_LOG_BINLOG::log_and_order(THD *thd, my_xid xid, bool all, binlog_cache_mngr *cache_mngr= thd->binlog_setup_trx_data(); if (!cache_mngr) -#ifdef WITH_WSREP { WSREP_DEBUG("Skipping empty log_xid: %s", thd->query()); DBUG_RETURN(0); } -#else - DBUG_RETURN(0); -#endif /* WITH_WSREP */ cache_mngr->using_xa= TRUE; cache_mngr->xa_xid= xid; @@ -9857,3 +9708,50 @@ maria_declare_plugin(binlog) MariaDB_PLUGIN_MATURITY_STABLE /* maturity */ } maria_declare_plugin_end; + +#ifdef WITH_WSREP +IO_CACHE * get_trans_log(THD * thd) +{ + binlog_cache_mngr *cache_mngr = (binlog_cache_mngr*) + thd_get_ha_data(thd, binlog_hton); + if (cache_mngr) + return cache_mngr->get_binlog_cache_log(true); + + WSREP_DEBUG("binlog cache not initialized, conn :%ld", thd->thread_id); + return NULL; +} + + +bool wsrep_trans_cache_is_empty(THD *thd) +{ + binlog_cache_mngr *const cache_mngr= + (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); + return (!cache_mngr || cache_mngr->trx_cache.empty()); +} + + +void thd_binlog_trx_reset(THD * thd) +{ + /* + todo: fix autocommit select to not call the caller + */ + if (thd_get_ha_data(thd, binlog_hton) != NULL) + { + binlog_cache_mngr *const cache_mngr= + (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); + if (cache_mngr) + cache_mngr->reset(false, true); + } + thd->clear_binlog_table_maps(); +} + + +void thd_binlog_rollback_stmt(THD * thd) +{ + WSREP_DEBUG("thd_binlog_rollback_stmt :%ld", thd->thread_id); + binlog_cache_mngr *const cache_mngr= + (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); + if (cache_mngr) + cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF); +} +#endif /* WITH_WSREP */ diff --git a/sql/log.h b/sql/log.h index 411b06bbced..3e9a11b8b94 100644 --- a/sql/log.h +++ b/sql/log.h @@ -19,6 +19,8 @@ #include "unireg.h" // REQUIRED: for other includes #include "handler.h" /* my_xid */ +#include "wsrep.h" +#include "wsrep_mysqld.h" class Relay_log_info; @@ -106,10 +108,11 @@ public: int log_and_order(THD *thd, my_xid xid, bool all, bool need_prepare_ordered, bool need_commit_ordered) { -#ifndef WITH_WSREP - DBUG_ASSERT(0 /* Internal error - TC_LOG_DUMMY::log_and_order() called - */); -#endif + /* + If we are not using WSREP this is an Internal error + - TC_LOG_DUMMY::log_and_order() called + */ + DBUG_ASSERT(IF_WSREP(1,0)); return 1; } int unlog(ulong cookie, my_xid xid) { return 0; } @@ -984,22 +987,6 @@ enum enum_binlog_format { BINLOG_FORMAT_UNSPEC=3 ///< thd_binlog_format() returns it when binlog is closed }; -#ifdef WITH_WSREP -IO_CACHE * get_trans_log(THD * thd); -bool wsrep_trans_cache_is_empty(THD *thd); -void thd_binlog_flush_pending_rows_event(THD *thd, bool stmt_end); -void thd_binlog_trx_reset(THD * thd); -void thd_binlog_rollback_stmt(THD * thd); -#endif /* WITH_WSREP */ - -#if defined(WITH_WSREP) && !defined(EMBEDDED_LIBRARY) -#define WSREP_FORMAT(my_format) \ - ((wsrep_forced_binlog_format != BINLOG_FORMAT_UNSPEC) ? \ - wsrep_forced_binlog_format : my_format) -#else -#define WSREP_FORMAT(my_format) my_format -#endif /* WITH_WSREP && !EMBEDDED_LIBRARY */ - int query_error_code(THD *thd, bool not_killed); uint purge_log_get_error_code(int res); diff --git a/sql/log_event.cc b/sql/log_event.cc index e288f4284b7..8e5f7a1f23e 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -44,10 +44,7 @@ #include #include #include "compat56.h" - -#if WITH_WSREP #include "wsrep_mysqld.h" -#endif #endif /* MYSQL_CLIENT */ #include @@ -3094,14 +3091,16 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, master_data_written(0) { time_t end_time; + #ifdef WITH_WSREP /* If Query_log_event will contain non trans keyword (not BEGIN, COMMIT, SAVEPOINT or ROLLBACK) we disable PA for this transaction. */ - if (!is_trans_keyword()) + if (WSREP_ON && !is_trans_keyword()) thd->wsrep_PA_safe= false; #endif /* WITH_WSREP */ + memset(&user, 0, sizeof(user)); memset(&host, 0, sizeof(host)); @@ -4055,11 +4054,7 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi, uint64 sub_id= 0; rpl_gtid gtid; Relay_log_info const *rli= rgi->rli; -#ifdef WITH_WSREP - Rpl_filter *rpl_filter= (rli->mi) ? rli->mi->rpl_filter: NULL; -#else Rpl_filter *rpl_filter= rli->mi->rpl_filter; -#endif /* WITH_WSREP */ bool current_stmt_is_commit; DBUG_ENTER("Query_log_event::do_apply_event"); @@ -4534,8 +4529,9 @@ Query_log_event::do_shall_skip(rpl_group_info *rgi) } } #ifdef WITH_WSREP - else if (wsrep_mysql_replication_bundle && WSREP_ON && thd->wsrep_mysql_replicated > 0 && - (!strncasecmp(query , "BEGIN", 5) || !strncasecmp(query , "COMMIT", 6))) + else if (WSREP_ON && wsrep_mysql_replication_bundle && opt_slave_domain_parallel_threads == 0 && + thd->wsrep_mysql_replicated > 0 && + (is_begin() || is_commit())) { if (++thd->wsrep_mysql_replicated < (int)wsrep_mysql_replication_bundle) { @@ -7378,7 +7374,8 @@ Xid_log_event::do_shall_skip(rpl_group_info *rgi) DBUG_RETURN(Log_event::EVENT_SKIP_COUNT); } #ifdef WITH_WSREP - else if (wsrep_mysql_replication_bundle && WSREP_ON) + else if (wsrep_mysql_replication_bundle && WSREP_ON && + opt_slave_domain_parallel_threads == 0) { if (++thd->wsrep_mysql_replicated < (int)wsrep_mysql_replication_bundle) { @@ -8413,14 +8410,6 @@ err: end_io_cache(&file); if (fd >= 0) mysql_file_close(fd, MYF(0)); -#ifdef WITH_WSREP - if (WSREP(thd)) - thd_proc_info(thd, "exit Create_file_log_event::do_apply_event()"); - else - thd_proc_info(thd, 0); -#else /* WITH_WSREP */ - thd_proc_info(thd, 0); -#endif /* WITH_WSREP */ return error != 0; } #endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */ @@ -8592,14 +8581,6 @@ int Append_block_log_event::do_apply_event(rpl_group_info *rgi) err: if (fd >= 0) mysql_file_close(fd, MYF(0)); -#ifdef WITH_WSREP - if (WSREP(thd)) - thd_proc_info(thd, "exit Append_block_log_event::do_apply_event()"); - else - thd_proc_info(thd, 0); -#else /* WITH_WSREP */ - thd_proc_info(thd, 0); -#endif /* WITH_WSREP */ DBUG_RETURN(error); } #endif @@ -9694,7 +9675,7 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi) thd->wsrep_exec_mode, thd->wsrep_conflict_state, (long long)wsrep_thd_trx_seqno(thd)); - } + } #endif if (thd->is_slave_error || thd->is_fatal_error) { @@ -10842,13 +10823,8 @@ check_table_map(rpl_group_info *rgi, RPL_TABLE_LIST *table_list) DBUG_ENTER("check_table_map"); enum_tbl_map_status res= OK_TO_PROCESS; Relay_log_info *rli= rgi->rli; - -#ifdef WITH_WSREP - if ((rgi->thd->slave_thread /* filtering is for slave only */ || - (WSREP(rgi->thd) && rgi->thd->wsrep_applier)) && -#else - if (rgi->thd->slave_thread /* filtering is for slave only */ && -#endif /* WITH_WSREP */ + if ((rgi->thd->slave_thread /* filtering is for slave only */ || + IF_WSREP((WSREP(rgi->thd) && rgi->thd->wsrep_applier), 0)) && (!rli->mi->rpl_filter->db_ok(table_list->db) || (rli->mi->rpl_filter->is_on() && !rli->mi->rpl_filter->tables_ok("", table_list)))) res= FILTERED_OUT; @@ -11596,23 +11572,20 @@ int Write_rows_log_event::do_exec_row(rpl_group_info *rgi) { DBUG_ASSERT(m_table != NULL); -#ifdef WITH_WSREP -#ifdef WSREP_PROC_INFO - char info[64]; - info[sizeof(info) - 1] = '\0'; - snprintf(info, sizeof(info) - 1, "Write_rows_log_event::write_row(%lld)", - (long long) wsrep_thd_trx_seqno(thd)); - const char* tmp = (WSREP(thd)) ? thd_proc_info(thd, info) : NULL; -#else - const char* tmp = (WSREP(thd)) ? - thd_proc_info(thd,"Write_rows_log_event::write_row()") : NULL; -#endif /* WSREP_PROC_INFO */ -#endif /* WITH_WSREP */ - int error= write_row(rgi, slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT); + const char *tmp= thd->get_proc_info(); + const char *message= "Write_rows_log_event::write_row()"; + +#ifdef WSREP_PROC_INFO + my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, + "Write_rows_log_event::write_row(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); + message= thd->wsrep_info; +#endif /* WSREP_PROC_INFO */ + + thd_proc_info(thd, message); + int error= write_row(rgi, slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT); + thd_proc_info(thd, tmp); -#ifdef WITH_WSREP - if (WSREP(thd)) thd_proc_info(thd, tmp); -#endif /* WITH_WSREP */ if (error && !thd->is_error()) { DBUG_ASSERT(0); @@ -12289,37 +12262,34 @@ Delete_rows_log_event::do_after_row_operations(const Slave_reporting_capability int Delete_rows_log_event::do_exec_row(rpl_group_info *rgi) { int error; + const char *tmp= thd->get_proc_info(); + const char *message= "Delete_rows_log_event::find_row()"; const bool invoke_triggers= slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers; DBUG_ASSERT(m_table != NULL); -#ifdef WITH_WSREP #ifdef WSREP_PROC_INFO - char info[64]; - info[sizeof(info) - 1] = '\0'; - snprintf(info, sizeof(info) - 1, "Delete_rows_log_event::find_row(%lld)", - (long long) wsrep_thd_trx_seqno(thd)); - const char* tmp = (WSREP(thd)) ? thd_proc_info(thd, info) : NULL; -#else - const char* tmp = (WSREP(thd)) ? - thd_proc_info(thd,"Delete_rows_log_event::find_row()") : NULL; + my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, + "Delete_rows_log_event::find_row(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); + message= thd->wsrep_info; #endif /* WSREP_PROC_INFO */ -#endif /* WITH_WSREP */ + + thd_proc_info(thd, message); if (!(error= find_row(rgi))) { /* Delete the record found, located in record[0] */ -#ifdef WITH_WSREP + message= "Delete_rows_log_event::ha_delete_row()"; #ifdef WSREP_PROC_INFO - snprintf(info, sizeof(info) - 1, + snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, "Delete_rows_log_event::ha_delete_row(%lld)", (long long) wsrep_thd_trx_seqno(thd)); - if (WSREP(thd)) thd_proc_info(thd, info); -#else - if (WSREP(thd)) thd_proc_info(thd,"Delete_rows_log_event::ha_delete_row()"); -#endif /* WSREP_PROC_INFO */ -#endif /* WITH_WSREP */ + message= thd->wsrep_info; +#endif + thd_proc_info(thd, message); + if (invoke_triggers && process_triggers(TRG_EVENT_DELETE, TRG_ACTION_BEFORE, FALSE)) error= HA_ERR_GENERIC; // in case if error is not set yet @@ -12330,9 +12300,7 @@ int Delete_rows_log_event::do_exec_row(rpl_group_info *rgi) error= HA_ERR_GENERIC; // in case if error is not set yet m_table->file->ha_index_or_rnd_end(); } -#ifdef WITH_WSREP - if (WSREP(thd)) thd_proc_info(thd, tmp); -#endif /* WITH_WSREP */ + thd_proc_info(thd, tmp); return error; } @@ -12460,20 +12428,18 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) { const bool invoke_triggers= slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers; + const char *tmp= thd->get_proc_info(); + const char *message= "Update_rows_log_event::find_row()"; DBUG_ASSERT(m_table != NULL); -#ifdef WITH_WSREP #ifdef WSREP_PROC_INFO - char info[64]; - info[sizeof(info) - 1] = '\0'; - snprintf(info, sizeof(info) - 1, "Update_rows_log_event::find_row(%lld)", - (long long) wsrep_thd_trx_seqno(thd)); - const char* tmp = (WSREP(thd)) ? thd_proc_info(thd, info) : NULL; -#else - const char* tmp = (WSREP(thd)) ? - thd_proc_info(thd,"Update_rows_log_event::find_row()") : NULL; + my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, + "Update_rows_log_event::find_row(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); + message= thd->wsrep_info; #endif /* WSREP_PROC_INFO */ -#endif /* WITH_WSREP */ + + thd_proc_info(thd, message); int error= find_row(rgi); if (error) { @@ -12483,6 +12449,7 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) */ m_curr_row= m_curr_row_end; unpack_current_row(rgi); + thd_proc_info(thd, tmp); return error; } @@ -12500,18 +12467,16 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) store_record(m_table,record[1]); m_curr_row= m_curr_row_end; -#ifdef WITH_WSREP + message= "Update_rows_log_event::unpack_current_row()"; #ifdef WSREP_PROC_INFO - snprintf(info, sizeof(info) - 1, - "Update_rows_log_event::unpack_current_row(%lld)", - (long long) wsrep_thd_trx_seqno(thd)); - if (WSREP(thd)) thd_proc_info(thd, info); -#else - if (WSREP(thd)) - thd_proc_info(thd,"Update_rows_log_event::unpack_current_row()"); + my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, + "Update_rows_log_event::unpack_current_row(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); + message= thd->wsrep_info; #endif /* WSREP_PROC_INFO */ -#endif /* WITH_WSREP */ + /* this also updates m_curr_row_end */ + thd_proc_info(thd, message); if ((error= unpack_current_row(rgi))) goto err; @@ -12529,17 +12494,15 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) DBUG_DUMP("new values", m_table->record[0], m_table->s->reclength); #endif -#ifdef WITH_WSREP + message= "Update_rows_log_event::ha_update_row()"; #ifdef WSREP_PROC_INFO - snprintf(info, sizeof(info) - 1, - "Update_rows_log_event::ha_update_row(%lld)", - (long long) wsrep_thd_trx_seqno(thd)); - if (WSREP(thd)) thd_proc_info(thd, info); -#else - if (WSREP(thd)) thd_proc_info(thd,"Update_rows_log_event::ha_update_row()"); + my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, + "Update_rows_log_event::ha_update_row(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); + message= thd->wsrep_info; #endif /* WSREP_PROC_INFO */ -#endif /* WITH_WSREP */ + thd_proc_info(thd, message); if (invoke_triggers && process_triggers(TRG_EVENT_UPDATE, TRG_ACTION_BEFORE, TRUE)) { @@ -12555,9 +12518,8 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) process_triggers(TRG_EVENT_UPDATE, TRG_ACTION_AFTER, TRUE)) error= HA_ERR_GENERIC; // in case if error is not set yet -#ifdef WITH_WSREP - if (WSREP(thd)) thd_proc_info(thd, tmp); -#endif /* WITH_WSREP */ + thd_proc_info(thd, tmp); + err: m_table->file->ha_index_or_rnd_end(); return error; @@ -12647,7 +12609,9 @@ void Incident_log_event::pack_info(THD *thd, Protocol *protocol) m_incident, description(), m_message.str); protocol->store(buf, bytes, &my_charset_bin); } -#endif +#endif /* MYSQL_CLIENT */ + + #if WITH_WSREP && !defined(MYSQL_CLIENT) Format_description_log_event *wsrep_format_desc; // TODO: free them at the end /* @@ -12661,13 +12625,12 @@ Log_event* wsrep_read_log_event( char **arg_buf, size_t *arg_buf_len, const Format_description_log_event *description_event) { - DBUG_ENTER("wsrep_read_log_event"); char *head= (*arg_buf); - uint data_len = uint4korr(head + EVENT_LEN_OFFSET); char *buf= (*arg_buf); const char *error= 0; Log_event *res= 0; + DBUG_ENTER("wsrep_read_log_event"); if (data_len > WSREP_MAX_ALLOWED_PACKET) { diff --git a/sql/log_event.h b/sql/log_event.h index 2091d968558..6d0281bd790 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -1340,7 +1340,12 @@ public: */ int apply_event(rpl_group_info *rgi) { - return do_apply_event(rgi); + int res; + THD_STAGE_INFO(thd, stage_apply_event); + res= do_apply_event(rgi); + THD_STAGE_INFO(thd, stage_after_apply_event); + res= 0; + return res; } diff --git a/sql/mdl.cc b/sql/mdl.cc index 2172e34cd2a..e5e906ae5d0 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -22,19 +22,9 @@ #include #include #include - -#ifdef WITH_WSREP #include "wsrep_mysqld.h" #include "wsrep_thd.h" -extern "C" my_thread_id wsrep_thd_thread_id(THD *thd); -extern "C" char *wsrep_thd_query(THD *thd); -void sql_print_information(const char *format, ...) - ATTRIBUTE_FORMAT(printf, 1, 2); -extern bool -wsrep_grant_mdl_exception(MDL_context *requestor_ctx, - MDL_ticket *ticket); -#endif /* WITH_WSREP */ #ifdef HAVE_PSI_INTERFACE static PSI_mutex_key key_MDL_map_mutex; static PSI_mutex_key key_MDL_wait_LOCK_wait_status; @@ -1511,22 +1501,23 @@ void MDL_lock::Ticket_list::add_ticket(MDL_ticket *ticket) DBUG_ASSERT(ticket->get_lock()); #ifdef WITH_WSREP if ((this == &(ticket->get_lock()->m_waiting)) && - wsrep_thd_is_BF((void *)(ticket->get_ctx()->wsrep_get_thd()), false)) + wsrep_thd_is_BF((void *)(ticket->get_ctx()->get_thd()), false)) { Ticket_iterator itw(ticket->get_lock()->m_waiting); Ticket_iterator itg(ticket->get_lock()->m_granted); + DBUG_ASSERT(WSREP_ON); MDL_ticket *waiting, *granted; MDL_ticket *prev=NULL; bool added= false; while ((waiting= itw++) && !added) { - if (!wsrep_thd_is_BF((void *)(waiting->get_ctx()->wsrep_get_thd()), true)) + if (!wsrep_thd_is_BF((void *)(waiting->get_ctx()->get_thd()), true)) { WSREP_DEBUG("MDL add_ticket inserted before: %lu %s", - wsrep_thd_thread_id(waiting->get_ctx()->wsrep_get_thd()), - wsrep_thd_query(waiting->get_ctx()->wsrep_get_thd())); + wsrep_thd_thread_id(waiting->get_ctx()->get_thd()), + wsrep_thd_query(waiting->get_ctx()->get_thd())); m_list.insert_after(prev, ticket); added= true; } @@ -1547,16 +1538,14 @@ void MDL_lock::Ticket_list::add_ticket(MDL_ticket *ticket) } } else +#endif /* WITH_WSREP */ { -#endif /* WITH_WSREP */ - /* - Add ticket to the *back* of the queue to ensure fairness - among requests with the same priority. - */ - m_list.push_back(ticket); -#ifdef WITH_WSREP + /* + Add ticket to the *back* of the queue to ensure fairness + among requests with the same priority. + */ + m_list.push_back(ticket); } -#endif /* WITH_WSREP */ m_bitmap|= MDL_BIT(ticket->get_type()); } @@ -1897,9 +1886,7 @@ MDL_lock::can_grant_lock(enum_mdl_type type_arg, bool can_grant= FALSE; bitmap_t waiting_incompat_map= incompatible_waiting_types_bitmap()[type_arg]; bitmap_t granted_incompat_map= incompatible_granted_types_bitmap()[type_arg]; -#ifdef WITH_WSREP bool wsrep_can_grant= TRUE; -#endif /* WITH_WSREP */ /* New lock request can be satisfied iff: @@ -1922,55 +1909,49 @@ MDL_lock::can_grant_lock(enum_mdl_type type_arg, { if (ticket->get_ctx() != requestor_ctx && ticket->is_incompatible_when_granted(type_arg)) -#ifdef WITH_WSREP { - if (wsrep_thd_is_BF((void *)(requestor_ctx->wsrep_get_thd()),false) && + if (IF_WSREP(!WSREP_ON, 0)) + break; +#ifdef WITH_WSREP + if (wsrep_thd_is_BF((void *)(requestor_ctx->get_thd()),false) && key.mdl_namespace() == MDL_key::GLOBAL) { WSREP_DEBUG("global lock granted for BF: %lu %s", - wsrep_thd_thread_id(requestor_ctx->wsrep_get_thd()), - wsrep_thd_query(requestor_ctx->wsrep_get_thd())); + wsrep_thd_thread_id(requestor_ctx->get_thd()), + wsrep_thd_query(requestor_ctx->get_thd())); can_grant = true; } else if (!wsrep_grant_mdl_exception(requestor_ctx, ticket)) { wsrep_can_grant= FALSE; - if (wsrep_log_conflicts) - { - MDL_lock * lock = ticket->get_lock(); - WSREP_INFO( - "MDL conflict db=%s table=%s ticket=%d solved by %s", - lock->key.db_name(), lock->key.name(), ticket->get_type(), "abort" - ); + if (wsrep_log_conflicts) + { + MDL_lock * lock = ticket->get_lock(); + WSREP_INFO( + "MDL conflict db=%s table=%s ticket=%d solved by %s", + lock->key.db_name(), lock->key.name(), ticket->get_type(), + "abort" ); } } else - { can_grant= TRUE; - } + /* Continue loop */ } -#else - break; #endif /* WITH_WSREP */ } -#ifdef WITH_WSREP - if ((ticket == NULL) && wsrep_can_grant) -#else - if (ticket == NULL) /* Incompatible locks are our own. */ -#endif /* WITH_WSREP */ - + if ((ticket == NULL) && IF_WSREP(wsrep_can_grant, 1)) can_grant= TRUE; } } #ifdef WITH_WSREP else { - if (wsrep_thd_is_BF((void *)(requestor_ctx->wsrep_get_thd()), false) && + if (wsrep_thd_is_BF((void *)(requestor_ctx->get_thd()), false) && key.mdl_namespace() == MDL_key::GLOBAL) { WSREP_DEBUG("global lock granted for BF (waiting queue): %lu %s", - wsrep_thd_thread_id(requestor_ctx->wsrep_get_thd()), - wsrep_thd_query(requestor_ctx->wsrep_get_thd())); + wsrep_thd_thread_id(requestor_ctx->get_thd()), + wsrep_thd_query(requestor_ctx->get_thd())); can_grant = true; } } @@ -3019,12 +3000,7 @@ void MDL_context::release_locks_stored_before(enum_mdl_duration duration, DBUG_VOID_RETURN; } -#ifdef WITH_WSREP -void MDL_context::release_explicit_locks() -{ - release_locks_stored_before(MDL_EXPLICIT, NULL); -} -#endif + /** Release all explicit locks in the context which correspond to the same name/object as this lock request. @@ -3332,7 +3308,16 @@ void MDL_context::set_transaction_duration_for_all_locks() ticket->m_duration= MDL_TRANSACTION; #endif } + + #ifdef WITH_WSREP + +void MDL_context::release_explicit_locks() +{ + release_locks_stored_before(MDL_EXPLICIT, NULL); +} + + void MDL_ticket::wsrep_report(bool debug) { if (debug) diff --git a/sql/mdl.h b/sql/mdl.h index 639a8966b33..231f95d7419 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -776,13 +776,10 @@ public: m_tickets[MDL_TRANSACTION].is_empty() && m_tickets[MDL_EXPLICIT].is_empty()); } - -#ifdef WITH_WSREP inline bool has_transactional_locks() const { return !m_tickets[MDL_TRANSACTION].is_empty(); } -#endif /* WITH_WSREP */ MDL_savepoint mdl_savepoint() { @@ -923,7 +920,6 @@ private: */ MDL_wait_for_subgraph *m_waiting_for; private: - THD *get_thd() const { return m_owner->get_thd(); } MDL_ticket *find_ticket(MDL_request *mdl_req, enum_mdl_duration *duration); void release_locks_stored_before(enum_mdl_duration duration, MDL_ticket *sentinel); @@ -932,9 +928,7 @@ private: MDL_ticket **out_ticket); public: -#ifdef WITH_WSREP - THD *wsrep_get_thd() const { return get_thd(); } -#endif + THD *get_thd() const { return m_owner->get_thd(); } void find_deadlock(); ulong get_thread_id() const { return thd_get_thread_id(get_thd()); } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index b2cbeebae49..1288f2c2fc7 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -71,13 +71,11 @@ #include "scheduler.h" #include #include "debug_sync.h" -#ifdef WITH_WSREP #include "wsrep_mysqld.h" #include "wsrep_var.h" #include "wsrep_thd.h" #include "wsrep_sst.h" -ulong wsrep_running_threads = 0; // # of currently running wsrep threads -#endif + #include "sql_callback.h" #include "threadpool.h" @@ -359,7 +357,8 @@ static bool volatile select_thread_in_use, signal_thread_in_use; static volatile bool ready_to_exit; static my_bool opt_debugging= 0, opt_external_locking= 0, opt_console= 0; static my_bool opt_short_log_format= 0; -static uint kill_cached_threads, wake_thread; +uint kill_cached_threads; +static uint wake_thread; ulong max_used_connections; static volatile ulong cached_thread_count= 0; static char *mysqld_user, *mysqld_chroot; @@ -367,25 +366,19 @@ static char *default_character_set_name; static char *character_set_filesystem_name; static char *lc_messages; static char *lc_time_names_name; -#ifndef WITH_WSREP -static char *my_bind_addr_str; -#else char *my_bind_addr_str; -#endif /* WITH_WSREP */ static char *default_collation_name; char *default_storage_engine, *default_tmp_storage_engine; static char compiled_default_collation_name[]= MYSQL_DEFAULT_COLLATION_NAME; static I_List thread_cache; static bool binlog_format_used= false; LEX_STRING opt_init_connect, opt_init_slave; -static mysql_cond_t COND_thread_cache, COND_flush_thread_cache; +mysql_cond_t COND_thread_cache; +static mysql_cond_t COND_flush_thread_cache; static DYNAMIC_ARRAY all_options; /* Global variables */ -#ifdef WITH_WSREP -ulong my_bind_addr; -#endif /* WITH_WSREP */ bool opt_bin_log, opt_bin_log_used=0, opt_ignore_builtin_innodb= 0; my_bool opt_log, opt_slow_log, debug_assert_if_crashed_table= 0, opt_help= 0; static my_bool opt_abort; @@ -479,10 +472,6 @@ ulong opt_binlog_rows_event_max_size; my_bool opt_master_verify_checksum= 0; my_bool opt_slave_sql_verify_checksum= 1; const char *binlog_format_names[]= {"MIXED", "STATEMENT", "ROW", NullS}; -#ifdef WITH_WSREP -const char *wsrep_binlog_format_names[]= - {"MIXED", "STATEMENT", "ROW", "NONE", NullS}; -#endif /*WITH_WSREP */ #ifdef HAVE_INITGROUPS volatile sig_atomic_t calling_initgroups= 0; /**< Used in SIGSEGV handler. */ #endif @@ -748,6 +737,7 @@ mysql_cond_t COND_server_started; int mysqld_server_started=0, mysqld_server_initialized= 0; File_parser_dummy_hook file_parser_dummy_hook; + #ifdef WITH_WSREP mysql_mutex_t LOCK_wsrep_ready; mysql_cond_t COND_wsrep_ready; @@ -763,7 +753,10 @@ mysql_cond_t COND_wsrep_replaying; mysql_mutex_t LOCK_wsrep_slave_threads; mysql_mutex_t LOCK_wsrep_desync; int wsrep_replaying= 0; -static void wsrep_close_threads(THD* thd); +ulong wsrep_running_threads = 0; // # of currently running wsrep threads +ulong my_bind_addr; +const char *wsrep_binlog_format_names[]= + {"MIXED", "STATEMENT", "ROW", "NONE", NullS}; #endif /* WITH_WSREP */ /* replication parameters, if master_host is not NULL, we are a slave */ @@ -1465,7 +1458,7 @@ bool mysqld_embedded=0; bool mysqld_embedded=1; #endif -static my_bool plugins_are_initialized= FALSE; +my_bool plugins_are_initialized= FALSE; #ifndef DBUG_OFF static const char* default_dbug_option; @@ -1772,7 +1765,8 @@ static void close_connections(void) #endif #ifdef WITH_WSREP /* - * TODO: this code block may turn out redundant. wsrep->disconnect() + * WSREP_TODO: + * this code block may turn out redundant. wsrep->disconnect() * should terminate slave threads gracefully, and we don't need * to signal them here. * The code here makes sure mysqld will not hang during shutdown @@ -1950,15 +1944,19 @@ static void __cdecl kill_server(int sig_ptr) } } #endif + #ifdef WITH_WSREP - if (WSREP_ON) wsrep_stop_replication(NULL); + if (WSREP_ON) + wsrep_stop_replication(NULL); #endif close_connections(); + #ifdef WITH_WSREP - if (wsrep_inited == 1) + if (WSREP_ON && wsrep_inited == 1) wsrep_deinit(true); #endif + if (sig != MYSQL_KILL_SIGNAL && sig != 0) unireg_abort(1); /* purecov: inspected */ @@ -2053,14 +2051,18 @@ extern "C" void unireg_abort(int exit_code) usage(); if (exit_code) sql_print_error("Aborting\n"); + #ifdef WITH_WSREP + /* Check if wsrep class is used. If yes, then cleanup wsrep */ if (wsrep) { - /* This is an abort situation, we cannot expect to gracefully close all - * wsrep threads here, we can only diconnect from service */ + /* + This is an abort situation, we cannot expect to gracefully close all + wsrep threads here, we can only diconnect from service + */ wsrep_close_client_connections(FALSE); shutdown_in_progress= 1; - THD* thd(0); + THD *thd(0); wsrep->disconnect(wsrep); WSREP_INFO("Service disconnected."); wsrep_close_threads(thd); /* this won't close all threads */ @@ -2072,6 +2074,7 @@ extern "C" void unireg_abort(int exit_code) wsrep_deinit(true); } #endif // WITH_WSREP + clean_up(!opt_abort && (exit_code || !opt_bootstrap)); /* purecov: inspected */ DBUG_PRINT("quit",("done with cleanup in unireg_abort")); mysqld_exit(exit_code); @@ -2621,6 +2624,7 @@ static MYSQL_SOCKET activate_tcp_port(uint port) unireg_abort(1); } #if defined(WITH_WSREP) && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) + if (WSREP_ON) (void) fcntl(mysql_socket_getfd(ip_sock), F_SETFD, FD_CLOEXEC); #endif /* WITH_WSREP */ @@ -2751,7 +2755,8 @@ static void network_init(void) sql_print_warning("listen() on Unix socket failed with error %d", socket_errno); #if defined(WITH_WSREP) && defined(HAVE_FCNTL) - (void) fcntl(mysql_socket_getfd(unix_sock), F_SETFD, FD_CLOEXEC); + if (WSREP_ON) + (void) fcntl(mysql_socket_getfd(unix_sock), F_SETFD, FD_CLOEXEC); #endif /* WITH_WSREP */ } #endif @@ -2833,15 +2838,16 @@ void dec_connection_count(THD *thd) applier as well as rollbacker threads. */ if (!thd->wsrep_applier) + return; #endif /* WITH_WSREP */ - { - DBUG_ASSERT(*thd->scheduler->connection_count > 0); - mysql_mutex_lock(&LOCK_connection_count); - (*thd->scheduler->connection_count)--; - mysql_mutex_unlock(&LOCK_connection_count); - } + + DBUG_ASSERT(*thd->scheduler->connection_count > 0); + mysql_mutex_lock(&LOCK_connection_count); + (*thd->scheduler->connection_count)--; + mysql_mutex_unlock(&LOCK_connection_count); } + /* Delete THD and decrement thread counters, including thread_running */ @@ -3014,11 +3020,7 @@ bool one_thread_per_connection_end(THD *thd, bool put_in_cache) /* Mark that current_thd is not valid anymore */ set_current_thd(0); -#ifdef WITH_WSREP - if (put_in_cache && cache_thread() && !wsrep_applier) -#else - if (put_in_cache && cache_thread()) -#endif /* WITH_WSREP */ + if (put_in_cache && cache_thread() && IF_WSREP(!wsrep_applier, 1)) DBUG_RETURN(0); // Thread is reused /* @@ -4139,6 +4141,7 @@ static int init_common_variables() } else opt_log_basename= glob_hostname; + #ifdef WITH_WSREP if (0 == wsrep_node_name || 0 == wsrep_node_name[0]) { @@ -4146,6 +4149,7 @@ static int init_common_variables() wsrep_node_name= my_strdup(glob_hostname, MYF(MY_WME)); } #endif /* WITH_WSREP */ + if (!*pidfile_name) { strmake(pidfile_name, opt_log_basename, sizeof(pidfile_name)-5); @@ -4205,11 +4209,16 @@ static int init_common_variables() compile_time_assert(sizeof(com_status_vars)/sizeof(com_status_vars[0]) - 1 == SQLCOM_END + 8); #endif + #ifdef WITH_WSREP - /* This is a protection against mutually incompatible option values. */ + /* + This is a protection against mutually incompatible option values. + Note WSREP_ON == global_system_variables.wsrep_on + */ if (WSREP_ON && wsrep_check_opts (remaining_argc, remaining_argv)) global_system_variables.wsrep_on= 0; #endif /* WITH_WSREP */ + if (get_options(&remaining_argc, &remaining_argv)) return 1; set_server_version(); @@ -4923,18 +4932,10 @@ static int init_server_components() /* need to configure logging before initializing storage engines */ if (!opt_bin_log_used) { -#ifdef WITH_WSREP - if (!WSREP_ON && opt_log_slave_updates) -#else - if (opt_log_slave_updates) -#endif + if (IF_WSREP(!WSREP_ON,1) && opt_log_slave_updates) sql_print_warning("You need to use --log-bin to make " "--log-slave-updates work."); -#ifdef WITH_WSREP - if (!WSREP_ON && binlog_format_used) -#else - if (binlog_format_used) -#endif + if (IF_WSREP(!WSREP_ON, 1) && binlog_format_used) sql_print_warning("You need to use --log-bin to make " "--binlog-format work."); } @@ -5018,7 +5019,7 @@ a file name for --log-bin-index option", opt_binlog_index_name); after SST has happened */ } - if (!wsrep_recovery) + if (WSREP_ON && !wsrep_recovery) { if (opt_bootstrap) // bootsrap option given - disable wsrep functionality { @@ -5192,23 +5193,34 @@ a file name for --log-bin-index option", opt_binlog_index_name); #endif #ifdef WITH_WSREP - if (!opt_bin_log) + if (WSREP_ON && !opt_bin_log) { wsrep_emulate_bin_log= 1; } #endif + + /* if total_ha_2pc <= 1 + tc_log = tc_log_dummy + else + if opt_bin_log == true + tc_log = mysql_bin_log + else + if WITH_WSREP + if WSREP_ON + tc_log = tc_log_dummy + else + tc_log = tc_log_mmap + else + tc_log=tc_log_mmap + */ tc_log= (total_ha_2pc > 1 ? (opt_bin_log ? (TC_LOG *) &mysql_bin_log : + IF_WSREP((WSREP_ON ? (TC_LOG *) &tc_log_dummy : + (TC_LOG *) &tc_log_mmap), (TC_LOG *) &tc_log_mmap)) : + (TC_LOG *) &tc_log_dummy); + #ifdef WITH_WSREP - (WSREP_ON ? - (TC_LOG *) &tc_log_dummy : - (TC_LOG *) &tc_log_mmap)) : -#else - (TC_LOG *) &tc_log_mmap) : -#endif - (TC_LOG *) &tc_log_dummy); -#ifdef WITH_WSREP - WSREP_DEBUG("Initial TC log open: %s", + WSREP_DEBUG("Initial TC log open: %s", (tc_log == &mysql_bin_log) ? "binlog" : (tc_log == &tc_log_mmap) ? "mmap" : (tc_log == &tc_log_dummy) ? "dummy" : "unknown" @@ -5296,468 +5308,6 @@ static void create_shutdown_thread() #endif /* EMBEDDED_LIBRARY */ -#ifdef WITH_WSREP -typedef void (*wsrep_thd_processor_fun)(THD *); - -pthread_handler_t start_wsrep_THD(void *arg) -{ - THD *thd; - rpl_sql_thread_info sql_info(NULL); - wsrep_thd_processor_fun processor= (wsrep_thd_processor_fun)arg; - - if (my_thread_init()) - { - WSREP_ERROR("Could not initialize thread"); - return(NULL); - } - - if (!(thd= new THD(true))) - { - return(NULL); - } - mysql_mutex_lock(&LOCK_thread_count); - thd->thread_id=thread_id++; - - thd->real_id=pthread_self(); // Keep purify happy - thread_count++; - thread_created++; - threads.append(thd); - - my_net_init(&thd->net,(st_vio*) 0, MYF(0)); - - DBUG_PRINT("wsrep",(("creating thread %lld"), (long long)thd->thread_id)); - thd->prior_thr_create_utime= thd->start_utime= microsecond_interval_timer(); - (void) mysql_mutex_unlock(&LOCK_thread_count); - - /* from bootstrap()... */ - thd->bootstrap=1; - thd->max_client_packet_length= thd->net.max_packet; - thd->security_ctx->master_access= ~(ulong)0; - thd->system_thread_info.rpl_sql_info= &sql_info; - - /* from handle_one_connection... */ - pthread_detach_this_thread(); - - mysql_thread_set_psi_id(thd->thread_id); - thd->thr_create_utime= microsecond_interval_timer(); - if (MYSQL_CALLBACK_ELSE(thread_scheduler, init_new_connection_thread, (), 0)) - { - close_connection(thd, ER_OUT_OF_RESOURCES); - statistic_increment(aborted_connects,&LOCK_status); - MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0)); - - return(NULL); - } - -// - /* - handle_one_connection() is normally the only way a thread would - start and would always be on the very high end of the stack , - therefore, the thread stack always starts at the address of the - first local variable of handle_one_connection, which is thd. We - need to know the start of the stack so that we could check for - stack overruns. - */ - DBUG_PRINT("wsrep", ("handle_one_connection called by thread %lld\n", - (long long)thd->thread_id)); - /* now that we've called my_thread_init(), it is safe to call DBUG_* */ - - thd->thread_stack= (char*) &thd; - if (thd->store_globals()) - { - close_connection(thd, ER_OUT_OF_RESOURCES); - statistic_increment(aborted_connects,&LOCK_status); - MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0)); - delete thd; - - return(NULL); - } - - thd->system_thread= SYSTEM_THREAD_SLAVE_SQL; - thd->security_ctx->skip_grants(); - - /* handle_one_connection() again... */ - //thd->version= refresh_version; - thd->proc_info= 0; - thd->set_command(COM_SLEEP); - thd->set_time(); - thd->init_for_queries(); - - mysql_mutex_lock(&LOCK_thread_count); - wsrep_running_threads++; - mysql_cond_broadcast(&COND_thread_count); - mysql_mutex_unlock(&LOCK_thread_count); - - processor(thd); - - close_connection(thd, 0); - - mysql_mutex_lock(&LOCK_thread_count); - wsrep_running_threads--; - WSREP_DEBUG("wsrep running threads now: %lu", wsrep_running_threads); - mysql_cond_broadcast(&COND_thread_count); - mysql_mutex_unlock(&LOCK_thread_count); - - // Note: We can't call THD destructor without crashing - // if plugins have not been initialized. However, in most of the - // cases this means that pre SE initialization SST failed and - // we are going to exit anyway. - if (plugins_are_initialized) - { - net_end(&thd->net); - MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 1)); - } - else - { - // TODO: lightweight cleanup to get rid of: - // 'Error in my_thread_global_end(): 2 threads didn't exit' - // at server shutdown - } - - my_thread_end(); - if (thread_handling > SCHEDULER_ONE_THREAD_PER_CONNECTION) - { - mysql_mutex_lock(&LOCK_thread_count); - delete thd; - thread_count--; - mysql_mutex_unlock(&LOCK_thread_count); - } - return(NULL); -} - -/**/ -static bool abort_replicated(THD *thd) -{ - bool ret_code= false; - if (thd->wsrep_query_state== QUERY_COMMITTING) - { - if (wsrep_debug) WSREP_INFO("aborting replicated trx: %lu", thd->real_id); - - (void)wsrep_abort_thd(thd, thd, TRUE); - ret_code= true; - } - return ret_code; -} -/**/ -static inline bool is_client_connection(THD *thd) -{ -#if REMOVE -// REMOVE THIS LATER (lp:777201). Below we had to add an explicit check for -// wsrep_applier since wsrep_exec_mode didn't seem to always work -if (thd->wsrep_applier && thd->wsrep_exec_mode != REPL_RECV) -WSREP_WARN("applier has wsrep_exec_mode = %d", thd->wsrep_exec_mode); - - if ( thd->slave_thread || /* declared as mysql slave */ - thd->system_thread || /* declared as system thread */ - !thd->vio_ok() || /* server internal thread */ - thd->wsrep_exec_mode==REPL_RECV || /* applier or replaying thread */ - thd->wsrep_applier || /* wsrep slave applier */ - !thd->variables.wsrep_on) /* client, but fenced outside wsrep */ - return false; - - return true; -#else - return (thd->wsrep_client_thread && thd->variables.wsrep_on); -#endif /* REMOVE */ -} - -static inline bool is_replaying_connection(THD *thd) -{ - bool ret; - - mysql_mutex_lock(&thd->LOCK_wsrep_thd); - ret= (thd->wsrep_conflict_state == REPLAYING) ? true : false; - mysql_mutex_unlock(&thd->LOCK_wsrep_thd); - - return ret; -} - -static inline bool is_committing_connection(THD *thd) -{ - bool ret; - - mysql_mutex_lock(&thd->LOCK_wsrep_thd); - ret= (thd->wsrep_query_state == QUERY_COMMITTING) ? true : false; - mysql_mutex_unlock(&thd->LOCK_wsrep_thd); - - return ret; -} - -static bool have_client_connections() -{ - THD *tmp; - - I_List_iterator it(threads); - while ((tmp=it++)) - { - DBUG_PRINT("quit",("Informing thread %ld that it's time to die", - tmp->thread_id)); - if (is_client_connection(tmp) && tmp->killed == KILL_CONNECTION) - { - (void)abort_replicated(tmp); - return true; - } - } - return false; -} - -/* - returns the number of wsrep appliers running. - However, the caller (thd parameter) is not taken in account - */ -static int have_wsrep_appliers(THD *thd) -{ - int ret= 0; - THD *tmp; - - I_List_iterator it(threads); - while ((tmp=it++)) - { - ret+= (tmp != thd && tmp->wsrep_applier); - } - return ret; -} - -static void wsrep_close_thread(THD *thd) -{ - thd->killed= KILL_CONNECTION; - MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (thd)); - if (thd->mysys_var) - { - thd->mysys_var->abort=1; - mysql_mutex_lock(&thd->mysys_var->mutex); - if (thd->mysys_var->current_cond) - { - mysql_mutex_lock(thd->mysys_var->current_mutex); - mysql_cond_broadcast(thd->mysys_var->current_cond); - mysql_mutex_unlock(thd->mysys_var->current_mutex); - } - mysql_mutex_unlock(&thd->mysys_var->mutex); - } -} - -static my_bool have_committing_connections() -{ - THD *tmp; - mysql_mutex_lock(&LOCK_thread_count); // For unlink from list - - I_List_iterator it(threads); - while ((tmp=it++)) - { - if (!is_client_connection(tmp)) - continue; - - if (is_committing_connection(tmp)) - { - mysql_mutex_unlock(&LOCK_thread_count); - return TRUE; - } - } - mysql_mutex_unlock(&LOCK_thread_count); - return FALSE; -} - -int wsrep_wait_committing_connections_close(int wait_time) -{ - int sleep_time= 100; - - while (have_committing_connections() && wait_time > 0) - { - WSREP_DEBUG("wait for committing transaction to close: %d", wait_time); - my_sleep(sleep_time); - wait_time -= sleep_time; - } - if (have_committing_connections()) - { - return 1; - } - return 0; -} - -void wsrep_close_client_connections(my_bool wait_to_end) -{ - /* - First signal all threads that it's time to die - */ - - THD *tmp; - mysql_mutex_lock(&LOCK_thread_count); // For unlink from list - - bool kill_cached_threads_saved= kill_cached_threads; - kill_cached_threads= true; // prevent future threads caching - mysql_cond_broadcast(&COND_thread_cache); // tell cached threads to die - - I_List_iterator it(threads); - while ((tmp=it++)) - { - DBUG_PRINT("quit",("Informing thread %ld that it's time to die", - tmp->thread_id)); - /* We skip slave threads & scheduler on this first loop through. */ - if (!is_client_connection(tmp)) - continue; - - if (is_replaying_connection(tmp)) - { - tmp->killed= KILL_CONNECTION; - continue; - } - - /* replicated transactions must be skipped */ - if (abort_replicated(tmp)) - continue; - - WSREP_DEBUG("closing connection %ld", tmp->thread_id); - wsrep_close_thread(tmp); - } - mysql_mutex_unlock(&LOCK_thread_count); - - if (thread_count) - sleep(2); // Give threads time to die - - mysql_mutex_lock(&LOCK_thread_count); - /* - Force remaining threads to die by closing the connection to the client - */ - - I_List_iterator it2(threads); - while ((tmp=it2++)) - { -#ifndef __bsdi__ // Bug in BSDI kernel - if (is_client_connection(tmp) && - !abort_replicated(tmp) && - !is_replaying_connection(tmp)) - { - WSREP_INFO("killing local connection: %ld",tmp->thread_id); - close_connection(tmp,0); - } -#endif - } - - DBUG_PRINT("quit",("Waiting for threads to die (count=%u)",thread_count)); - if (wsrep_debug) - WSREP_INFO("waiting for client connections to close: %u", thread_count); - - while (wait_to_end && have_client_connections()) - { - mysql_cond_wait(&COND_thread_count, &LOCK_thread_count); - DBUG_PRINT("quit",("One thread died (count=%u)", thread_count)); - } - - kill_cached_threads= kill_cached_threads_saved; - - mysql_mutex_unlock(&LOCK_thread_count); - - /* All client connection threads have now been aborted */ -} - -void wsrep_close_applier(THD *thd) -{ - WSREP_DEBUG("closing applier %ld", thd->thread_id); - wsrep_close_thread(thd); -} - -static void wsrep_close_threads(THD *thd) -{ - THD *tmp; - mysql_mutex_lock(&LOCK_thread_count); // For unlink from list - - I_List_iterator it(threads); - while ((tmp=it++)) - { - DBUG_PRINT("quit",("Informing thread %ld that it's time to die", - tmp->thread_id)); - /* We skip slave threads & scheduler on this first loop through. */ - if (tmp->wsrep_applier && tmp != thd) - { - WSREP_DEBUG("closing wsrep thread %ld", tmp->thread_id); - wsrep_close_thread (tmp); - } - } - - mysql_mutex_unlock(&LOCK_thread_count); -} - -void wsrep_close_applier_threads(int count) -{ - THD *tmp; - mysql_mutex_lock(&LOCK_thread_count); // For unlink from list - - I_List_iterator it(threads); - while ((tmp=it++) && count) - { - DBUG_PRINT("quit",("Informing thread %ld that it's time to die", - tmp->thread_id)); - /* We skip slave threads & scheduler on this first loop through. */ - if (tmp->wsrep_applier) - { - WSREP_DEBUG("closing wsrep applier thread %ld", tmp->thread_id); - tmp->wsrep_applier_closing= TRUE; - count--; - } - } - - mysql_mutex_unlock(&LOCK_thread_count); -} - -void wsrep_wait_appliers_close(THD *thd) -{ - /* Wait for wsrep appliers to gracefully exit */ - mysql_mutex_lock(&LOCK_thread_count); - while (have_wsrep_appliers(thd) > 1) - // 1 is for rollbacker thread which needs to be killed explicitly. - // This gotta be fixed in a more elegant manner if we gonna have arbitrary - // number of non-applier wsrep threads. - { - if (thread_handling > SCHEDULER_ONE_THREAD_PER_CONNECTION) - { - mysql_mutex_unlock(&LOCK_thread_count); - my_sleep(100); - mysql_mutex_lock(&LOCK_thread_count); - } - else - mysql_cond_wait(&COND_thread_count,&LOCK_thread_count); - DBUG_PRINT("quit",("One applier died (count=%u)",thread_count)); - } - mysql_mutex_unlock(&LOCK_thread_count); - /* Now kill remaining wsrep threads: rollbacker */ - wsrep_close_threads (thd); - /* and wait for them to die */ - mysql_mutex_lock(&LOCK_thread_count); - while (have_wsrep_appliers(thd) > 0) - { - if (thread_handling > SCHEDULER_ONE_THREAD_PER_CONNECTION) - { - mysql_mutex_unlock(&LOCK_thread_count); - my_sleep(100); - mysql_mutex_lock(&LOCK_thread_count); - } - else - mysql_cond_wait(&COND_thread_count,&LOCK_thread_count); - DBUG_PRINT("quit",("One thread died (count=%u)",thread_count)); - } - mysql_mutex_unlock(&LOCK_thread_count); - - /* All wsrep applier threads have now been aborted. However, if this thread - is also applier, we are still running... - */ -} - -void wsrep_kill_mysql(THD *thd) -{ - if (mysqld_server_started) - { - if (!shutdown_in_progress) - { - WSREP_INFO("starting shutdown"); - kill_mysql(); - } - } - else - { - unireg_abort(1); - } -} -#endif /* WITH_WSREP */ #if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY) static void handle_connections_methods() @@ -5935,7 +5485,8 @@ int mysqld_main(int argc, char **argv) } #endif #ifdef WITH_WSREP - wsrep_filter_new_cluster (&argc, argv); + if (WSREP_ON) + wsrep_filter_new_cluster (&argc, argv); #endif /* WITH_WSREP */ orig_argc= argc; @@ -6154,7 +5705,7 @@ int mysqld_main(int argc, char **argv) #endif #ifdef WITH_WSREP /* WSREP AFTER SE */ - if (wsrep_recovery) + if (WSREP_ON && wsrep_recovery) { select_thread_in_use= 0; wsrep_recover(); @@ -6219,28 +5770,31 @@ int mysqld_main(int argc, char **argv) unireg_abort(1); #ifdef WITH_WSREP /* WSREP AFTER SE */ - if (opt_bootstrap) + if (WSREP_ON) { - /*! bootstrap wsrep init was taken care of above */ - } - else - { - wsrep_SE_initialized(); - - if (wsrep_before_SE()) + if (opt_bootstrap) { - /*! in case of no SST wsrep waits in view handler callback */ - wsrep_SE_init_grab(); - wsrep_SE_init_done(); - /*! in case of SST wsrep waits for wsrep->sst_received */ - wsrep_sst_continue(); + /*! bootstrap wsrep init was taken care of above */ } else { - wsrep_init_startup (false); - } + wsrep_SE_initialized(); - wsrep_create_appliers(wsrep_slave_threads - 1); + if (wsrep_before_SE()) + { + /*! in case of no SST wsrep waits in view handler callback */ + wsrep_SE_init_grab(); + wsrep_SE_init_done(); + /*! in case of SST wsrep waits for wsrep->sst_received */ + wsrep_sst_continue(); + } + else + { + wsrep_init_startup (false); + } + + wsrep_create_appliers(wsrep_slave_threads - 1); + } } #endif /* WITH_WSREP */ if (opt_bootstrap) @@ -6311,9 +5865,7 @@ int mysqld_main(int argc, char **argv) #ifdef EXTRA_DEBUG2 sql_print_error("Before Lock_thread_count"); #endif -#ifdef WITH_WSREP WSREP_DEBUG("Before Lock_thread_count"); -#endif mysql_mutex_lock(&LOCK_thread_count); DBUG_PRINT("quit", ("Got thread_count mutex")); select_thread_in_use=0; // For close_connections @@ -10140,7 +9692,8 @@ void refresh_status(THD *thd) /* Reset some global variables */ reset_status_vars(); #ifdef WITH_WSREP - wsrep->stats_reset(wsrep); + if (WSREP_ON) + wsrep->stats_reset(wsrep); #endif /* WITH_WSREP */ /* Reset the counters of all key caches (default and named). */ @@ -10193,6 +9746,7 @@ static PSI_file_info all_server_files[]= }; #endif /* HAVE_PSI_INTERFACE */ +PSI_stage_info stage_after_apply_event= { 0, "after apply log event", 0}; PSI_stage_info stage_after_create= { 0, "After create", 0}; PSI_stage_info stage_after_opening_tables= { 0, "After opening tables", 0}; PSI_stage_info stage_after_table_lock= { 0, "After table lock", 0}; @@ -10200,6 +9754,7 @@ PSI_stage_info stage_allocating_local_table= { 0, "allocating local table", 0}; PSI_stage_info stage_alter_inplace_prepare= { 0, "preparing for alter table", 0}; PSI_stage_info stage_alter_inplace= { 0, "altering table", 0}; PSI_stage_info stage_alter_inplace_commit= { 0, "committing alter table to storage engine", 0}; +PSI_stage_info stage_apply_event= { 0, "apply log event", 0}; PSI_stage_info stage_changing_master= { 0, "Changing master", 0}; PSI_stage_info stage_checking_master_version= { 0, "Checking master version", 0}; PSI_stage_info stage_checking_permissions= { 0, "checking permissions", 0}; @@ -10273,6 +9828,7 @@ PSI_stage_info stage_sql_thd_waiting_until_delay= { 0, "Waiting until MASTER_DEL PSI_stage_info stage_storing_result_in_query_cache= { 0, "storing result in query cache", 0}; PSI_stage_info stage_storing_row_into_queue= { 0, "storing row into queue", 0}; PSI_stage_info stage_system_lock= { 0, "System lock", 0}; +PSI_stage_info stage_unlocking_tables= { 0, "Unlocking tables", 0}; PSI_stage_info stage_update= { 0, "update", 0}; PSI_stage_info stage_updating= { 0, "updating", 0}; PSI_stage_info stage_updating_main_table= { 0, "updating main table", 0}; @@ -10317,6 +9873,7 @@ PSI_stage_info stage_gtid_wait_other_connection= { 0, "Waiting for other master PSI_stage_info *all_server_stages[]= { + & stage_after_apply_event, & stage_after_create, & stage_after_opening_tables, & stage_after_table_lock, @@ -10324,6 +9881,7 @@ PSI_stage_info *all_server_stages[]= & stage_alter_inplace, & stage_alter_inplace_commit, & stage_alter_inplace_prepare, + & stage_apply_event, & stage_binlog_processing_checkpoint_notify, & stage_binlog_stopping_background_thread, & stage_binlog_waiting_background_tasks, @@ -10405,6 +9963,7 @@ PSI_stage_info *all_server_stages[]= & stage_storing_result_in_query_cache, & stage_storing_row_into_queue, & stage_system_lock, + & stage_unlocking_tables, & stage_update, & stage_updating, & stage_updating_main_table, diff --git a/sql/mysqld.h b/sql/mysqld.h index d00fa5c57a6..8a6794cc30c 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -25,6 +25,7 @@ #include "sql_list.h" /* I_List */ #include "sql_cmd.h" #include +#include "my_pthread.h" class THD; struct handlerton; @@ -333,6 +334,7 @@ void init_server_psi_keys(); MAINTAINER: Please keep this list in order, to limit merge collisions. Hint: grep PSI_stage_info | sort -u */ +extern PSI_stage_info stage_apply_event; extern PSI_stage_info stage_after_create; extern PSI_stage_info stage_after_opening_tables; extern PSI_stage_info stage_after_table_lock; @@ -340,6 +342,7 @@ extern PSI_stage_info stage_allocating_local_table; extern PSI_stage_info stage_alter_inplace_prepare; extern PSI_stage_info stage_alter_inplace; extern PSI_stage_info stage_alter_inplace_commit; +extern PSI_stage_info stage_after_apply_event; extern PSI_stage_info stage_changing_master; extern PSI_stage_info stage_checking_master_version; extern PSI_stage_info stage_checking_permissions; @@ -413,6 +416,7 @@ extern PSI_stage_info stage_statistics; extern PSI_stage_info stage_storing_result_in_query_cache; extern PSI_stage_info stage_storing_row_into_queue; extern PSI_stage_info stage_system_lock; +extern PSI_stage_info stage_unlocking_tables; extern PSI_stage_info stage_update; extern PSI_stage_info stage_updating; extern PSI_stage_info stage_updating_main_table; @@ -766,9 +770,4 @@ extern uint internal_tmp_table_max_key_segments; extern uint volatile global_disable_checkpoint; extern my_bool opt_help; -#ifdef WITH_WSREP -#include "my_pthread.h" -pthread_handler_t start_wsrep_THD(void*); -#endif /* WITH_WSREP */ - #endif /* MYSQLD_INCLUDED */ diff --git a/sql/protocol.cc b/sql/protocol.cc index af2accfd146..caa00dd80e3 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -488,14 +488,8 @@ static uchar *net_store_length_fast(uchar *packet, uint length) void Protocol::end_statement() { -#ifdef WITH_WSREP - /*sanity check, can be removed before 1.0 release */ - if (WSREP(thd) && thd->wsrep_conflict_state== REPLAYING) - { - WSREP_ERROR("attempting net_end_statement while replaying"); - return; - } -#endif + /* sanity check*/ + DBUG_ASSERT_IF_WSREP(!(WSREP_ON && WSREP(thd) && thd->wsrep_conflict_state == REPLAYING)); DBUG_ENTER("Protocol::end_statement"); DBUG_ASSERT(! thd->get_stmt_da()->is_sent()); bool error= FALSE; diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index b82dbb07a42..29a1b9728e5 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -305,13 +305,8 @@ unpack_row(rpl_group_info *rgi, normal unpack operation. */ uint16 const metadata= tabledef->field_metadata(i); -#ifndef DBUG_OFF uchar const *const old_pack_ptr= pack_ptr; -#else -#ifdef WITH_WSREP - uchar const *const old_pack_ptr= pack_ptr; -#endif /* WITH_WSREP */ -#endif /* !DBUF_OFF */ + pack_ptr= f->unpack(f->ptr, pack_ptr, row_end, metadata); DBUG_PRINT("debug", ("field: %s; metadata: 0x%x;" " pack_ptr: 0x%lx; pack_ptr': 0x%lx; bytes: %d", @@ -321,17 +316,21 @@ unpack_row(rpl_group_info *rgi, if (!pack_ptr) { #ifdef WITH_WSREP - /* - Debug message to troubleshoot bug: - https://mariadb.atlassian.net/browse/MDEV-4404 - */ - WSREP_WARN("ROW event unpack field: %s metadata: 0x%x;" - " pack_ptr: 0x%lx; conv_table %p conv_field %p table %s" - " row_end: 0x%lx", - f->field_name, metadata, - (ulong) old_pack_ptr, conv_table, conv_field, - (table_found) ? "found" : "not found", (ulong)row_end - ); + if (WSREP_ON) + { + /* + Debug message to troubleshoot bug: + https://mariadb.atlassian.net/browse/MDEV-4404 + Galera Node throws "Could not read field" error and drops out of cluster + */ + WSREP_WARN("ROW event unpack field: %s metadata: 0x%x;" + " pack_ptr: 0x%lx; conv_table %p conv_field %p table %s" + " row_end: 0x%lx", + f->field_name, metadata, + (ulong) old_pack_ptr, conv_table, conv_field, + (table_found) ? "found" : "not found", (ulong)row_end + ); + } #endif /* WITH_WSREP */ rgi->rli->report(ERROR_LEVEL, ER_SLAVE_CORRUPT_EVENT, diff --git a/sql/slave.cc b/sql/slave.cc index 54a32f320c0..746b1d48458 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -52,10 +52,8 @@ #include "log_event.h" // Rotate_log_event, // Create_file_log_event, // Format_description_log_event - -#ifdef WITH_WSREP #include "wsrep_mysqld.h" -#endif + #ifdef HAVE_REPLICATION #include "rpl_tblmap.h" @@ -4370,9 +4368,7 @@ pthread_handler_t handle_slave_sql(void *arg) my_off_t saved_skip= 0; Master_info *mi= ((Master_info*)arg); Relay_log_info* rli = &mi->rli; -#ifdef WITH_WSREP my_bool wsrep_node_dropped= FALSE; -#endif /* WITH_WSREP */ const char *errmsg; rpl_group_info *serial_rgi; rpl_sql_thread_info sql_info(mi->rpl_filter); @@ -4380,9 +4376,8 @@ pthread_handler_t handle_slave_sql(void *arg) // needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff my_thread_init(); DBUG_ENTER("handle_slave_sql"); -#ifdef WITH_WSREP + wsrep_restart_point: -#endif /* WITH_WSREP */ LINT_INIT(saved_master_log_pos); LINT_INIT(saved_log_pos); @@ -4515,7 +4510,8 @@ pthread_handler_t handle_slave_sql(void *arg) #ifdef WITH_WSREP thd->wsrep_exec_mode= LOCAL_STATE; /* synchronize with wsrep replication */ - if (WSREP_ON) wsrep_ready_wait(); + if (WSREP_ON) + wsrep_ready_wait(); #endif DBUG_PRINT("master_info",("log_file_name: %s position: %s", rli->group_master_log_name, @@ -4617,7 +4613,7 @@ log '%s' at position %s, relay log '%s' position: %s%s", RPL_LOG_NAME, rli->group_master_log_name, (ulong) rli->group_master_log_pos); saved_skip= 0; } - + if (exec_relay_log_event(thd, rli, serial_rgi)) { DBUG_PRINT("info", ("exec_relay_log_event() failed")); @@ -4626,8 +4622,7 @@ log '%s' at position %s, relay log '%s' position: %s%s", RPL_LOG_NAME, { slave_output_error_info(rli, thd); #ifdef WITH_WSREP - uint32 const last_errno= rli->last_error().number; - if (WSREP_ON && last_errno == ER_UNKNOWN_COM_ERROR) + if (WSREP_ON && rli->last_error().number == ER_UNKNOWN_COM_ERROR) { wsrep_node_dropped= TRUE; } @@ -4721,7 +4716,7 @@ err_during_init: /* if slave stopped due to node going non primary, we set global flag to trigger automatic restart of slave when node joins back to cluster */ - if (wsrep_node_dropped && wsrep_restart_slave) + if (WSREP_ON && wsrep_node_dropped && wsrep_restart_slave) { if (wsrep_ready) { diff --git a/sql/sp.cc b/sql/sp.cc index b5b543ead0e..261299464c5 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -32,7 +32,7 @@ #include -static bool +bool create_string(THD *thd, String *buf, stored_procedure_type sp_type, const char *db, ulong dblen, @@ -924,7 +924,7 @@ end: } -static void +void sp_returns_type(THD *thd, String &result, sp_head *sp) { TABLE table; @@ -2126,7 +2126,7 @@ int sp_cache_routine(THD *thd, enum stored_procedure_type type, sp_name *name, @return Returns TRUE on success, FALSE on (alloc) failure. */ -static bool +bool create_string(THD *thd, String *buf, stored_procedure_type type, const char *db, ulong dblen, @@ -2271,37 +2271,4 @@ sp_load_for_information_schema(THD *thd, TABLE *proc_table, String *db, thd->lex= old_lex; return sp; } -#ifdef WITH_WSREP -int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len) -{ - String log_query; - sp_head *sp = thd->lex->sphead; - ulong saved_mode= thd->variables.sql_mode; - String retstr(64); - retstr.set_charset(system_charset_info); - log_query.set_charset(system_charset_info); - - if (sp->m_type == TYPE_ENUM_FUNCTION) - { - sp_returns_type(thd, retstr, sp); - } - - if (!create_string(thd, &log_query, - sp->m_type, - (sp->m_explicit_name ? sp->m_db.str : NULL), - (sp->m_explicit_name ? sp->m_db.length : 0), - sp->m_name.str, sp->m_name.length, - sp->m_params.str, sp->m_params.length, - retstr.c_ptr(), retstr.length(), - sp->m_body.str, sp->m_body.length, - sp->m_chistics, &(thd->lex->definer->user), - &(thd->lex->definer->host), - saved_mode)) - { - WSREP_WARN("SP create string failed: %s", thd->query()); - return 1; - } - return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(), buf, buf_len); -} -#endif /* WITH_WSREP */ diff --git a/sql/sp.h b/sql/sp.h index 3353132346b..de32b5454f8 100644 --- a/sql/sp.h +++ b/sql/sp.h @@ -214,4 +214,19 @@ bool load_collation(MEM_ROOT *mem_root, CHARSET_INFO *dflt_cl, CHARSET_INFO **cl); +void sp_returns_type(THD *thd, + String &result, + sp_head *sp); + +bool create_string(THD *thd, String *buf, + stored_procedure_type type, + const char *db, ulong dblen, + const char *name, ulong namelen, + const char *params, ulong paramslen, + const char *returns, ulong returnslen, + const char *body, ulong bodylen, + st_sp_chistics *chistics, + const LEX_STRING *definer_user, + const LEX_STRING *definer_host, + ulonglong sql_mode); #endif /* _SP_H_ */ diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 2491c019e6a..b55b89265c4 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2560,12 +2560,8 @@ int check_alter_user(THD *thd, const char *host, const char *user) goto end; } -#ifdef WITH_WSREP - if ((!WSREP(thd) || !thd->wsrep_applier) && + if (IF_WSREP((!WSREP(thd) || !thd->wsrep_applier), 1) && !thd->slave_thread && !thd->security_ctx->priv_user[0]) -#else - if (!thd->slave_thread && !thd->security_ctx->priv_user[0]) -#endif /* WITH_WSREP */ { my_message(ER_PASSWORD_ANONYMOUS_USER, ER(ER_PASSWORD_ANONYMOUS_USER), MYF(0)); @@ -2576,10 +2572,9 @@ int check_alter_user(THD *thd, const char *host, const char *user) my_error(ER_PASSWORD_NO_MATCH, MYF(0)); goto end; } + if (!thd->slave_thread && -#ifdef WITH_WSREP - (!WSREP(thd) || !thd->wsrep_applier) && -#endif /* WITH_WSREP */ + IF_WSREP((!WSREP(thd) || !thd->wsrep_applier),1) && (strcmp(thd->security_ctx->priv_user, user) || my_strcasecmp(system_charset_info, host, thd->security_ctx->priv_host))) @@ -2648,9 +2643,8 @@ bool change_password(THD *thd, const char *host, const char *user, enum_binlog_format save_binlog_format; uint new_password_len= (uint) strlen(new_password); int result=0; -#ifdef WITH_WSREP const CSET_STRING query_save = thd->query_string; -#endif /* WITH_WSREP */ + DBUG_ENTER("change_password"); DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'", host,user,new_password)); @@ -2658,10 +2652,11 @@ bool change_password(THD *thd, const char *host, const char *user, if (check_change_password(thd, host, user, new_password, new_password_len)) DBUG_RETURN(1); + #ifdef WITH_WSREP if (WSREP(thd) && !thd->wsrep_applier) { - query_length= sprintf(buff, "SET PASSWORD FOR '%-.120s'@'%-.120s'='%-.120s'", + query_length= sprintf(buff, "SET PASSWORD FOR '%-.120s'@'%-.120s'='%-.120s'", user ? user : "", host ? host : "", new_password); @@ -2736,11 +2731,10 @@ end: DBUG_RETURN(result); -#ifdef WITH_WSREP - error: - WSREP_ERROR("Replication of SET PASSWORD failed: %s", buff); +error: + WSREP_ERROR("Repliation of SET PASSWORD failed: %s", buff); DBUG_RETURN(result); -#endif /* WITH_WSREP */ + } int acl_check_set_default_role(THD *thd, const char *host, const char *user) @@ -2759,9 +2753,7 @@ int acl_set_default_role(THD *thd, const char *host, const char *user, bool clear_role= FALSE; char buff[512]; enum_binlog_format save_binlog_format; -#ifdef WITH_WSREP const CSET_STRING query_save = thd->query_string; -#endif /* WITH_WSREP */ DBUG_ENTER("acl_set_default_role"); DBUG_PRINT("enter",("host: '%s' user: '%s' rolename: '%s'", @@ -2867,6 +2859,7 @@ int acl_set_default_role(THD *thd, const char *host, const char *user, } end: close_mysql_tables(thd); + #ifdef WITH_WSREP if (WSREP(thd) && !thd->wsrep_applier) { @@ -2876,14 +2869,10 @@ end: thd->wsrep_exec_mode = LOCAL_STATE; } #endif /* WITH_WSREP */ + thd->restore_stmt_binlog_format(save_binlog_format); DBUG_RETURN(result); -#ifdef WITH_WSREP - error: - WSREP_ERROR("Replication of SET PASSWORD failed: %s", buff); - DBUG_RETURN(result); -#endif /* WITH_WSREP */ } diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index ee70914d331..a620ae98c6d 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -1143,9 +1143,8 @@ bool Sql_cmd_analyze_table::execute(THD *thd) FALSE, UINT_MAX, FALSE)) goto error; thd->enable_slow_log= opt_log_slow_admin_statements; -#ifdef WITH_WSREP WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL); -#endif + res= mysql_admin_table(thd, first_table, &m_lex->check_opt, "analyze", lock_type, 1, 0, 0, 0, &handler::ha_analyze, 0); diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc index 8b4f4ab9963..cfe360217c2 100644 --- a/sql/sql_alter.cc +++ b/sql/sql_alter.cc @@ -18,9 +18,8 @@ // mysql_exchange_partition #include "sql_base.h" // open_temporary_tables #include "sql_alter.h" -#ifdef WITH_WSREP #include "wsrep_mysqld.h" -#endif /* WITH_WSREP */ + Alter_info::Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root) :drop_list(rhs.drop_list, mem_root), alter_list(rhs.alter_list, mem_root), @@ -320,6 +319,7 @@ bool Sql_cmd_alter_table::execute(THD *thd) DBUG_RETURN(TRUE); } #endif /* WITH_WSREP */ + result= mysql_alter_table(thd, select_lex->db, lex->name.str, &create_info, first_table, @@ -328,8 +328,6 @@ bool Sql_cmd_alter_table::execute(THD *thd) select_lex->order_list.first, lex->ignore); -#ifdef WITH_WSREP -#endif /* WITH_WSREP */ DBUG_RETURN(result); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 373adf2596e..68f325e20ab 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -61,11 +61,8 @@ #ifdef __WIN__ #include #endif - -#ifdef WITH_WSREP #include "wsrep_mysqld.h" #include "wsrep_thd.h" -#endif // WITH_WSREP bool No_such_table_error_handler::handle_condition(THD *, @@ -4588,8 +4585,10 @@ restart: } } } + #ifdef WITH_WSREP - if ((thd->lex->sql_command== SQLCOM_INSERT || + if (WSREP_ON && + (thd->lex->sql_command== SQLCOM_INSERT || thd->lex->sql_command== SQLCOM_INSERT_SELECT || thd->lex->sql_command== SQLCOM_REPLACE || thd->lex->sql_command== SQLCOM_REPLACE_SELECT || @@ -4608,15 +4607,7 @@ restart: err: THD_STAGE_INFO(thd, stage_after_opening_tables); - -#ifdef WITH_WSREP - if (WSREP(thd)) - thd_proc_info(thd, "exit open_tables()"); - else - thd_proc_info(thd, 0); -#else /* WITH_WSREP */ thd_proc_info(thd, 0); -#endif /* WITH_WSREP */ free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block @@ -5072,15 +5063,7 @@ end: } THD_STAGE_INFO(thd, stage_after_opening_tables); -#ifdef WITH_WSREP - if (WSREP(thd)) - thd_proc_info(thd, "End opening table"); - else thd_proc_info(thd, 0); -#else /* WITH_WSREP */ - thd_proc_info(thd, 0); -#endif /* WITH_WSREP */ - DBUG_RETURN(table); } @@ -9034,19 +9017,17 @@ bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use, (e.g. see partitioning code). */ if (!thd_table->needs_reopen()) -#ifdef WITH_WSREP { signalled|= mysql_lock_abort_for_thread(thd, thd_table); - if (thd && WSREP(thd) && wsrep_thd_is_BF((void *)thd, true)) +#ifdef WITH_WSREP + if (thd && WSREP(thd) && wsrep_thd_is_BF((void *)thd, true)) { WSREP_DEBUG("remove_table_from_cache: %llu", (unsigned long long) thd->real_id); wsrep_abort_thd((void *)thd, (void *)in_use, FALSE); } - } -#else - signalled|= mysql_lock_abort_for_thread(thd, thd_table); #endif + } } mysql_mutex_unlock(&in_use->LOCK_thd_data); } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index aef03199503..1f0c19538b2 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -64,10 +64,8 @@ #include "sql_parse.h" // is_update_query #include "sql_callback.h" #include "lock.h" -#ifdef WITH_WSREP #include "wsrep_mysqld.h" #include "wsrep_thd.h" -#endif #include "sql_connect.h" /* @@ -820,176 +818,6 @@ char *thd_get_error_context_description(THD *thd, char *buffer, return buffer; } -#ifdef WITH_WSREP -extern int wsrep_on(void *thd) -{ - return (int)(WSREP(((THD*)thd))); -} -extern "C" bool wsrep_thd_is_wsrep_on(THD *thd) -{ - return thd->variables.wsrep_on; -} - -extern "C" bool wsrep_consistency_check(void *thd) -{ - return ((THD*)thd)->wsrep_consistency_check == CONSISTENCY_CHECK_RUNNING; -} - -extern "C" void wsrep_thd_set_exec_mode(THD *thd, enum wsrep_exec_mode mode) -{ - thd->wsrep_exec_mode= mode; -} -extern "C" void wsrep_thd_set_query_state( - THD *thd, enum wsrep_query_state state) -{ - thd->wsrep_query_state= state; -} -extern "C" void wsrep_thd_set_conflict_state( - THD *thd, enum wsrep_conflict_state state) -{ - thd->wsrep_conflict_state= state; -} - - -extern "C" enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd) -{ - return thd->wsrep_exec_mode; -} - -extern "C" const char *wsrep_thd_exec_mode_str(THD *thd) -{ - return - (!thd) ? "void" : - (thd->wsrep_exec_mode == LOCAL_STATE) ? "local" : - (thd->wsrep_exec_mode == REPL_RECV) ? "applier" : - (thd->wsrep_exec_mode == TOTAL_ORDER) ? "total order" : - (thd->wsrep_exec_mode == LOCAL_COMMIT) ? "local commit" : "void"; -} - -extern "C" enum wsrep_query_state wsrep_thd_query_state(THD *thd) -{ - return thd->wsrep_query_state; -} - -extern "C" const char *wsrep_thd_query_state_str(THD *thd) -{ - return - (!thd) ? "void" : - (thd->wsrep_query_state == QUERY_IDLE) ? "idle" : - (thd->wsrep_query_state == QUERY_EXEC) ? "executing" : - (thd->wsrep_query_state == QUERY_COMMITTING) ? "committing" : - (thd->wsrep_query_state == QUERY_EXITING) ? "exiting" : - (thd->wsrep_query_state == QUERY_ROLLINGBACK) ? "rolling back" : "void"; -} - -extern "C" enum wsrep_conflict_state wsrep_thd_conflict_state(THD *thd) -{ - return thd->wsrep_conflict_state; -} -extern "C" const char *wsrep_thd_conflict_state_str(THD *thd) -{ - return - (!thd) ? "void" : - (thd->wsrep_conflict_state == NO_CONFLICT) ? "no conflict" : - (thd->wsrep_conflict_state == MUST_ABORT) ? "must abort" : - (thd->wsrep_conflict_state == ABORTING) ? "aborting" : - (thd->wsrep_conflict_state == MUST_REPLAY) ? "must replay" : - (thd->wsrep_conflict_state == REPLAYING) ? "replaying" : - (thd->wsrep_conflict_state == RETRY_AUTOCOMMIT) ? "retrying" : - (thd->wsrep_conflict_state == CERT_FAILURE) ? "cert failure" : "void"; -} - -extern "C" wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd) -{ - return &thd->wsrep_ws_handle; -} - -extern "C" void wsrep_thd_LOCK(THD *thd) -{ - mysql_mutex_lock(&thd->LOCK_wsrep_thd); -} -extern "C" void wsrep_thd_UNLOCK(THD *thd) -{ - mysql_mutex_unlock(&thd->LOCK_wsrep_thd); -} -extern "C" time_t wsrep_thd_query_start(THD *thd) -{ - return thd->query_start(); -} -extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd) -{ - return thd->wsrep_rand; -} -extern "C" my_thread_id wsrep_thd_thread_id(THD *thd) -{ - return thd->thread_id; -} -extern "C" wsrep_seqno_t wsrep_thd_trx_seqno(THD *thd) -{ - return (thd) ? thd->wsrep_trx_meta.gtid.seqno : WSREP_SEQNO_UNDEFINED; -} -extern "C" query_id_t wsrep_thd_query_id(THD *thd) -{ - return thd->query_id; -} -extern "C" char *wsrep_thd_query(THD *thd) -{ - return (thd) ? thd->query() : NULL; -} -extern "C" query_id_t wsrep_thd_wsrep_last_query_id(THD *thd) -{ - return thd->wsrep_last_query_id; -} -extern "C" void wsrep_thd_set_wsrep_last_query_id(THD *thd, query_id_t id) -{ - thd->wsrep_last_query_id= id; -} -extern "C" void wsrep_thd_awake(THD *thd, my_bool signal) -{ - if (signal) - { - mysql_mutex_lock(&thd->LOCK_thd_data); - thd->awake(KILL_QUERY); - mysql_mutex_unlock(&thd->LOCK_thd_data); - } - else - { - mysql_mutex_lock(&LOCK_wsrep_replaying); - mysql_cond_broadcast(&COND_wsrep_replaying); - mysql_mutex_unlock(&LOCK_wsrep_replaying); - } -} -extern "C" int wsrep_thd_retry_counter(THD *thd) -{ - return(thd->wsrep_retry_counter); -} - -extern int -wsrep_trx_order_before(void *thd1, void *thd2) -{ - if (wsrep_thd_trx_seqno((THD*)thd1) < wsrep_thd_trx_seqno((THD*)thd2)) { - WSREP_DEBUG("BF conflict, order: %lld %lld\n", - (long long)wsrep_thd_trx_seqno((THD*)thd1), - (long long)wsrep_thd_trx_seqno((THD*)thd2)); - return 1; - } - WSREP_DEBUG("waiting for BF, trx order: %lld %lld\n", - (long long)wsrep_thd_trx_seqno((THD*)thd1), - (long long)wsrep_thd_trx_seqno((THD*)thd2)); - return 0; -} -extern "C" int -wsrep_trx_is_aborting(void *thd_ptr) -{ - if (thd_ptr) { - if ((((THD *)thd_ptr)->wsrep_conflict_state == MUST_ABORT) || - (((THD *)thd_ptr)->wsrep_conflict_state == ABORTING)) { - return 1; - } - } - return 0; -} -#endif #if MARIA_PLUGIN_INTERFACE_VERSION < 0x0200 /** @@ -1069,7 +897,7 @@ THD::THD(bool is_applier) wsrep_client_thread(false), wsrep_po_handle(WSREP_PO_INITIALIZER), wsrep_po_cnt(0), - wsrep_po_in_trans(false), +// wsrep_po_in_trans(false), wsrep_apply_format(0), wsrep_apply_toi(false), #endif @@ -1243,13 +1071,9 @@ THD::THD(bool is_applier) my_rnd_init(&rand, tmp + (ulong) &rand, tmp + (ulong) ::global_query_id); substitute_null_with_insert_id = FALSE; thr_lock_info_init(&lock_info); /* safety: will be reset after start */ -#ifdef WITH_WSREP lock_info.mysql_thd= (void *)this; - lock_info.in_lock_tables= false; -#ifdef WSREP_PROC_INFO + wsrep_info[sizeof(wsrep_info) - 1] = '\0'; /* make sure it is 0-terminated */ -#endif /* WSREP_PROC_INFO */ -#endif /* WITH_WSREP */ m_internal_handler= NULL; m_binlog_invoker= INVOKER_NONE; @@ -1992,9 +1816,6 @@ void THD::awake(killed_state state_to_set) /* Interrupt target waiting inside a storage engine. */ if (state_to_set != NOT_KILLED) -#ifdef WITH_WSREP - /* TODO: prevent applier close here */ -#endif /* WITH_WSREP */ ha_kill_query(this, thd_kill_level(this)); /* Broadcast a condition to kick the target if it is waiting on it. */ @@ -2127,19 +1948,17 @@ bool THD::notify_shared_lock(MDL_context_owner *ctx_in_use, (e.g. see partitioning code). */ if (!thd_table->needs_reopen()) -#ifdef WITH_WSREP { signalled|= mysql_lock_abort_for_thread(this, thd_table); - if (this && WSREP(this) && wsrep_thd_is_BF((void *)this, FALSE)) +#if WITH_WSREP + if (WSREP_ON && this && WSREP(this) && wsrep_thd_is_BF((void *)this, FALSE)) { WSREP_DEBUG("remove_table_from_cache: %llu", (unsigned long long) this->real_id); wsrep_abort_thd((void *)this, (void *)in_use, FALSE); } +#endif /* WITH_WSREP */ } -#else - signalled|= mysql_lock_abort_for_thread(this, thd_table); -#endif } mysql_mutex_unlock(&in_use->LOCK_thd_data); } @@ -2322,11 +2141,10 @@ void THD::cleanup_after_query() table_map_for_update= 0; m_binlog_invoker= INVOKER_NONE; #ifdef WITH_WSREP - if (TOTAL_ORDER == wsrep_exec_mode) - { - wsrep_exec_mode = LOCAL_STATE; - } - //wsrep_trx_seqno = 0; + if (WSREP_ON && TOTAL_ORDER == wsrep_exec_mode) + { + wsrep_exec_mode = LOCAL_STATE; + } #endif /* WITH_WSREP */ #ifndef EMBEDDED_LIBRARY @@ -2751,7 +2569,7 @@ bool select_send::send_result_set_metadata(List &list, uint flags) { bool res; #ifdef WITH_WSREP - if (WSREP(thd) && thd->wsrep_retry_query) + if (WSREP_ON && WSREP(thd) && thd->wsrep_retry_query) { WSREP_DEBUG("skipping select metadata"); return FALSE; @@ -4502,12 +4320,9 @@ extern "C" int thd_non_transactional_update(const MYSQL_THD thd) extern "C" int thd_binlog_format(const MYSQL_THD thd) { -#ifdef WITH_WSREP - if (((WSREP(thd) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()) && - (thd->variables.option_bits & OPTION_BIN_LOG)) -#else - if (mysql_bin_log.is_open() && (thd->variables.option_bits & OPTION_BIN_LOG)) -#endif + if (IF_WSREP(((WSREP(thd) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()), + mysql_bin_log.is_open()) && + thd->variables.option_bits & OPTION_BIN_LOG) return (int) WSREP_FORMAT(thd->variables.binlog_format); else return BINLOG_FORMAT_UNSPEC; @@ -5494,14 +5309,10 @@ int THD::decide_logging_format(TABLE_LIST *tables) 5. Error: Cannot modify table that uses a storage engine limited to row-logging when binlog_format = STATEMENT */ -#ifdef WITH_WSREP - if (!WSREP(this) || wsrep_exec_mode == LOCAL_STATE) + if (IF_WSREP(WSREP_ON && (!WSREP(this) || wsrep_exec_mode == LOCAL_STATE),1)) { -#endif /* WITH_WSREP */ - my_error((error= ER_BINLOG_STMT_MODE_AND_ROW_ENGINE), MYF(0), ""); -#ifdef WITH_WSREP + my_error((error= ER_BINLOG_STMT_MODE_AND_ROW_ENGINE), MYF(0), ""); } -#endif /* WITH_WSREP */ } else if (is_write && (unsafe_flags= lex->get_stmt_unsafe_flags()) != 0) { @@ -5849,15 +5660,11 @@ CPP_UNNAMED_NS_END int THD::binlog_write_row(TABLE* table, bool is_trans, MY_BITMAP const* cols, size_t colcnt, uchar const *record) -{ -#ifdef WITH_WSREP - DBUG_ASSERT(is_current_stmt_binlog_format_row() && - ((WSREP(this) && wsrep_emulate_bin_log) || - mysql_bin_log.is_open())); -#else - DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open()); -#endif +{ + DBUG_ASSERT(is_current_stmt_binlog_format_row() && + IF_WSREP(((WSREP_ON && WSREP(this) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()), + mysql_bin_log.is_open())); /* Pack records into format for transfer. We are allocating more memory than needed, but that doesn't matter. @@ -5889,14 +5696,10 @@ int THD::binlog_update_row(TABLE* table, bool is_trans, MY_BITMAP const* cols, size_t colcnt, const uchar *before_record, const uchar *after_record) -{ -#ifdef WITH_WSREP - DBUG_ASSERT(is_current_stmt_binlog_format_row() && - ((WSREP(this) && wsrep_emulate_bin_log) - || mysql_bin_log.is_open())); -#else - DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open()); -#endif +{ + DBUG_ASSERT(is_current_stmt_binlog_format_row() && + IF_WSREP(((WSREP_ON && WSREP(this) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()), + mysql_bin_log.is_open())); size_t const before_maxlen = max_row_length(table, before_record); size_t const after_maxlen = max_row_length(table, after_record); @@ -5944,14 +5747,10 @@ int THD::binlog_update_row(TABLE* table, bool is_trans, int THD::binlog_delete_row(TABLE* table, bool is_trans, MY_BITMAP const* cols, size_t colcnt, uchar const *record) -{ -#ifdef WITH_WSREP - DBUG_ASSERT(is_current_stmt_binlog_format_row() && - ((WSREP(this) && wsrep_emulate_bin_log) - || mysql_bin_log.is_open())); -#else - DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open()); -#endif +{ + DBUG_ASSERT(is_current_stmt_binlog_format_row() && + IF_WSREP(((WSREP_ON && WSREP(this) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()), + mysql_bin_log.is_open())); /* Pack records into format for transfer. We are allocating more @@ -5986,11 +5785,8 @@ int THD::binlog_remove_pending_rows_event(bool clear_maps, { DBUG_ENTER("THD::binlog_remove_pending_rows_event"); -#ifdef WITH_WSREP - if (!(WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open())) -#else - if (!mysql_bin_log.is_open()) -#endif + IF_WSREP(WSREP_ON && !(WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open()), + !mysql_bin_log.is_open()); DBUG_RETURN(0); /* Ensure that all events in a GTID group are in the same cache */ @@ -6013,11 +5809,8 @@ int THD::binlog_flush_pending_rows_event(bool stmt_end, bool is_transactional) mode: it might be the case that we left row-based mode before flushing anything (e.g., if we have explicitly locked tables). */ -#ifdef WITH_WSREP - if (!(WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open())) -#else - if (!mysql_bin_log.is_open()) -#endif + IF_WSREP(WSREP_ON && !(WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open()), + !mysql_bin_log.is_open()); DBUG_RETURN(0); /* Ensure that all events in a GTID group are in the same cache */ @@ -6269,12 +6062,10 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg, DBUG_ENTER("THD::binlog_query"); DBUG_PRINT("enter", ("qtype: %s query: '%-.*s'", show_query_type(qtype), (int) query_len, query_arg)); -#ifdef WITH_WSREP - DBUG_ASSERT(query_arg && (WSREP_EMULATE_BINLOG(this) - || mysql_bin_log.is_open())); -#else - DBUG_ASSERT(query_arg && mysql_bin_log.is_open()); -#endif + + DBUG_ASSERT(query_arg && + IF_WSREP(WSREP_ON && (WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open()), + mysql_bin_log.is_open())); /* If this is withing a BEGIN ... COMMIT group, don't log it */ if (variables.option_bits & OPTION_GTID_BEGIN) diff --git a/sql/sql_class.h b/sql/sql_class.h index 0f8ac303f3d..b2f7b459cb4 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -50,25 +50,14 @@ void set_thd_stage_info(void *thd, const char *calling_func, const char *calling_file, const unsigned int calling_line); - + #define THD_STAGE_INFO(thd, stage) \ (thd)->enter_stage(& stage, NULL, __func__, __FILE__, __LINE__) #include "my_apc.h" #include "rpl_gtid.h" - -#ifdef WITH_WSREP #include "wsrep_mysqld.h" -struct wsrep_thd_shadow { - ulonglong options; - uint server_status; - enum wsrep_exec_mode wsrep_exec_mode; - Vio *vio; - ulong tx_isolation; - char *db; - size_t db_length; -}; -#endif + class Reprepare_observer; class Relay_log_info; struct rpl_group_info; @@ -2746,6 +2735,9 @@ public: const bool wsrep_applier; /* dedicated slave applier thread */ bool wsrep_applier_closing; /* applier marked to close */ bool wsrep_client_thread; /* to identify client threads*/ + bool wsrep_PA_safe; + bool wsrep_converted_lock_session; + bool wsrep_apply_toi; /* applier processing in TOI */ enum wsrep_exec_mode wsrep_exec_mode; query_id_t wsrep_last_query_id; enum wsrep_query_state wsrep_query_state; @@ -2758,17 +2750,13 @@ public: uint32 wsrep_rand; Relay_log_info* wsrep_rli; rpl_group_info* wsrep_rgi; - bool wsrep_converted_lock_session; wsrep_ws_handle_t wsrep_ws_handle; -#ifdef WSREP_PROC_INFO char wsrep_info[128]; /* string for dynamic proc info */ -#endif /* WSREP_PROC_INFO */ ulong wsrep_retry_counter; // of autocommit - bool wsrep_PA_safe; char* wsrep_retry_query; size_t wsrep_retry_query_len; enum enum_server_command wsrep_retry_command; - enum wsrep_consistency_check_mode + enum wsrep_consistency_check_mode wsrep_consistency_check; wsrep_stats_var* wsrep_status_vars; int wsrep_mysql_replicated; @@ -2777,12 +2765,10 @@ public: size_t wsrep_TOI_pre_query_len; wsrep_po_handle_t wsrep_po_handle; size_t wsrep_po_cnt; - my_bool wsrep_po_in_trans; #ifdef GTID_SUPPORT rpl_sid wsrep_po_sid; #endif /* GTID_SUPPORT */ void* wsrep_apply_format; - bool wsrep_apply_toi; /* applier processing in TOI */ #endif /* WITH_WSREP */ /** Internal parser state. diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 357294a567a..0065edcc14d 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -37,6 +37,7 @@ // reset_host_errors #include "sql_acl.h" // acl_getroot, NO_ACCESS, SUPER_ACL #include "sql_callback.h" +#include "wsrep_mysqld.h" HASH global_user_stats, global_client_stats, global_table_stats; HASH global_index_stats; @@ -44,9 +45,6 @@ HASH global_index_stats; extern mysql_mutex_t LOCK_global_user_client_stats; extern mysql_mutex_t LOCK_global_table_stats; extern mysql_mutex_t LOCK_global_index_stats; -#ifdef WITH_WSREP -#include "wsrep_mysqld.h" -#endif /* Get structure for logging connection data for the current user @@ -1397,7 +1395,7 @@ void do_handle_one_connection(THD *thd_arg) break; } end_connection(thd); - + #ifdef WITH_WSREP if (WSREP(thd)) { diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 9a6ca541706..5eb4c405c4b 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -642,22 +642,19 @@ cleanup: if (!transactional_table && deleted > 0) thd->transaction.stmt.modified_non_trans_table= thd->transaction.all.modified_non_trans_table= TRUE; - + /* See similar binlogging code in sql_update.cc, for comments */ if ((error < 0) || thd->transaction.stmt.modified_non_trans_table) { -#ifdef WITH_WSREP - if ((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open())) -#else - if (mysql_bin_log.is_open()) -#endif + if(IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), + mysql_bin_log.is_open())) { int errcode= 0; if (error < 0) thd->clear_error(); else errcode= query_error_code(thd, killed_status == NOT_KILLED); - + /* [binlog]: If 'handler::delete_all_rows()' was called and the storage engine does not inject the rows itself, we replicate @@ -1111,17 +1108,14 @@ void multi_delete::abort_result_set() DBUG_ASSERT(error_handled); DBUG_VOID_RETURN; } - + if (thd->transaction.stmt.modified_non_trans_table) { - /* + /* there is only side effects; to binlog with the error */ -#ifdef WITH_WSREP - if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) -#else - if (mysql_bin_log.is_open()) -#endif + if (IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), + mysql_bin_log.is_open())) { int errcode= query_error_code(thd, thd->killed == NOT_KILLED); /* possible error of writing binary log is ignored deliberately */ @@ -1297,11 +1291,8 @@ bool multi_delete::send_eof() } if ((local_error == 0) || thd->transaction.stmt.modified_non_trans_table) { -#ifdef WITH_WSREP - if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) -#else - if (mysql_bin_log.is_open()) -#endif + if(IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), + mysql_bin_log.is_open())) { int errcode= 0; if (local_error == 0) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 2097f636dd2..5ee341435cf 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1014,11 +1014,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, thd->transaction.stmt.modified_non_trans_table || was_insert_delayed) { -#ifdef WITH_WSREP - if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) -#else - if (mysql_bin_log.is_open()) -#endif + if(IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), + mysql_bin_log.is_open())) { int errcode= 0; if (error <= 0) @@ -3199,6 +3196,7 @@ bool Delayed_insert::handle_inserts(void) mysql_cond_broadcast(&cond_client); // If waiting clients } } + #ifdef WITH_WSREP if (WSREP((&thd))) thd_proc_info(&thd, "insert done"); @@ -3657,15 +3655,11 @@ bool select_insert::send_eof() DBUG_PRINT("enter", ("trans_table=%d, table_type='%s'", trans_table, table->file->table_type())); -#ifdef WITH_WSREP - error= (thd->wsrep_conflict_state == MUST_ABORT || - thd->wsrep_conflict_state == CERT_FAILURE) ? -1 : - (thd->locked_tables_mode <= LTM_LOCK_TABLES ? - table->file->ha_end_bulk_insert() : 0); -#else - error= (thd->locked_tables_mode <= LTM_LOCK_TABLES ? - table->file->ha_end_bulk_insert() : 0); -#endif /* WITH_WSREP */ + error = IF_WSREP((thd->wsrep_conflict_state == MUST_ABORT || + thd->wsrep_conflict_state == CERT_FAILURE) ? -1 :, ) + (thd->locked_tables_mode <= LTM_LOCK_TABLES ? + table->file->ha_end_bulk_insert() : 0); + if (!error && thd->is_error()) error= thd->get_stmt_da()->sql_errno(); @@ -3693,13 +3687,9 @@ bool select_insert::send_eof() events are in the transaction cache and will be written when ha_autocommit_or_rollback() is issued below. */ -#ifdef WITH_WSREP - if ((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) && - (!error || thd->transaction.stmt.modified_non_trans_table)) -#else - if (mysql_bin_log.is_open() && - (!error || thd->transaction.stmt.modified_non_trans_table)) -#endif + if(IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), + mysql_bin_log.is_open()) && + (!error || thd->transaction.stmt.modified_non_trans_table)) { int errcode= 0; if (!error) @@ -3783,11 +3773,8 @@ void select_insert::abort_result_set() { if (!can_rollback_data()) thd->transaction.all.modified_non_trans_table= TRUE; -#ifdef WITH_WSREP - if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) -#else - if (mysql_bin_log.is_open()) -#endif + if(IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), + mysql_bin_log.is_open())) { int errcode= query_error_code(thd, thd->killed == NOT_KILLED); /* error of writing binary log is ignored */ @@ -4195,11 +4182,8 @@ select_create::binlog_show_create_table(TABLE **tables, uint count) create_info->table_was_deleted); DBUG_ASSERT(result == 0); /* store_create_info() always return 0 */ -#ifdef WITH_WSREP - if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) -#else - if (mysql_bin_log.is_open()) -#endif /* WITH_WSREP */ + if(IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), + mysql_bin_log.is_open())) { int errcode= query_error_code(thd, thd->killed == NOT_KILLED); result= thd->binlog_query(THD::STMT_QUERY_TYPE, @@ -4209,9 +4193,9 @@ select_create::binlog_show_create_table(TABLE **tables, uint count) /* suppress_use */ FALSE, errcode); } -#ifdef WITH_WSREP - ha_wsrep_fake_trx_id(thd); -#endif + + IF_WSREP(ha_wsrep_fake_trx_id(thd), ); + return result; } @@ -4242,16 +4226,19 @@ bool select_create::send_eof() if (!(thd->variables.option_bits & OPTION_GTID_BEGIN)) trans_commit_implicit(thd); #ifdef WITH_WSREP + if (WSREP_ON) + { mysql_mutex_lock(&thd->LOCK_wsrep_thd); if (thd->wsrep_conflict_state != NO_CONFLICT) { - WSREP_DEBUG("select_create commit failed, thd: %lu err: %d %s", + WSREP_DEBUG("select_create commit failed, thd: %lu err: %d %s", thd->thread_id, thd->wsrep_conflict_state, thd->query()); mysql_mutex_unlock(&thd->LOCK_wsrep_thd); abort_result_set(); return TRUE; } mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } #endif /* WITH_WSREP */ } else if (!thd->is_current_stmt_binlog_format_row()) diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index ea6817ad0b2..926aa7d5e5a 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2009, 2013, Monty Program Ab. + Copyright (c) 2009, 2014, Monty Program Ab. 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 @@ -1580,7 +1580,7 @@ int lex_one_token(void *arg, THD *thd) else { #ifdef WITH_WSREP - if (version == 99997 && thd->wsrep_exec_mode == LOCAL_STATE) + if (WSREP(thd) && version == 99997 && thd->wsrep_exec_mode == LOCAL_STATE) { WSREP_DEBUG("consistency check: %s", thd->query()); thd->wsrep_consistency_check= CONSISTENCY_CHECK_DECLARED; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ad8418d5b59..87efbabe6f8 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2008, 2013, Monty Program Ab + Copyright (c) 2008, 2014, Monty Program Ab 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 @@ -103,12 +103,14 @@ #include "../storage/maria/ha_maria.h" #endif -#ifdef WITH_WSREP #include "wsrep_mysqld.h" #include "wsrep_thd.h" + +#ifdef WITH_WSREP static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length, Parser_state *parser_state); #endif /* WITH_WSREP */ + /** @defgroup Runtime_Environment Runtime Environment @{ @@ -895,18 +897,20 @@ bool do_command(THD *thd) NET *net= &thd->net; enum enum_server_command command; DBUG_ENTER("do_command"); + #ifdef WITH_WSREP if (WSREP(thd)) { mysql_mutex_lock(&thd->LOCK_wsrep_thd); thd->wsrep_query_state= QUERY_IDLE; - if (thd->wsrep_conflict_state==MUST_ABORT) + if (thd->wsrep_conflict_state==MUST_ABORT) { wsrep_client_rollback(thd); } mysql_mutex_unlock(&thd->LOCK_wsrep_thd); } #endif /* WITH_WSREP */ + /* indicator of uninitialized lex => normal flow of errors handling (see my_message_sql) @@ -976,19 +980,17 @@ bool do_command(THD *thd) thd->wsrep_query_state= QUERY_EXEC; mysql_mutex_unlock(&thd->LOCK_wsrep_thd); } - - if ((WSREP(thd) && packet_length == packet_error) || - (!WSREP(thd) && (packet_length == packet_error))) -#else - if (packet_length == packet_error) #endif /* WITH_WSREP */ + + if (packet_length == packet_error) { DBUG_PRINT("info",("Got error %d reading command from socket %s", net->error, vio_description(net->vio))); #ifdef WITH_WSREP - if (WSREP(thd)) { + if (WSREP(thd)) + { mysql_mutex_lock(&thd->LOCK_wsrep_thd); if (thd->wsrep_conflict_state == MUST_ABORT) { @@ -998,6 +1000,7 @@ bool do_command(THD *thd) mysql_mutex_unlock(&thd->LOCK_wsrep_thd); } #endif /* WITH_WSREP */ + /* Instrument this broken statement as "statement/com/error" */ thd->m_statement_psi= MYSQL_REFINE_STATEMENT(thd->m_statement_psi, com_statement_info[COM_END]. @@ -1053,7 +1056,8 @@ bool do_command(THD *thd) command_name[command].str)); #ifdef WITH_WSREP - if (WSREP(thd)) { + if (WSREP(thd)) + { /* * bail out if DB snapshot has not been installed. We however, * allow queries "SET" and "SHOW", they are trapped later in execute_command @@ -1087,7 +1091,8 @@ bool do_command(THD *thd) DBUG_ASSERT(!thd->apc_target.is_enabled()); return_value= dispatch_command(command, thd, packet+1, (uint) (packet_length-1)); #ifdef WITH_WSREP - if (WSREP(thd)) { + if (WSREP(thd)) + { while (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT) { WSREP_DEBUG("Retry autocommit for: %s\n", thd->wsrep_retry_query); @@ -1105,13 +1110,14 @@ bool do_command(THD *thd) thd->wsrep_retry_query_len); thd->variables.character_set_client = current_charset; } - } - if (thd->wsrep_retry_query && thd->wsrep_conflict_state != REPLAYING) - { - my_free(thd->wsrep_retry_query); - thd->wsrep_retry_query = NULL; - thd->wsrep_retry_query_len = 0; - thd->wsrep_retry_command = COM_CONNECT; + + if (thd->wsrep_retry_query && thd->wsrep_conflict_state != REPLAYING) + { + my_free(thd->wsrep_retry_query); + thd->wsrep_retry_query = NULL; + thd->wsrep_retry_query_len = 0; + thd->wsrep_retry_command = COM_CONNECT; + } } #endif /* WITH_WSREP */ DBUG_ASSERT(!thd->apc_target.is_enabled()); @@ -1137,7 +1143,7 @@ out: @retval FALSE The statement isn't updating any relevant tables. */ -static my_bool deny_updates_if_read_only_option(THD *thd, +my_bool deny_updates_if_read_only_option(THD *thd, TABLE_LIST *all_tables) { DBUG_ENTER("deny_updates_if_read_only_option"); @@ -1191,33 +1197,7 @@ static my_bool deny_updates_if_read_only_option(THD *thd, DBUG_RETURN(FALSE); } -#ifdef WITH_WSREP -static my_bool wsrep_read_only_option(THD *thd, TABLE_LIST *all_tables) -{ - int opt_readonly_saved = opt_readonly; - ulong flag_saved = (ulong)(thd->security_ctx->master_access & SUPER_ACL); - opt_readonly = 0; - thd->security_ctx->master_access &= ~SUPER_ACL; - - my_bool ret = !deny_updates_if_read_only_option(thd, all_tables); - - opt_readonly = opt_readonly_saved; - thd->security_ctx->master_access |= flag_saved; - - return ret; -} - -static void wsrep_copy_query(THD *thd) -{ - thd->wsrep_retry_command = thd->get_command(); - thd->wsrep_retry_query_len = thd->query_length(); - thd->wsrep_retry_query = (char *)my_malloc( - thd->wsrep_retry_query_len + 1, MYF(0)); - strncpy(thd->wsrep_retry_query, thd->query(), thd->wsrep_retry_query_len); - thd->wsrep_retry_query[thd->wsrep_retry_query_len] = '\0'; -} -#endif /* WITH_WSREP */ /** Perform one connection-level (COM_XXXX) command. @@ -1248,7 +1228,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, DBUG_PRINT("info", ("command: %d", command)); #ifdef WITH_WSREP - if (WSREP(thd)) { + if (WSREP(thd)) + { if (!thd->in_multi_stmt_transaction_mode()) { thd->wsrep_PA_safe= true; @@ -1480,10 +1461,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; #ifdef WITH_WSREP - wsrep_mysql_parse(thd, thd->query(), thd->query_length(), &parser_state); -#else - mysql_parse(thd, thd->query(), thd->query_length(), &parser_state); + if (WSREP_ON) + wsrep_mysql_parse(thd, thd->query(), thd->query_length(), &parser_state); + else #endif /* WITH_WSREP */ + mysql_parse(thd, thd->query(), thd->query_length(), &parser_state); while (!thd->killed && (parser_state.m_lip.found_semicolon != NULL) && ! thd->is_error()) @@ -1557,19 +1539,20 @@ bool dispatch_command(enum enum_server_command command, THD *thd, Count each statement from the client. */ statistic_increment(thd->status_var.questions, &LOCK_status); -#ifdef WITH_WSREP - if (!WSREP(thd)) + + if(IF_WSREP(!WSREP(thd), 1)) thd->set_time(); /* Reset the query start time. */ -#else - thd->set_time(); /* Reset the query start time. */ -#endif /* WITH_WSREP */ + parser_state.reset(beginning_of_next_stmt, length); /* TODO: set thd->lex->sql_command to SQLCOM_END here */ + #ifdef WITH_WSREP - wsrep_mysql_parse(thd, beginning_of_next_stmt, length, &parser_state); -#else - mysql_parse(thd, beginning_of_next_stmt, length, &parser_state); + if (WSREP_ON) + wsrep_mysql_parse(thd, beginning_of_next_stmt, length, &parser_state); + else #endif /* WITH_WSREP */ + mysql_parse(thd, beginning_of_next_stmt, length, &parser_state); + } DBUG_PRINT("info",("query ready")); @@ -1909,7 +1892,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, #ifdef WITH_WSREP dispatch_end: - if (WSREP(thd)) { + if (WSREP(thd)) + { /* wsrep BF abort in query exec phase */ mysql_mutex_lock(&thd->LOCK_wsrep_thd); if ((thd->wsrep_conflict_state != REPLAYING) && @@ -1919,25 +1903,25 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->update_server_status(); thd->protocol->end_statement(); query_cache_end_of_result(thd); - } + } else { mysql_mutex_unlock(&thd->LOCK_wsrep_thd); } - } else { /* if (WSREP(thd))... */ + } + else #endif /* WITH_WSREP */ - DBUG_ASSERT(thd->derived_tables == NULL && - (thd->open_tables == NULL || + { + DBUG_ASSERT(thd->derived_tables == NULL && + (thd->open_tables == NULL || (thd->locked_tables_mode == LTM_LOCK_TABLES))); - thd_proc_info(thd, "updating status"); - /* Finalize server status flags after executing a command. */ - thd->update_server_status(); - thd->protocol->end_statement(); - query_cache_end_of_result(thd); -#ifdef WITH_WSREP + thd_proc_info(thd, "updating status"); + /* Finalize server status flags after executing a command. */ + thd->update_server_status(); + thd->protocol->end_statement(); + query_cache_end_of_result(thd); } -#endif /* WITH_WSREP */ if (!thd->is_error() && !thd->killed_errno()) mysql_audit_general(thd, MYSQL_AUDIT_GENERAL_RESULT, 0, 0); @@ -2389,13 +2373,6 @@ err: return TRUE; } -#ifdef WITH_WSREP -static bool wsrep_is_show_query(enum enum_sql_command command) -{ - DBUG_ASSERT(command >= 0 && command <= SQLCOM_END); - return (sql_command_flags[command] & CF_STATUS_COMMAND) != 0; -} -#endif /* WITH_WSREP */ /** Execute command saved in thd and lex->sql_command. @@ -2598,7 +2575,8 @@ mysql_execute_command(THD *thd) } /* endif unlikely slave */ #endif #ifdef WITH_WSREP - if (WSREP(thd)) { + if (WSREP(thd)) + { /* change LOCK TABLE WRITE to transaction */ @@ -2630,31 +2608,10 @@ mysql_execute_command(THD *thd) lex->sql_command != SQLCOM_SET_OPTION && !wsrep_is_show_query(lex->sql_command)) { -#if DIRTY_HACK - /* Dirty hack for lp:1002714 - trying to recognize mysqldump connection - * and allow it to continue. Actuall mysqldump_magic_str may be longer - * and is obviously version dependent and may be issued by any client - * connection after which connection becomes non-replicating. */ - static char const mysqldump_magic_str[]= -"SELECT LOGFILE_GROUP_NAME, FILE_NAME, TOTAL_EXTENTS, INITIAL_SIZE, ENGINE, EXTRA FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'UNDO LOG' AND FILE_NAME IS NOT NULL"; - static const size_t mysqldump_magic_str_len= sizeof(mysqldump_magic_str) -1; - if (SQLCOM_SELECT != lex->sql_command || - thd->query_length() < mysqldump_magic_str_len || - strncmp(thd->query(), mysqldump_magic_str, mysqldump_magic_str_len)) - { -#endif /* DIRTY_HACK */ my_message(ER_UNKNOWN_COM_ERROR, "WSREP has not yet prepared node for application use", MYF(0)); goto error; -#if DIRTY_HACK - } - else - { - /* mysqldump connection, allow all further queries to pass */ - thd->variables.wsrep_on= FALSE; - } -#endif /* DIRTY_HACK */ } } #endif /* WITH_WSREP */ @@ -2701,16 +2658,14 @@ mysql_execute_command(THD *thd) if (trans_commit_implicit(thd)) { thd->mdl_context.release_transactional_locks(); -#ifdef WITH_WSREP WSREP_DEBUG("implicit commit failed, MDL released: %lu", thd->thread_id); -#endif /* WITH_WSREP */ goto error; } /* Release metadata locks acquired in this transaction. */ thd->mdl_context.release_transactional_locks(); } } - + #ifndef DBUG_OFF if (lex->sql_command != SQLCOM_SET_OPTION) DEBUG_SYNC(thd,"before_execute_sql_command"); @@ -2764,7 +2719,8 @@ mysql_execute_command(THD *thd) case SQLCOM_SHOW_STATUS: { #ifdef WITH_WSREP - if (WSREP_CLIENT(thd) && wsrep_causal_wait(thd)) goto error; + if (WSREP_CLIENT(thd) && wsrep_causal_wait(thd)) + goto error; #endif /* WITH_WSREP */ execute_show_status(thd, all_tables); break; @@ -2799,7 +2755,8 @@ mysql_execute_command(THD *thd) case SQLCOM_SHOW_STATUS_PROC: case SQLCOM_SHOW_STATUS_FUNC: #ifdef WITH_WSREP - if (WSREP_CLIENT(thd) && wsrep_causal_wait(thd)) goto error; + if (WSREP_CLIENT(thd) && wsrep_causal_wait(thd)) + goto error; #endif /* WITH_WSREP */ case SQLCOM_SHOW_DATABASES: @@ -2823,7 +2780,8 @@ mysql_execute_command(THD *thd) case SQLCOM_SHOW_INDEX_STATS: case SQLCOM_SELECT: #ifdef WITH_WSREP - if (WSREP_CLIENT(thd) && wsrep_causal_wait(thd)) goto error; + if (WSREP_CLIENT(thd) && wsrep_causal_wait(thd)) + goto error; case SQLCOM_SHOW_VARIABLES: case SQLCOM_SHOW_CHARSETS: case SQLCOM_SHOW_COLLATIONS: @@ -3187,7 +3145,7 @@ case SQLCOM_PREPARE: */ if(lex->ignore) lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_IGNORE_SELECT); - + if(lex->duplicates == DUP_REPLACE) lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_REPLACE_SELECT); @@ -3199,7 +3157,7 @@ case SQLCOM_PREPARE: raise a warning, as it may cause problems (see 'NAME_CONST issues' in 'Binary Logging of Stored Programs') */ - if (thd->query_name_consts && + if (thd->query_name_consts && mysql_bin_log.is_open() && WSREP_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_STMT && !mysql_bin_log.is_query_in_union(thd, thd->query_id)) @@ -3320,8 +3278,8 @@ case SQLCOM_PREPARE: /* in STATEMENT format, we probably have to replicate also temporary tables, like mysql replication does */ - if (!thd->is_current_stmt_binlog_format_row() || - !(create_info.options & HA_LEX_CREATE_TMP_TABLE)) + if (WSREP_ON && (!thd->is_current_stmt_binlog_format_row() || + !(create_info.options & HA_LEX_CREATE_TMP_TABLE))) WSREP_TO_ISOLATION_BEGIN(create_table->db, create_table->table_name, NULL) #endif /* WITH_WSREP */ @@ -3510,7 +3468,8 @@ end_with_restore_list: #else { #ifdef WITH_WSREP - if (WSREP_CLIENT(thd) && wsrep_causal_wait(thd)) goto error; + if (WSREP_CLIENT(thd) && wsrep_causal_wait(thd)) + goto error; #endif /* WITH_WSREP */ /* @@ -3576,7 +3535,8 @@ end_with_restore_list: { DBUG_ASSERT(first_table == all_tables && first_table != 0); #ifdef WITH_WSREP - if (WSREP_CLIENT(thd) && wsrep_causal_wait(thd)) goto error; + if (WSREP_CLIENT(thd) && wsrep_causal_wait(thd)) + goto error; #endif /* WITH_WSREP */ if (check_table_access(thd, SELECT_ACL, all_tables, @@ -3790,14 +3750,14 @@ end_with_restore_list: if ((res= insert_precheck(thd, all_tables))) break; #ifdef WITH_WSREP - if (lex->sql_command == SQLCOM_INSERT_SELECT && + if (WSREP_ON && lex->sql_command == SQLCOM_INSERT_SELECT && thd->wsrep_consistency_check == CONSISTENCY_CHECK_DECLARED) { thd->wsrep_consistency_check = CONSISTENCY_CHECK_RUNNING; WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL); } +#endif /* WITH_WSREP */ -#endif /* INSERT...SELECT...ON DUPLICATE KEY UPDATE/REPLACE SELECT/ INSERT...IGNORE...SELECT can be unsafe, unless ORDER BY PRIMARY KEY @@ -4015,14 +3975,17 @@ end_with_restore_list: thd->variables.option_bits|= OPTION_KEEP_LOG; } #ifdef WITH_WSREP - for (TABLE_LIST *table= all_tables; table; table= table->next_global) + if (WSREP_ON) { - if (!lex->drop_temporary && - (!thd->is_current_stmt_binlog_format_row() || - !find_temporary_table(thd, table))) + for (TABLE_LIST *table= all_tables; table; table= table->next_global) { - WSREP_TO_ISOLATION_BEGIN(NULL, NULL, all_tables); - break; + if (!lex->drop_temporary && + (!thd->is_current_stmt_binlog_format_row() || + !find_temporary_table(thd, table))) + { + WSREP_TO_ISOLATION_BEGIN(NULL, NULL, all_tables); + break; + } } } #endif /* WITH_WSREP */ @@ -4755,17 +4718,10 @@ end_with_restore_list: able to open it (with SQLCOM_HA_OPEN) in the first place. */ unit->set_limit(select_lex); -#ifdef WITH_WSREP - { char* tmp_info= NULL; - if (WSREP(thd)) tmp_info = (char *)thd_proc_info(thd, "mysql_ha_read()"); -#endif /* WITH_WSREP */ + res= mysql_ha_read(thd, first_table, lex->ha_read_mode, lex->ident.str, lex->insert_list, lex->ha_rkey_mode, select_lex->where, unit->select_limit_cnt, unit->offset_limit_cnt); -#ifdef WITH_WSREP - if (WSREP(thd)) thd_proc_info(thd, tmp_info); - } -#endif /* WITH_WSREP */ break; case SQLCOM_BEGIN: @@ -4773,9 +4729,7 @@ end_with_restore_list: if (trans_begin(thd, lex->start_transaction_opt)) { thd->mdl_context.release_transactional_locks(); -#ifdef WITH_WSREP WSREP_DEBUG("BEGIN failed, MDL released: %lu", thd->thread_id); -#endif /* WITH_WSREP */ goto error; } my_ok(thd); @@ -4793,9 +4747,7 @@ end_with_restore_list: if (trans_commit(thd)) { thd->mdl_context.release_transactional_locks(); -#ifdef WITH_WSREP WSREP_DEBUG("COMMIT failed, MDL released: %lu", thd->thread_id); -#endif /* WITH_WSREP */ goto error; } thd->mdl_context.release_transactional_locks(); @@ -4818,19 +4770,16 @@ end_with_restore_list: thd->print_aborted_warning(3, "RELEASE"); } #ifdef WITH_WSREP - if (WSREP(thd)) { - + if (WSREP(thd)) + { if (thd->wsrep_conflict_state == NO_CONFLICT || thd->wsrep_conflict_state == REPLAYING) { my_ok(thd); } - } else { -#endif /* WITH_WSREP */ - my_ok(thd); -#ifdef WITH_WSREP - } + } else #endif /* WITH_WSREP */ + my_ok(thd); break; } case SQLCOM_ROLLBACK: @@ -4847,9 +4796,7 @@ end_with_restore_list: if (trans_rollback(thd)) { thd->mdl_context.release_transactional_locks(); -#ifdef WITH_WSREP WSREP_DEBUG("rollback failed, MDL released: %lu", thd->thread_id); -#endif /* WITH_WSREP */ goto error; } thd->mdl_context.release_transactional_locks(); @@ -4869,16 +4816,15 @@ end_with_restore_list: if (tx_release) thd->killed= KILL_CONNECTION; #ifdef WITH_WSREP - if (WSREP(thd)) { + if (WSREP(thd)) + { if (thd->wsrep_conflict_state == NO_CONFLICT) { my_ok(thd); } - } else { -#endif /* WITH_WSREP */ - my_ok(thd); -#ifdef WITH_WSREP } + else #endif /* WITH_WSREP */ + my_ok(thd); break; } case SQLCOM_RELEASE_SAVEPOINT: @@ -5394,9 +5340,7 @@ create_sp_error: if (trans_xa_commit(thd)) { thd->mdl_context.release_transactional_locks(); -#ifdef WITH_WSREP WSREP_DEBUG("XA commit failed, MDL released: %lu", thd->thread_id); -#endif /* WITH_WSREP */ goto error; } thd->mdl_context.release_transactional_locks(); @@ -5412,9 +5356,7 @@ create_sp_error: if (trans_xa_rollback(thd)) { thd->mdl_context.release_transactional_locks(); -#ifdef WITH_WSREP WSREP_DEBUG("XA rollback failed, MDL released: %lu", thd->thread_id); -#endif /* WITH_WSREP */ goto error; } thd->mdl_context.release_transactional_locks(); @@ -5764,7 +5706,8 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables) else status_var_add(thd->status_var.rows_sent, thd->get_sent_row_count()); #ifdef WITH_WSREP - if (lex->sql_command == SQLCOM_SHOW_STATUS) wsrep_free_status(thd); + if (WSREP_ON && lex->sql_command == SQLCOM_SHOW_STATUS) + wsrep_free_status(thd); #endif /* WITH_WSREP */ return res; } @@ -6610,7 +6553,8 @@ void THD::reset_for_next_command() transactions. Appliers and replayers are either processing ROW events or get autoinc variable values from Query_log_event. */ - if (WSREP(thd) && thd->wsrep_exec_mode == LOCAL_STATE) { + if (WSREP(thd) && thd->wsrep_exec_mode == LOCAL_STATE) + { if (wsrep_auto_increment_control) { if (thd->variables.auto_increment_offset != @@ -6831,7 +6775,7 @@ void mysql_init_multi_delete(LEX *lex) static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length, Parser_state *parser_state) { - bool is_autocommit= + bool is_autocommit= !thd->in_multi_stmt_transaction_mode() && thd->wsrep_conflict_state == NO_CONFLICT && !thd->wsrep_applier && @@ -7959,14 +7903,9 @@ kill_one_thread(THD *thd, longlong id, killed_state kill_signal, killed_type typ faster and do a harder kill than KILL_SYSTEM_THREAD; */ -#ifdef WITH_WSREP if (((thd->security_ctx->master_access & SUPER_ACL) || thd->security_ctx->user_matches(tmp->security_ctx)) && - !wsrep_thd_is_BF((void *)tmp, true)) -#else - if ((thd->security_ctx->master_access & SUPER_ACL) || - thd->security_ctx->user_matches(tmp->security_ctx)) -#endif /* WITH_WSREP */ + IF_WSREP(!wsrep_thd_is_BF((void *)tmp, true), 1)) { tmp->awake(kill_signal); error=0; diff --git a/sql/sql_parse.h b/sql/sql_parse.h index 773ede9edee..87f8854e050 100644 --- a/sql/sql_parse.h +++ b/sql/sql_parse.h @@ -202,22 +202,5 @@ inline bool is_supported_parser_charset(CHARSET_INFO *cs) { return MY_TEST(cs->mbminlen == 1); } -#ifdef WITH_WSREP - -#define WSREP_MYSQL_DB (char *)"mysql" -#define WSREP_TO_ISOLATION_BEGIN(db_, table_, table_list_) \ - if (WSREP(thd) && wsrep_to_isolation_begin(thd, db_, table_, table_list_)) goto error; - -#define WSREP_TO_ISOLATION_END \ - if (WSREP(thd) || (thd && thd->wsrep_exec_mode==TOTAL_ORDER)) \ - wsrep_to_isolation_end(thd); - -#else - -#define WSREP_TO_ISOLATION_BEGIN(db_, table_, table_list_) -#define WSREP_TO_ISOLATION_END - -#endif /* WITH_WSREP */ - #endif /* SQL_PARSE_INCLUDED */ diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc index ac67291fbd1..9db8b1c136a 100644 --- a/sql/sql_partition_admin.cc +++ b/sql/sql_partition_admin.cc @@ -1,4 +1,5 @@ /* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, SkySQL Ab. 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 @@ -764,18 +765,22 @@ bool Sql_cmd_alter_table_truncate_partition::execute(THD *thd) DBUG_RETURN(TRUE); #ifdef WITH_WSREP - TABLE *find_temporary_table(THD *thd, const TABLE_LIST *tl); - - if ((!thd->is_current_stmt_binlog_format_row() || - !find_temporary_table(thd, first_table)) && - wsrep_to_isolation_begin( - thd, first_table->db, first_table->table_name, NULL) - ) + if (WSREP_ON) { - WSREP_WARN("ALTER TABLE isolation failure"); - DBUG_RETURN(TRUE); + TABLE *find_temporary_table(THD *thd, const TABLE_LIST *tl); + + if ((!thd->is_current_stmt_binlog_format_row() || + !find_temporary_table(thd, first_table)) && + wsrep_to_isolation_begin( + thd, first_table->db, first_table->table_name, NULL) + ) + { + WSREP_WARN("ALTER TABLE isolation failure"); + DBUG_RETURN(TRUE); + } } #endif /* WITH_WSREP */ + if (open_tables(thd, &first_table, &table_counter, 0)) DBUG_RETURN(true); diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 3ebed0643a5..ea9748c8cb2 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -3087,21 +3087,19 @@ void plugin_thdvar_init(THD *thd) thd->variables.dynamic_variables_size= 0; thd->variables.dynamic_variables_ptr= 0; -#ifdef WITH_WSREP - if (!WSREP(thd) || !thd->wsrep_applier) { -#endif - mysql_mutex_lock(&LOCK_plugin); - thd->variables.table_plugin= + if (IF_WSREP((!WSREP(thd) || !thd->wsrep_applier),1)) + { + mysql_mutex_lock(&LOCK_plugin); + thd->variables.table_plugin= intern_plugin_lock(NULL, global_system_variables.table_plugin); - if (global_system_variables.tmp_table_plugin) - thd->variables.tmp_table_plugin= + if (global_system_variables.tmp_table_plugin) + thd->variables.tmp_table_plugin= intern_plugin_lock(NULL, global_system_variables.tmp_table_plugin); - intern_plugin_unlock(NULL, old_table_plugin); - intern_plugin_unlock(NULL, old_tmp_table_plugin); - mysql_mutex_unlock(&LOCK_plugin); -#ifdef WITH_WSREP + intern_plugin_unlock(NULL, old_table_plugin); + intern_plugin_unlock(NULL, old_tmp_table_plugin); + mysql_mutex_unlock(&LOCK_plugin); } -#endif + DBUG_VOID_RETURN; } diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 8a6de8b6693..d9365e14494 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2002, 2013, Oracle and/or its affiliates. - Copyright (c) 2008, 2013, Monty Program Ab + Copyright (c) 2008, 2014, Monty Program Ab 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 @@ -117,6 +117,7 @@ When one supplies long data for a placeholder: #include "lock.h" // MYSQL_OPEN_FORCE_SHARED_MDL #include "sql_handler.h" #include "transaction.h" // trans_rollback_implicit +#include "wsrep_mysqld.h" /** A result class used to send cursor rows using the binary protocol. @@ -3547,9 +3548,7 @@ Prepared_statement::set_parameters(String *expanded_query, return res; } -#ifdef WITH_WSREP -void wsrep_replay_transaction(THD *thd); -#endif /* WITH_WSREP */ + /** Execute a prepared statement. Re-prepare it a limited number of times if necessary. @@ -3629,20 +3628,25 @@ reexecute: thd->m_reprepare_observer= NULL; #ifdef WITH_WSREP - mysql_mutex_lock(&thd->LOCK_wsrep_thd); - switch (thd->wsrep_conflict_state) - { - case CERT_FAILURE: - WSREP_DEBUG("PS execute fail for CERT_FAILURE: thd: %ld err: %d", - thd->thread_id, thd->get_stmt_da()->sql_errno() ); - thd->wsrep_conflict_state = NO_CONFLICT; - break; - case MUST_REPLAY: - (void)wsrep_replay_transaction(thd); - default: break; + if (WSREP_ON) + { + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + switch (thd->wsrep_conflict_state) + { + case CERT_FAILURE: + WSREP_DEBUG("PS execute fail for CERT_FAILURE: thd: %ld err: %d", + thd->thread_id, thd->get_stmt_da()->sql_errno() ); + thd->wsrep_conflict_state = NO_CONFLICT; + break; + + case MUST_REPLAY: + (void)wsrep_replay_transaction(thd); + default: + break; + } + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); } - mysql_mutex_unlock(&thd->LOCK_wsrep_thd); #endif /* WITH_WSREP */ if ((sql_command_flags[lex->sql_command] & CF_REEXECUTION_FRAGILE) && diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index eaed0660e46..d8db5c55c3b 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2008, 2013, Monty Program Ab + Copyright (c) 2008, 2014, Monty Program Ab 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 @@ -2946,15 +2946,7 @@ int start_slave(THD* thd , Master_info* mi, bool net_report) err: unlock_slave_threads(mi); - -#ifdef WITH_WSREP - if (WSREP(thd)) - thd_proc_info(thd, "exit stop_slave()"); - else thd_proc_info(thd, 0); -#else /* WITH_WSREP */ - thd_proc_info(thd, 0); -#endif /* WITH_WSREP */ if (slave_errno) { diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 25c005539af..6ffb19256bf 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2972,13 +2972,9 @@ static bool show_status_array(THD *thd, const char *wild, DBUG_ASSERT(name_buffer[0] >= 'a'); DBUG_ASSERT(name_buffer[0] <= 'z'); -#ifdef WITH_WSREP - // TODO: remove once lp:1306875 has been addressed. - if (status_var && (is_wsrep_var == FALSE)) -#else - /* traditionally status variables have a first letter uppercased */ - if (status_var) -#endif /* WITH_WSREP */ + // WSREP_TODO: remove once lp:1306875 has been addressed. + if (IF_WSREP(WSREP_ON && is_wsrep_var == FALSE, 1) && + status_var) name_buffer[0]-= 'a' - 'A'; } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index e632a65b636..b86de2f6cc1 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5265,58 +5265,9 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, DBUG_ENTER("mysql_create_like_table"); #ifdef WITH_WSREP - if (WSREP(thd) && !thd->wsrep_applier) - { - TABLE *tmp_table; - bool is_tmp_table= FALSE; - - for (tmp_table= thd->temporary_tables; tmp_table; tmp_table=tmp_table->next) - { - if (!strcmp(src_table->db, tmp_table->s->db.str) && - !strcmp(src_table->table_name, tmp_table->s->table_name.str)) - { - is_tmp_table= TRUE; - break; - } - } - if (create_info->options & HA_LEX_CREATE_TMP_TABLE) - { - /* CREATE TEMPORARY TABLE LIKE must be skipped from replication */ - WSREP_DEBUG("CREATE TEMPORARY TABLE LIKE... skipped replication\n %s", - thd->query()); - } - else if (!is_tmp_table) - { - /* this is straight CREATE TABLE LIKE... eith no tmp tables */ - WSREP_TO_ISOLATION_BEGIN(table->db, table->table_name, NULL); - } - else - { - /* here we have CREATE TABLE LIKE - the temporary table definition will be needed in slaves to - enable the create to succeed - */ - TABLE_LIST tbl; - bzero((void*) &tbl, sizeof(tbl)); - tbl.db= src_table->db; - tbl.table_name= tbl.alias= src_table->table_name; - tbl.table= tmp_table; - char buf[2048]; - String query(buf, sizeof(buf), system_charset_info); - query.length(0); // Have to zero it since constructor doesn't - - (void) store_create_info(thd, &tbl, &query, NULL, TRUE, FALSE); - WSREP_DEBUG("TMP TABLE: %s", query.ptr()); - - thd->wsrep_TOI_pre_query= query.ptr(); - thd->wsrep_TOI_pre_query_len= query.length(); - - WSREP_TO_ISOLATION_BEGIN(table->db, table->table_name, NULL); - - thd->wsrep_TOI_pre_query= NULL; - thd->wsrep_TOI_pre_query_len= 0; - } - } + if (WSREP_ON && !thd->wsrep_applier && + wsrep_create_like_table(thd, table, src_table, create_info)) + goto end; #endif /* @@ -5580,14 +5531,9 @@ err: thd->query_length(), is_trans)) res= 1; } + +end: DBUG_RETURN(res); - -#ifdef WITH_WSREP - error: - thd->wsrep_TOI_pre_query= NULL; - DBUG_RETURN(TRUE); -#endif /* WITH_WSREP */ - } @@ -8119,10 +8065,6 @@ simple_rename_or_index_change(THD *thd, TABLE_LIST *table_list, : HA_EXTRA_FORCE_REOPEN; DBUG_ENTER("simple_rename_or_index_change"); -#ifdef WITH_WSREP - bool do_log_write(true); -#endif /* WITH_WSREP */ - if (keys_onoff != Alter_info::LEAVE_AS_IS) { if (wait_while_table_is_used(thd, table, extra_func)) @@ -8182,13 +8124,7 @@ simple_rename_or_index_change(THD *thd, TABLE_LIST *table_list, if (!error) { -#ifdef WITH_WSREP - if (!WSREP(thd) || do_log_write) { -#endif /* WITH_WSREP */ - error= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); -#ifdef WITH_WSREP - } -#endif /* !WITH_WSREP */ + error= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); if (!error) my_ok(thd); diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index c3188305092..268fad5d90e 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -434,14 +434,9 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) binlogged, so they share the same danger, so trust_function_creators applies to them too. */ -#ifdef WITH_WSREP - if (!trust_function_creators && - (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) && + if (!trust_function_creators && + IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), mysql_bin_log.is_open()) && !(thd->security_ctx->master_access & SUPER_ACL)) -#else - if (!trust_function_creators && mysql_bin_log.is_open() && - !(thd->security_ctx->master_access & SUPER_ACL)) -#endif /* WITH_WSREP */ { my_error(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER, MYF(0)); DBUG_RETURN(TRUE); @@ -2443,55 +2438,4 @@ bool load_table_name_for_trigger(THD *thd, DBUG_RETURN(FALSE); } -#ifdef WITH_WSREP -int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len) -{ - LEX *lex= thd->lex; - String stmt_query; - LEX_STRING definer_user; - LEX_STRING definer_host; - - if (!lex->definer) - { - if (!thd->slave_thread) - { - if (!(lex->definer= create_default_definer(thd, false))) - return 1; - } - } - - if (lex->definer) - { - /* SUID trigger. */ - - definer_user= lex->definer->user; - definer_host= lex->definer->host; - } - else - { - /* non-SUID trigger. */ - - definer_user.str= 0; - definer_user.length= 0; - - definer_host.str= 0; - definer_host.length= 0; - } - - stmt_query.append(STRING_WITH_LEN("CREATE ")); - - append_definer(thd, &stmt_query, &definer_user, &definer_host); - - LEX_STRING stmt_definition; - stmt_definition.str= (char*) thd->lex->stmt_definition_begin; - stmt_definition.length= thd->lex->stmt_definition_end - - thd->lex->stmt_definition_begin; - trim_whitespace(thd->charset(), & stmt_definition); - - stmt_query.append(stmt_definition.str, stmt_definition.length); - - return wsrep_to_buf_helper(thd, stmt_query.c_ptr(), stmt_query.length(), - buf, buf_len); -} -#endif /* WITH_WSREP */ diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc index 8046405a4b4..5e23c6ee32b 100644 --- a/sql/sql_truncate.cc +++ b/sql/sql_truncate.cc @@ -24,9 +24,7 @@ #include "sql_acl.h" // DROP_ACL #include "sql_parse.h" // check_one_table_access() #include "sql_truncate.h" -#ifdef WITH_WSREP #include "wsrep_mysqld.h" -#endif /* WITH_WSREP */ #include "sql_show.h" //append_identifier() diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 58d04674033..c458f01303d 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2011, 2013, Monty Program Ab. + Copyright (c) 2011, 2014, Monty Program Ab. 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 @@ -976,11 +976,8 @@ int mysql_update(THD *thd, */ if ((error < 0) || thd->transaction.stmt.modified_non_trans_table) { -#ifdef WITH_WSREP - if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) -#else - if (mysql_bin_log.is_open()) -#endif + if (IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), + mysql_bin_log.is_open())) { int errcode= 0; if (error < 0) @@ -2223,11 +2220,8 @@ void multi_update::abort_result_set() The query has to binlog because there's a modified non-transactional table either from the query's list or via a stored routine: bug#13270,23333 */ -#ifdef WITH_WSREP - if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) -#else - if (mysql_bin_log.is_open()) -#endif + if (IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), + mysql_bin_log.is_open())) { /* THD::killed status might not have been set ON at time of an error @@ -2496,11 +2490,8 @@ bool multi_update::send_eof() if (local_error == 0 || thd->transaction.stmt.modified_non_trans_table) { -#ifdef WITH_WSREP - if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) -#else - if (mysql_bin_log.is_open()) -#endif + if (IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), + mysql_bin_log.is_open())) { int errcode= 0; if (local_error == 0) diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 1bf972d2c55..2c2d301f622 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -3338,9 +3338,7 @@ static bool fix_autocommit(sys_var *self, THD *thd, enum_var_type type) { thd->variables.option_bits&= ~OPTION_AUTOCOMMIT; thd->mdl_context.release_transactional_locks(); -#ifdef WITH_WSREP WSREP_DEBUG("autocommit, MDL TRX lock released: %lu", thd->thread_id); -#endif /* WITH_WSREP */ return true; } /* diff --git a/sql/table.cc b/sql/table.cc index 25dd9786d94..735dbf6eedd 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -40,9 +40,7 @@ #include "sql_statistics.h" #include "discover.h" #include "mdl.h" // MDL_wait_for_graph_visitor -#ifdef WITH_WSREP #include "ha_partition.h" -#endif /* WITH_WSREP */ /* INFORMATION_SCHEMA name */ LEX_STRING INFORMATION_SCHEMA_NAME= {C_STRING_WITH_LEN("information_schema")}; diff --git a/sql/transaction.cc b/sql/transaction.cc index 72a8c47cdd8..e7d3c0afc78 100644 --- a/sql/transaction.cc +++ b/sql/transaction.cc @@ -98,7 +98,8 @@ static bool xa_trans_force_rollback(THD *thd) */ thd->transaction.xid_state.rm_error= 0; #ifdef WITH_WSREP - wsrep_register_hton(thd, TRUE); + if (WSREP_ON) + wsrep_register_hton(thd, TRUE); #endif /* WITH_WSREP */ if (ha_rollback_trans(thd, true)) { @@ -139,14 +140,16 @@ bool trans_begin(THD *thd, uint flags) { thd->variables.option_bits&= ~OPTION_TABLE_LOCK; #ifdef WITH_WSREP - wsrep_register_hton(thd, TRUE); + if (WSREP_ON) + wsrep_register_hton(thd, TRUE); #endif /* WITH_WSREP */ thd->server_status&= ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY); DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS")); res= MY_TEST(ha_commit_trans(thd, TRUE)); #ifdef WITH_WSREP - wsrep_post_commit(thd, TRUE); + if (WSREP_ON) + wsrep_post_commit(thd, TRUE); #endif /* WITH_WSREP */ } @@ -228,14 +231,16 @@ bool trans_commit(THD *thd) DBUG_RETURN(TRUE); #ifdef WITH_WSREP - wsrep_register_hton(thd, TRUE); + if (WSREP_ON) + wsrep_register_hton(thd, TRUE); #endif /* WITH_WSREP */ thd->server_status&= ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY); DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS")); res= ha_commit_trans(thd, TRUE); #ifdef WITH_WSREP - wsrep_post_commit(thd, TRUE); + if (WSREP_ON) + wsrep_post_commit(thd, TRUE); #endif /* WITH_WSREP */ /* if res is non-zero, then ha_commit_trans has rolled back the @@ -283,14 +288,16 @@ bool trans_commit_implicit(THD *thd) if (!thd->locked_tables_mode) thd->variables.option_bits&= ~OPTION_TABLE_LOCK; #ifdef WITH_WSREP - wsrep_register_hton(thd, TRUE); + if (WSREP_ON) + wsrep_register_hton(thd, TRUE); #endif /* WITH_WSREP */ thd->server_status&= ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY); DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS")); res= MY_TEST(ha_commit_trans(thd, TRUE)); #ifdef WITH_WSREP - wsrep_post_commit(thd, TRUE); + if (WSREP_ON) + wsrep_post_commit(thd, TRUE); #endif /* WITH_WSREP */ } @@ -331,7 +338,8 @@ bool trans_rollback(THD *thd) DBUG_RETURN(TRUE); #ifdef WITH_WSREP - wsrep_register_hton(thd, TRUE); + if (WSREP_ON) + wsrep_register_hton(thd, TRUE); #endif /* WITH_WSREP */ thd->server_status&= ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY); @@ -424,7 +432,8 @@ bool trans_commit_stmt(THD *thd) if (thd->transaction.stmt.ha_list) { #ifdef WITH_WSREP - wsrep_register_hton(thd, FALSE); + if (WSREP_ON) + wsrep_register_hton(thd, FALSE); #endif /* WITH_WSREP */ res= ha_commit_trans(thd, FALSE); if (! thd->in_active_multi_stmt_transaction()) @@ -432,7 +441,8 @@ bool trans_commit_stmt(THD *thd) thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation; thd->tx_read_only= thd->variables.tx_read_only; #ifdef WITH_WSREP - wsrep_post_commit(thd, FALSE); + if (WSREP_ON) + wsrep_post_commit(thd, FALSE); #endif /* WITH_WSREP */ } } @@ -475,7 +485,8 @@ bool trans_rollback_stmt(THD *thd) if (thd->transaction.stmt.ha_list) { #ifdef WITH_WSREP - wsrep_register_hton(thd, FALSE); + if (WSREP_ON) + wsrep_register_hton(thd, FALSE); #endif /* WITH_WSREP */ ha_rollback_trans(thd, FALSE); if (! thd->in_active_multi_stmt_transaction()) @@ -855,13 +866,15 @@ bool trans_xa_commit(THD *thd) else if (xa_state == XA_IDLE && thd->lex->xa_opt == XA_ONE_PHASE) { #ifdef WITH_WSREP - wsrep_register_hton(thd, TRUE); + if (WSREP_ON) + wsrep_register_hton(thd, TRUE); #endif /* WITH_WSREP */ int r= ha_commit_trans(thd, TRUE); if ((res= MY_TEST(r))) my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0)); #ifdef WITH_WSREP - wsrep_post_commit(thd, TRUE); + if (WSREP_ON) + wsrep_post_commit(thd, TRUE); #endif /* WITH_WSREP */ } else if (xa_state == XA_PREPARED && thd->lex->xa_opt == XA_NONE) @@ -882,7 +895,8 @@ bool trans_xa_commit(THD *thd) thd->variables.lock_wait_timeout)) { #ifdef WITH_WSREP - wsrep_register_hton(thd, TRUE); + if (WSREP_ON) + wsrep_register_hton(thd, TRUE); #endif /* WITH_WSREP */ ha_rollback_trans(thd, TRUE); my_error(ER_XAER_RMERR, MYF(0)); diff --git a/sql/tztime.cc b/sql/tztime.cc index 2a5a5d1681b..577474cd78f 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -2711,7 +2711,8 @@ main(int argc, char **argv) #ifdef WITH_WSREP // Replicate MyISAM DDL for this session, cf. lp:1161432 - printf("SET GLOBAL wsrep_replicate_myisam= ON;\n"); + // timezone info unfixable in XtraDB Cluster + printf("SET GLOBAL wsrep_replicate_myisam= ON;\n"); #endif /* WITH_WSREP */ if (argc == 1 && !opt_leap) diff --git a/sql/wsrep_binlog.cc b/sql/wsrep_binlog.cc index 5cb910248a2..ee8a9cb130b 100644 --- a/sql/wsrep_binlog.cc +++ b/sql/wsrep_binlog.cc @@ -15,7 +15,9 @@ #include "wsrep_binlog.h" #include "wsrep_priv.h" +#include "log.h" +extern handlerton *binlog_hton; /* Write the contents of a cache to a memory buffer. @@ -320,7 +322,6 @@ void wsrep_dump_rbr_buf(THD *thd, const void* rbr_buf, size_t buf_len) filename, errno, strerror(errno)); } } -extern handlerton *binlog_hton; /* wsrep exploits binlog's caches even if binlogging itself is not @@ -406,3 +407,8 @@ cleanup: // close file if (of) fclose(of); } + +void thd_binlog_flush_pending_rows_event(THD *thd, bool stmt_end) +{ + thd->binlog_flush_pending_rows_event(stmt_end); +} diff --git a/sql/wsrep_hton.cc b/sql/wsrep_hton.cc index 48577a9b5a1..96f1431a82f 100644 --- a/sql/wsrep_hton.cc +++ b/sql/wsrep_hton.cc @@ -539,7 +539,7 @@ static int wsrep_hton_init(void *p) wsrep_hton= (handlerton *)p; //wsrep_hton->state=opt_bin_log ? SHOW_OPTION_YES : SHOW_OPTION_NO; wsrep_hton->state= SHOW_OPTION_YES; - wsrep_hton->db_type=DB_TYPE_WSREP; + wsrep_hton->db_type=(legacy_db_type)0; wsrep_hton->savepoint_offset= sizeof(my_off_t); wsrep_hton->close_connection= wsrep_close_connection; wsrep_hton->savepoint_set= wsrep_savepoint_set; diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index a9344b0a946..a77f85cbbdb 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -1,4 +1,4 @@ -/* Copyright 2008-2013 Codership Oy +/* Copyright 2008-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 @@ -16,6 +16,13 @@ #include #include #include +#include "slave.h" +#include "rpl_mi.h" +#include "sql_repl.h" +#include "rpl_filter.h" +#include "sql_callback.h" +#include "sp_head.h" +#include "sp.h" #include "wsrep_priv.h" #include "wsrep_thd.h" #include "wsrep_sst.h" @@ -40,6 +47,13 @@ my_bool wsrep_preordered_opt= FALSE; * Begin configuration options and their default values */ +extern int wsrep_replaying; +extern ulong wsrep_running_threads; +extern ulong my_bind_addr; +extern my_bool plugins_are_initialized; +extern uint kill_cached_threads; +extern mysql_cond_t COND_thread_cache; + const char* wsrep_data_home_dir = NULL; const char* wsrep_dbug_option = ""; @@ -1292,7 +1306,7 @@ static int wsrep_TOI_begin(THD *thd, char *db_, char *table_, { thd->wsrep_exec_mode= TOTAL_ORDER; wsrep_to_isolation++; - if (buf) my_free(buf); + my_free(buf); wsrep_keys_free(&key_arr); WSREP_DEBUG("TO BEGIN: %lld, %d",(long long)wsrep_thd_trx_seqno(thd), thd->wsrep_exec_mode); @@ -1407,13 +1421,14 @@ static void wsrep_RSU_end(THD *thd) int wsrep_to_isolation_begin(THD *thd, char *db_, char *table_, const TABLE_LIST* table_list) { + int ret= 0; /* No isolation for applier or replaying threads. */ - if (thd->wsrep_exec_mode == REPL_RECV) return 0; + if (thd->wsrep_exec_mode == REPL_RECV) + return 0; - int ret= 0; mysql_mutex_lock(&thd->LOCK_wsrep_thd); if (thd->wsrep_conflict_state == MUST_ABORT) @@ -1501,8 +1516,8 @@ wsrep_grant_mdl_exception(MDL_context *requestor_ctx, ) { if (!WSREP_ON) return FALSE; - THD *request_thd = requestor_ctx->wsrep_get_thd(); - THD *granted_thd = ticket->get_ctx()->wsrep_get_thd(); + THD *request_thd = requestor_ctx->get_thd(); + THD *granted_thd = ticket->get_ctx()->get_thd(); bool ret = FALSE; mysql_mutex_lock(&request_thd->LOCK_wsrep_thd); @@ -1560,3 +1575,856 @@ wsrep_grant_mdl_exception(MDL_context *requestor_ctx, } return ret; } + + +pthread_handler_t start_wsrep_THD(void *arg) +{ + THD *thd; + rpl_sql_thread_info sql_info(NULL); + wsrep_thd_processor_fun processor= (wsrep_thd_processor_fun)arg; + + if (my_thread_init()) + { + WSREP_ERROR("Could not initialize thread"); + return(NULL); + } + + if (!(thd= new THD(true))) + { + return(NULL); + } + mysql_mutex_lock(&LOCK_thread_count); + thd->thread_id=thread_id++; + + thd->real_id=pthread_self(); // Keep purify happy + thread_count++; + thread_created++; + threads.append(thd); + + my_net_init(&thd->net,(st_vio*) 0, MYF(0)); + + DBUG_PRINT("wsrep",(("creating thread %lld"), (long long)thd->thread_id)); + thd->prior_thr_create_utime= thd->start_utime= microsecond_interval_timer(); + (void) mysql_mutex_unlock(&LOCK_thread_count); + + /* from bootstrap()... */ + thd->bootstrap=1; + thd->max_client_packet_length= thd->net.max_packet; + thd->security_ctx->master_access= ~(ulong)0; + thd->system_thread_info.rpl_sql_info= &sql_info; + + /* from handle_one_connection... */ + pthread_detach_this_thread(); + + mysql_thread_set_psi_id(thd->thread_id); + thd->thr_create_utime= microsecond_interval_timer(); + if (MYSQL_CALLBACK_ELSE(thread_scheduler, init_new_connection_thread, (), 0)) + { + close_connection(thd, ER_OUT_OF_RESOURCES); + statistic_increment(aborted_connects,&LOCK_status); + MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0)); + + return(NULL); + } + +// + /* + handle_one_connection() is normally the only way a thread would + start and would always be on the very high end of the stack , + therefore, the thread stack always starts at the address of the + first local variable of handle_one_connection, which is thd. We + need to know the start of the stack so that we could check for + stack overruns. + */ + DBUG_PRINT("wsrep", ("handle_one_connection called by thread %lld\n", + (long long)thd->thread_id)); + /* now that we've called my_thread_init(), it is safe to call DBUG_* */ + + thd->thread_stack= (char*) &thd; + if (thd->store_globals()) + { + close_connection(thd, ER_OUT_OF_RESOURCES); + statistic_increment(aborted_connects,&LOCK_status); + MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0)); + delete thd; + + return(NULL); + } + + thd->system_thread= SYSTEM_THREAD_SLAVE_SQL; + thd->security_ctx->skip_grants(); + + /* handle_one_connection() again... */ + //thd->version= refresh_version; + thd->proc_info= 0; + thd->set_command(COM_SLEEP); + thd->set_time(); + thd->init_for_queries(); + + mysql_mutex_lock(&LOCK_thread_count); + wsrep_running_threads++; + mysql_cond_broadcast(&COND_thread_count); + mysql_mutex_unlock(&LOCK_thread_count); + + processor(thd); + + close_connection(thd, 0); + + mysql_mutex_lock(&LOCK_thread_count); + wsrep_running_threads--; + WSREP_DEBUG("wsrep running threads now: %lu", wsrep_running_threads); + mysql_cond_broadcast(&COND_thread_count); + mysql_mutex_unlock(&LOCK_thread_count); + + // Note: We can't call THD destructor without crashing + // if plugins have not been initialized. However, in most of the + // cases this means that pre SE initialization SST failed and + // we are going to exit anyway. + if (plugins_are_initialized) + { + net_end(&thd->net); + MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 1)); + } + else + { + // TODO: lightweight cleanup to get rid of: + // 'Error in my_thread_global_end(): 2 threads didn't exit' + // at server shutdown + } + + my_thread_end(); + if (thread_handling > SCHEDULER_ONE_THREAD_PER_CONNECTION) + { + mysql_mutex_lock(&LOCK_thread_count); + delete thd; + thread_count--; + mysql_mutex_unlock(&LOCK_thread_count); + } + return(NULL); +} + + +/**/ +static bool abort_replicated(THD *thd) +{ + bool ret_code= false; + if (thd->wsrep_query_state== QUERY_COMMITTING) + { + if (wsrep_debug) WSREP_INFO("aborting replicated trx: %lu", thd->real_id); + + (void)wsrep_abort_thd(thd, thd, TRUE); + ret_code= true; + } + return ret_code; +} + + +/**/ +static inline bool is_client_connection(THD *thd) +{ + return (thd->wsrep_client_thread && thd->variables.wsrep_on); +} + + +static inline bool is_replaying_connection(THD *thd) +{ + bool ret; + + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + ret= (thd->wsrep_conflict_state == REPLAYING) ? true : false; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + + return ret; +} + + +static inline bool is_committing_connection(THD *thd) +{ + bool ret; + + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + ret= (thd->wsrep_query_state == QUERY_COMMITTING) ? true : false; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + + return ret; +} + + +static bool have_client_connections() +{ + THD *tmp; + + I_List_iterator it(threads); + while ((tmp=it++)) + { + DBUG_PRINT("quit",("Informing thread %ld that it's time to die", + tmp->thread_id)); + if (is_client_connection(tmp) && tmp->killed == KILL_CONNECTION) + { + (void)abort_replicated(tmp); + return true; + } + } + return false; +} + +/* + returns the number of wsrep appliers running. + However, the caller (thd parameter) is not taken in account + */ +static int have_wsrep_appliers(THD *thd) +{ + int ret= 0; + THD *tmp; + + I_List_iterator it(threads); + while ((tmp=it++)) + { + ret+= (tmp != thd && tmp->wsrep_applier); + } + return ret; +} + + +static void wsrep_close_thread(THD *thd) +{ + thd->killed= KILL_CONNECTION; + MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (thd)); + if (thd->mysys_var) + { + thd->mysys_var->abort=1; + mysql_mutex_lock(&thd->mysys_var->mutex); + if (thd->mysys_var->current_cond) + { + mysql_mutex_lock(thd->mysys_var->current_mutex); + mysql_cond_broadcast(thd->mysys_var->current_cond); + mysql_mutex_unlock(thd->mysys_var->current_mutex); + } + mysql_mutex_unlock(&thd->mysys_var->mutex); + } +} + + +static my_bool have_committing_connections() +{ + THD *tmp; + mysql_mutex_lock(&LOCK_thread_count); // For unlink from list + + I_List_iterator it(threads); + while ((tmp=it++)) + { + if (!is_client_connection(tmp)) + continue; + + if (is_committing_connection(tmp)) + { + mysql_mutex_unlock(&LOCK_thread_count); + return TRUE; + } + } + mysql_mutex_unlock(&LOCK_thread_count); + return FALSE; +} + + +int wsrep_wait_committing_connections_close(int wait_time) +{ + int sleep_time= 100; + + while (have_committing_connections() && wait_time > 0) + { + WSREP_DEBUG("wait for committing transaction to close: %d", wait_time); + my_sleep(sleep_time); + wait_time -= sleep_time; + } + if (have_committing_connections()) + { + return 1; + } + return 0; +} + + +void wsrep_close_client_connections(my_bool wait_to_end) +{ + /* + First signal all threads that it's time to die + */ + + THD *tmp; + mysql_mutex_lock(&LOCK_thread_count); // For unlink from list + + bool kill_cached_threads_saved= kill_cached_threads; + kill_cached_threads= true; // prevent future threads caching + mysql_cond_broadcast(&COND_thread_cache); // tell cached threads to die + + I_List_iterator it(threads); + while ((tmp=it++)) + { + DBUG_PRINT("quit",("Informing thread %ld that it's time to die", + tmp->thread_id)); + /* We skip slave threads & scheduler on this first loop through. */ + if (!is_client_connection(tmp)) + continue; + + if (is_replaying_connection(tmp)) + { + tmp->killed= KILL_CONNECTION; + continue; + } + + /* replicated transactions must be skipped */ + if (abort_replicated(tmp)) + continue; + + WSREP_DEBUG("closing connection %ld", tmp->thread_id); + wsrep_close_thread(tmp); + } + mysql_mutex_unlock(&LOCK_thread_count); + + if (thread_count) + sleep(2); // Give threads time to die + + mysql_mutex_lock(&LOCK_thread_count); + /* + Force remaining threads to die by closing the connection to the client + */ + + I_List_iterator it2(threads); + while ((tmp=it2++)) + { +#ifndef __bsdi__ // Bug in BSDI kernel + if (is_client_connection(tmp) && + !abort_replicated(tmp) && + !is_replaying_connection(tmp)) + { + WSREP_INFO("killing local connection: %ld",tmp->thread_id); + close_connection(tmp,0); + } +#endif + } + + DBUG_PRINT("quit",("Waiting for threads to die (count=%u)",thread_count)); + if (wsrep_debug) + WSREP_INFO("waiting for client connections to close: %u", thread_count); + + while (wait_to_end && have_client_connections()) + { + mysql_cond_wait(&COND_thread_count, &LOCK_thread_count); + DBUG_PRINT("quit",("One thread died (count=%u)", thread_count)); + } + + kill_cached_threads= kill_cached_threads_saved; + + mysql_mutex_unlock(&LOCK_thread_count); + + /* All client connection threads have now been aborted */ +} + + +void wsrep_close_applier(THD *thd) +{ + WSREP_DEBUG("closing applier %ld", thd->thread_id); + wsrep_close_thread(thd); +} + + +void wsrep_close_threads(THD *thd) +{ + THD *tmp; + mysql_mutex_lock(&LOCK_thread_count); // For unlink from list + + I_List_iterator it(threads); + while ((tmp=it++)) + { + DBUG_PRINT("quit",("Informing thread %ld that it's time to die", + tmp->thread_id)); + /* We skip slave threads & scheduler on this first loop through. */ + if (tmp->wsrep_applier && tmp != thd) + { + WSREP_DEBUG("closing wsrep thread %ld", tmp->thread_id); + wsrep_close_thread (tmp); + } + } + + mysql_mutex_unlock(&LOCK_thread_count); +} + + +void wsrep_close_applier_threads(int count) +{ + THD *tmp; + mysql_mutex_lock(&LOCK_thread_count); // For unlink from list + + I_List_iterator it(threads); + while ((tmp=it++) && count) + { + DBUG_PRINT("quit",("Informing thread %ld that it's time to die", + tmp->thread_id)); + /* We skip slave threads & scheduler on this first loop through. */ + if (tmp->wsrep_applier) + { + WSREP_DEBUG("closing wsrep applier thread %ld", tmp->thread_id); + tmp->wsrep_applier_closing= TRUE; + count--; + } + } + + mysql_mutex_unlock(&LOCK_thread_count); +} + + +void wsrep_wait_appliers_close(THD *thd) +{ + /* Wait for wsrep appliers to gracefully exit */ + mysql_mutex_lock(&LOCK_thread_count); + while (have_wsrep_appliers(thd) > 1) + // 1 is for rollbacker thread which needs to be killed explicitly. + // This gotta be fixed in a more elegant manner if we gonna have arbitrary + // number of non-applier wsrep threads. + { + if (thread_handling > SCHEDULER_ONE_THREAD_PER_CONNECTION) + { + mysql_mutex_unlock(&LOCK_thread_count); + my_sleep(100); + mysql_mutex_lock(&LOCK_thread_count); + } + else + mysql_cond_wait(&COND_thread_count,&LOCK_thread_count); + DBUG_PRINT("quit",("One applier died (count=%u)",thread_count)); + } + mysql_mutex_unlock(&LOCK_thread_count); + /* Now kill remaining wsrep threads: rollbacker */ + wsrep_close_threads (thd); + /* and wait for them to die */ + mysql_mutex_lock(&LOCK_thread_count); + while (have_wsrep_appliers(thd) > 0) + { + if (thread_handling > SCHEDULER_ONE_THREAD_PER_CONNECTION) + { + mysql_mutex_unlock(&LOCK_thread_count); + my_sleep(100); + mysql_mutex_lock(&LOCK_thread_count); + } + else + mysql_cond_wait(&COND_thread_count,&LOCK_thread_count); + DBUG_PRINT("quit",("One thread died (count=%u)",thread_count)); + } + mysql_mutex_unlock(&LOCK_thread_count); + + /* All wsrep applier threads have now been aborted. However, if this thread + is also applier, we are still running... + */ +} + + +void wsrep_kill_mysql(THD *thd) +{ + if (mysqld_server_started) + { + if (!shutdown_in_progress) + { + WSREP_INFO("starting shutdown"); + kill_mysql(); + } + } + else + { + unireg_abort(1); + } +} + + +int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len) +{ + String log_query; + sp_head *sp = thd->lex->sphead; + ulong saved_mode= thd->variables.sql_mode; + String retstr(64); + retstr.set_charset(system_charset_info); + + log_query.set_charset(system_charset_info); + + if (sp->m_type == TYPE_ENUM_FUNCTION) + { + sp_returns_type(thd, retstr, sp); + } + + if (!create_string(thd, &log_query, + sp->m_type, + (sp->m_explicit_name ? sp->m_db.str : NULL), + (sp->m_explicit_name ? sp->m_db.length : 0), + sp->m_name.str, sp->m_name.length, + sp->m_params.str, sp->m_params.length, + retstr.c_ptr(), retstr.length(), + sp->m_body.str, sp->m_body.length, + sp->m_chistics, &(thd->lex->definer->user), + &(thd->lex->definer->host), + saved_mode)) + { + WSREP_WARN("SP create string failed: %s", thd->query()); + return 1; + } + + return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(), buf, buf_len); +} + + +extern int wsrep_on(void *thd) +{ + return (int)(WSREP(((THD*)thd))); +} + + +extern "C" bool wsrep_thd_is_wsrep_on(THD *thd) +{ + return thd->variables.wsrep_on; +} + + +extern "C" bool wsrep_consistency_check(void *thd) +{ + return ((THD*)thd)->wsrep_consistency_check == CONSISTENCY_CHECK_RUNNING; +} + + +extern "C" void wsrep_thd_set_exec_mode(THD *thd, enum wsrep_exec_mode mode) +{ + thd->wsrep_exec_mode= mode; +} + + +extern "C" void wsrep_thd_set_query_state( + THD *thd, enum wsrep_query_state state) +{ + thd->wsrep_query_state= state; +} + + +extern "C" void wsrep_thd_set_conflict_state( + THD *thd, enum wsrep_conflict_state state) +{ + thd->wsrep_conflict_state= state; +} + + +extern "C" enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd) +{ + return thd->wsrep_exec_mode; +} + + +extern "C" const char *wsrep_thd_exec_mode_str(THD *thd) +{ + return + (!thd) ? "void" : + (thd->wsrep_exec_mode == LOCAL_STATE) ? "local" : + (thd->wsrep_exec_mode == REPL_RECV) ? "applier" : + (thd->wsrep_exec_mode == TOTAL_ORDER) ? "total order" : + (thd->wsrep_exec_mode == LOCAL_COMMIT) ? "local commit" : "void"; +} + + +extern "C" enum wsrep_query_state wsrep_thd_query_state(THD *thd) +{ + return thd->wsrep_query_state; +} + + +extern "C" const char *wsrep_thd_query_state_str(THD *thd) +{ + return + (!thd) ? "void" : + (thd->wsrep_query_state == QUERY_IDLE) ? "idle" : + (thd->wsrep_query_state == QUERY_EXEC) ? "executing" : + (thd->wsrep_query_state == QUERY_COMMITTING) ? "committing" : + (thd->wsrep_query_state == QUERY_EXITING) ? "exiting" : + (thd->wsrep_query_state == QUERY_ROLLINGBACK) ? "rolling back" : "void"; +} + + +extern "C" enum wsrep_conflict_state wsrep_thd_conflict_state(THD *thd) +{ + return thd->wsrep_conflict_state; +} + + +extern "C" const char *wsrep_thd_conflict_state_str(THD *thd) +{ + return + (!thd) ? "void" : + (thd->wsrep_conflict_state == NO_CONFLICT) ? "no conflict" : + (thd->wsrep_conflict_state == MUST_ABORT) ? "must abort" : + (thd->wsrep_conflict_state == ABORTING) ? "aborting" : + (thd->wsrep_conflict_state == MUST_REPLAY) ? "must replay" : + (thd->wsrep_conflict_state == REPLAYING) ? "replaying" : + (thd->wsrep_conflict_state == RETRY_AUTOCOMMIT) ? "retrying" : + (thd->wsrep_conflict_state == CERT_FAILURE) ? "cert failure" : "void"; +} + + +extern "C" wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd) +{ + return &thd->wsrep_ws_handle; +} + + +extern "C" void wsrep_thd_LOCK(THD *thd) +{ + mysql_mutex_lock(&thd->LOCK_wsrep_thd); +} + + +extern "C" void wsrep_thd_UNLOCK(THD *thd) +{ + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); +} + + +extern "C" time_t wsrep_thd_query_start(THD *thd) +{ + return thd->query_start(); +} + + +extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd) +{ + return thd->wsrep_rand; +} + + +extern "C" my_thread_id wsrep_thd_thread_id(THD *thd) +{ + return thd->thread_id; +} + + +extern "C" wsrep_seqno_t wsrep_thd_trx_seqno(THD *thd) +{ + return (thd) ? thd->wsrep_trx_meta.gtid.seqno : WSREP_SEQNO_UNDEFINED; +} + + +extern "C" query_id_t wsrep_thd_query_id(THD *thd) +{ + return thd->query_id; +} + + +extern "C" char *wsrep_thd_query(THD *thd) +{ + return (thd) ? thd->query() : NULL; +} + + +extern "C" query_id_t wsrep_thd_wsrep_last_query_id(THD *thd) +{ + return thd->wsrep_last_query_id; +} + + +extern "C" void wsrep_thd_set_wsrep_last_query_id(THD *thd, query_id_t id) +{ + thd->wsrep_last_query_id= id; +} + + +extern "C" void wsrep_thd_awake(THD *thd, my_bool signal) +{ + if (signal) + { + mysql_mutex_lock(&thd->LOCK_thd_data); + thd->awake(KILL_QUERY); + mysql_mutex_unlock(&thd->LOCK_thd_data); + } + else + { + mysql_mutex_lock(&LOCK_wsrep_replaying); + mysql_cond_broadcast(&COND_wsrep_replaying); + mysql_mutex_unlock(&LOCK_wsrep_replaying); + } +} + + +extern "C" int wsrep_thd_retry_counter(THD *thd) +{ + return(thd->wsrep_retry_counter); +} + + +extern int +wsrep_trx_order_before(void *thd1, void *thd2) +{ + if (wsrep_thd_trx_seqno((THD*)thd1) < wsrep_thd_trx_seqno((THD*)thd2)) { + WSREP_DEBUG("BF conflict, order: %lld %lld\n", + (long long)wsrep_thd_trx_seqno((THD*)thd1), + (long long)wsrep_thd_trx_seqno((THD*)thd2)); + return 1; + } + WSREP_DEBUG("waiting for BF, trx order: %lld %lld\n", + (long long)wsrep_thd_trx_seqno((THD*)thd1), + (long long)wsrep_thd_trx_seqno((THD*)thd2)); + return 0; +} + + +extern "C" int +wsrep_trx_is_aborting(void *thd_ptr) +{ + if (thd_ptr) { + if ((((THD *)thd_ptr)->wsrep_conflict_state == MUST_ABORT) || + (((THD *)thd_ptr)->wsrep_conflict_state == ABORTING)) { + return 1; + } + } + return 0; +} + + +my_bool wsrep_read_only_option(THD *thd, TABLE_LIST *all_tables) +{ + int opt_readonly_saved = opt_readonly; + ulong flag_saved = (ulong)(thd->security_ctx->master_access & SUPER_ACL); + + opt_readonly = 0; + thd->security_ctx->master_access &= ~SUPER_ACL; + + my_bool ret = !deny_updates_if_read_only_option(thd, all_tables); + + opt_readonly = opt_readonly_saved; + thd->security_ctx->master_access |= flag_saved; + + return ret; +} + + +void wsrep_copy_query(THD *thd) +{ + thd->wsrep_retry_command = thd->get_command(); + thd->wsrep_retry_query_len = thd->query_length(); + thd->wsrep_retry_query = (char *)my_malloc( + thd->wsrep_retry_query_len + 1, MYF(0)); + strncpy(thd->wsrep_retry_query, thd->query(), thd->wsrep_retry_query_len); + thd->wsrep_retry_query[thd->wsrep_retry_query_len] = '\0'; +} + + +bool wsrep_is_show_query(enum enum_sql_command command) +{ + DBUG_ASSERT(command >= 0 && command <= SQLCOM_END); + return (sql_command_flags[command] & CF_STATUS_COMMAND) != 0; +} + +bool wsrep_create_like_table(THD* thd, TABLE_LIST* table, + TABLE_LIST* src_table, + HA_CREATE_INFO *create_info) +{ + TABLE *tmp_table; + bool is_tmp_table= FALSE; + + for (tmp_table= thd->temporary_tables; tmp_table; tmp_table=tmp_table->next) + { + if (!strcmp(src_table->db, tmp_table->s->db.str) && + !strcmp(src_table->table_name, tmp_table->s->table_name.str)) + { + is_tmp_table= TRUE; + break; + } + } + if (create_info->options & HA_LEX_CREATE_TMP_TABLE) + { + + /* CREATE TEMPORARY TABLE LIKE must be skipped from replication */ + WSREP_DEBUG("CREATE TEMPORARY TABLE LIKE... skipped replication\n %s", + thd->query()); + } + else if (!is_tmp_table) + { + /* this is straight CREATE TABLE LIKE... eith no tmp tables */ + WSREP_TO_ISOLATION_BEGIN(table->db, table->table_name, NULL); + } + else + { + /* here we have CREATE TABLE LIKE + the temporary table definition will be needed in slaves to + enable the create to succeed + */ + TABLE_LIST tbl; + bzero((void*) &tbl, sizeof(tbl)); + tbl.db= src_table->db; + tbl.table_name= tbl.alias= src_table->table_name; + tbl.table= tmp_table; + char buf[2048]; + String query(buf, sizeof(buf), system_charset_info); + query.length(0); // Have to zero it since constructor doesn't + + (void) store_create_info(thd, &tbl, &query, NULL, TRUE, FALSE); + WSREP_DEBUG("TMP TABLE: %s", query.ptr()); + + thd->wsrep_TOI_pre_query= query.ptr(); + thd->wsrep_TOI_pre_query_len= query.length(); + + WSREP_TO_ISOLATION_BEGIN(table->db, table->table_name, NULL); + + thd->wsrep_TOI_pre_query= NULL; + thd->wsrep_TOI_pre_query_len= 0; + } + + return(false); + +error: + thd->wsrep_TOI_pre_query= NULL; + return (true); +} + + +int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len) +{ + LEX *lex= thd->lex; + String stmt_query; + + LEX_STRING definer_user; + LEX_STRING definer_host; + + if (!lex->definer) + { + if (!thd->slave_thread) + { + if (!(lex->definer= create_default_definer(thd, false))) + return 1; + } + } + + if (lex->definer) + { + /* SUID trigger. */ + + definer_user= lex->definer->user; + definer_host= lex->definer->host; + } + else + { + /* non-SUID trigger. */ + + definer_user.str= 0; + definer_user.length= 0; + + definer_host.str= 0; + definer_host.length= 0; + } + + stmt_query.append(STRING_WITH_LEN("CREATE ")); + + append_definer(thd, &stmt_query, &definer_user, &definer_host); + + LEX_STRING stmt_definition; + stmt_definition.str= (char*) thd->lex->stmt_definition_begin; + stmt_definition.length= thd->lex->stmt_definition_end + - thd->lex->stmt_definition_begin; + trim_whitespace(thd->charset(), & stmt_definition); + + stmt_query.append(stmt_definition.str, stmt_definition.length); + + return wsrep_to_buf_helper(thd, stmt_query.c_ptr(), stmt_query.length(), + buf, buf_len); +} diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index 796f1aac0f1..18d525d2376 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -13,14 +13,18 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef WSREP_MYSQLD_H +#include + +#if !defined(WSREP_MYSQLD_H) && defined(WITH_WSREP) #define WSREP_MYSQLD_H -#include "mysqld.h" typedef struct st_mysql_show_var SHOW_VAR; #include //#include "rpl_gtid.h" #include "../wsrep/wsrep_api.h" +#include "mdl.h" +#include "mysqld.h" +#include "sql_table.h" #define WSREP_UNDEFINED_TRX_ID ULONGLONG_MAX @@ -59,6 +63,15 @@ enum wsrep_consistency_check_mode { CONSISTENCY_CHECK_RUNNING, }; +struct wsrep_thd_shadow { + ulonglong options; + uint server_status; + enum wsrep_exec_mode wsrep_exec_mode; + Vio *vio; + ulong tx_isolation; + char *db; + size_t db_length; +}; // Global wsrep parameters extern wsrep_t* wsrep; @@ -203,12 +216,6 @@ extern wsrep_seqno_t wsrep_locked_seqno; fun("WSREP: %s", msg); \ } -#define WSREP_DEBUG(...) \ - if (wsrep_debug) WSREP_LOG(sql_print_information, ##__VA_ARGS__) -#define WSREP_INFO(...) WSREP_LOG(sql_print_information, ##__VA_ARGS__) -#define WSREP_WARN(...) WSREP_LOG(sql_print_warning, ##__VA_ARGS__) -#define WSREP_ERROR(...) WSREP_LOG(sql_print_error, ##__VA_ARGS__) - #define WSREP_LOG_CONFLICT_THD(thd, role) \ WSREP_LOG(sql_print_information, \ "%s: \n " \ @@ -279,6 +286,7 @@ extern int wsrep_to_isolation; extern rpl_sidno wsrep_sidno; #endif /* GTID_SUPPORT */ extern my_bool wsrep_preordered_opt; +extern handlerton *wsrep_hton; #ifdef HAVE_PSI_INTERFACE extern PSI_mutex_key key_LOCK_wsrep_ready; @@ -317,4 +325,37 @@ const wsrep_uuid_t* wsrep_xid_uuid(const xid_t*); wsrep_seqno_t wsrep_xid_seqno(const xid_t*); extern "C" int wsrep_is_wsrep_xid(const void* xid); +extern "C" my_thread_id wsrep_thd_thread_id(THD *thd); +extern "C" char *wsrep_thd_query(THD *thd); + +extern bool +wsrep_grant_mdl_exception(MDL_context *requestor_ctx, + MDL_ticket *ticket); +IO_CACHE * get_trans_log(THD * thd); +bool wsrep_trans_cache_is_empty(THD *thd); +void thd_binlog_flush_pending_rows_event(THD *thd, bool stmt_end); +void thd_binlog_rollback_stmt(THD * thd); +void thd_binlog_trx_reset(THD * thd); + +typedef void (*wsrep_thd_processor_fun)(THD *); +pthread_handler_t start_wsrep_THD(void *arg); +int wsrep_wait_committing_connections_close(int wait_time); +void wsrep_close_client_connections(my_bool wait_to_end); +void wsrep_close_applier(THD *thd); +void wsrep_close_applier_threads(int count); +void wsrep_wait_appliers_close(THD *thd); +void wsrep_kill_mysql(THD *thd); +void wsrep_close_threads(THD *thd); +int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len); +my_bool wsrep_read_only_option(THD *thd, TABLE_LIST *all_tables); +void wsrep_copy_query(THD *thd); +bool wsrep_is_show_query(enum enum_sql_command command); +void wsrep_replay_transaction(THD *thd); +bool wsrep_create_like_table(THD* thd, TABLE_LIST* table, + TABLE_LIST* src_table, + HA_CREATE_INFO *create_info); +int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len); + +extern my_bool deny_updates_if_read_only_option(THD *thd, + TABLE_LIST *all_tables); #endif /* WSREP_MYSQLD_H */ diff --git a/sql/wsrep_sst.h b/sql/wsrep_sst.h index 6b2b419e63a..d85fed97fca 100644 --- a/sql/wsrep_sst.h +++ b/sql/wsrep_sst.h @@ -13,7 +13,7 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef WSREP_SST_H +#if !defined(WSREP_SST_H) && defined(WITH_WSREP) #define WSREP_SST_H #include // my_bool diff --git a/sql/wsrep_thd.h b/sql/wsrep_thd.h index a7e34c35101..14fdfc97858 100644 --- a/sql/wsrep_thd.h +++ b/sql/wsrep_thd.h @@ -13,7 +13,7 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef WSREP_THD_H +#if !defined(WSREP_THD_H) && defined(WITH_WSREP) #define WSREP_THD_H #include "sql_class.h" diff --git a/sql/wsrep_var.h b/sql/wsrep_var.h index 2a5e94b6724..c62ea7781cc 100644 --- a/sql/wsrep_var.h +++ b/sql/wsrep_var.h @@ -13,7 +13,7 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef WSREP_VAR_H +#if !defined (WSREP_VAR_H) && defined(WITH_WSREP) #define WSREP_VAR_H #define WSREP_CLUSTER_NAME "my_wsrep_cluster" diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index ed562f5172d..9313a0bf232 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -17326,44 +17326,44 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, if (!thd) { DBUG_PRINT("wsrep", ("no thd for conflicting lock")); - WSREP_WARN("no THD for trx: %llu", victim_trx->id); + WSREP_WARN("no THD for trx: %lu", victim_trx->id); DBUG_RETURN(1); } if (!bf_thd) { DBUG_PRINT("wsrep", ("no BF thd for conflicting lock")); - WSREP_WARN("no BF THD for trx: %llu", (bf_trx) ? bf_trx->id : 0); + WSREP_WARN("no BF THD for trx: %lu", (bf_trx) ? bf_trx->id : 0); DBUG_RETURN(1); } WSREP_LOG_CONFLICT(bf_thd, thd, TRUE); - WSREP_DEBUG("BF kill (%lu, seqno: %lld), victim: (%lu) trx: %llu", + WSREP_DEBUG("BF kill (%lu, seqno: %lld), victim: (%lu) trx: %lu", signal, (long long)bf_seqno, wsrep_thd_thread_id(thd), victim_trx->id); - WSREP_DEBUG("Aborting query: %s", + WSREP_DEBUG("Aborting query: %s", (thd && wsrep_thd_query(thd)) ? wsrep_thd_query(thd) : "void"); wsrep_thd_LOCK(thd); if (wsrep_thd_query_state(thd) == QUERY_EXITING) { - WSREP_DEBUG("kill trx EXITING for %llu", victim_trx->id); + WSREP_DEBUG("kill trx EXITING for %lu", victim_trx->id); wsrep_thd_UNLOCK(thd); DBUG_RETURN(0); } if(wsrep_thd_exec_mode(thd) != LOCAL_STATE) { - WSREP_DEBUG("withdraw for BF trx: %llu, state: %d", + WSREP_DEBUG("withdraw for BF trx: %lu, state: %d", victim_trx->id, wsrep_thd_conflict_state(thd)); } switch (wsrep_thd_conflict_state(thd)) { - case NO_CONFLICT: + case NO_CONFLICT: wsrep_thd_set_conflict_state(thd, MUST_ABORT); break; case MUST_ABORT: - WSREP_DEBUG("victim %llu in MUST ABORT state", + WSREP_DEBUG("victim %lu in MUST ABORT state", victim_trx->id); wsrep_thd_UNLOCK(thd); wsrep_thd_awake(thd, signal); @@ -17372,7 +17372,7 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, case ABORTED: case ABORTING: // fall through default: - WSREP_DEBUG("victim %llu in state %d", + WSREP_DEBUG("victim %lu in state %d", victim_trx->id, wsrep_thd_conflict_state(thd)); wsrep_thd_UNLOCK(thd); DBUG_RETURN(0); @@ -17385,7 +17385,7 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, WSREP_DEBUG("kill query for: %ld", wsrep_thd_thread_id(thd)); - WSREP_DEBUG("kill trx QUERY_COMMITTING for %llu", + WSREP_DEBUG("kill trx QUERY_COMMITTING for %lu", victim_trx->id); if (wsrep_thd_exec_mode(thd) == REPL_RECV) { @@ -17399,7 +17399,7 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, switch (rcode) { case WSREP_WARNING: - WSREP_DEBUG("cancel commit warning: %llu", + WSREP_DEBUG("cancel commit warning: %lu", victim_trx->id); wsrep_thd_UNLOCK(thd); wsrep_thd_awake(thd, signal); @@ -17409,8 +17409,8 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, break; default: WSREP_ERROR( - "cancel commit bad exit: %d %llu", - rcode, + "cancel commit bad exit: %d %lu", + rcode, victim_trx->id); /* unable to interrupt, must abort */ /* note: kill_mysql() will block, if we cannot. @@ -17424,10 +17424,10 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, wsrep_thd_awake(thd, signal); break; case QUERY_EXEC: - /* it is possible that victim trx is itself waiting for some + /* it is possible that victim trx is itself waiting for some * other lock. We need to cancel this waiting */ - WSREP_DEBUG("kill trx QUERY_EXEC for %llu", victim_trx->id); + WSREP_DEBUG("kill trx QUERY_EXEC for %lu", victim_trx->id); victim_trx->lock.was_chosen_as_deadlock_victim= TRUE; if (victim_trx->lock.wait_lock) { @@ -17444,7 +17444,7 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, wsrep_thd_awake(thd, signal); } else { /* abort currently executing query */ - DBUG_PRINT("wsrep",("sending KILL_QUERY to: %ld", + DBUG_PRINT("wsrep",("sending KILL_QUERY to: %ld", wsrep_thd_thread_id(thd))); WSREP_DEBUG("kill query for: %ld", wsrep_thd_thread_id(thd)); @@ -17464,8 +17464,8 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, { bool skip_abort= false; wsrep_aborting_thd_t abortees; - - WSREP_DEBUG("kill IDLE for %llu", victim_trx->id); + + WSREP_DEBUG("kill IDLE for %lu", victim_trx->id); if (wsrep_thd_exec_mode(thd) == REPL_RECV) { WSREP_DEBUG("kill BF IDLE, seqno: %lld", @@ -17485,14 +17485,14 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, /* check if we have a kill message for this already */ if (abortees->aborting_thd == thd) { skip_abort = true; - WSREP_WARN("duplicate thd aborter %lu", + WSREP_WARN("duplicate thd aborter %lu", wsrep_thd_thread_id(thd)); } abortees = abortees->next; } if (!skip_abort) { wsrep_aborting_thd_t aborting = (wsrep_aborting_thd_t) - my_malloc(sizeof(struct wsrep_aborting_thd), + my_malloc(sizeof(struct wsrep_aborting_thd), MYF(0)); aborting->aborting_thd = thd; aborting->next = wsrep_aborting_thd; @@ -17512,22 +17512,24 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, break; } default: - WSREP_WARN("bad wsrep query state: %d", + WSREP_WARN("bad wsrep query state: %d", wsrep_thd_query_state(thd)); wsrep_thd_UNLOCK(thd); break; } - + DBUG_RETURN(0); } -static int -wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd, + +static +int +wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd, my_bool signal) { DBUG_ENTER("wsrep_innobase_abort_thd"); trx_t* victim_trx = thd_to_trx(victim_thd); trx_t* bf_trx = (bf_thd) ? thd_to_trx(bf_thd) : NULL; - WSREP_DEBUG("abort transaction: BF: %s victim: %s", + WSREP_DEBUG("abort transaction: BF: %s victim: %s", wsrep_thd_query(bf_thd), wsrep_thd_query(victim_thd)); From 79180d87bb43374bcecb323aca5a811c6f5cec6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Thu, 21 Aug 2014 19:35:13 +0300 Subject: [PATCH 012/153] Fix Windows compiler errors. --- sql/mdl.cc | 2 +- sql/sql_class.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/mdl.cc b/sql/mdl.cc index e5e906ae5d0..86e893db14e 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -1936,8 +1936,8 @@ MDL_lock::can_grant_lock(enum_mdl_type type_arg, else can_grant= TRUE; /* Continue loop */ - } #endif /* WITH_WSREP */ + } } if ((ticket == NULL) && IF_WSREP(wsrep_can_grant, 1)) can_grant= TRUE; diff --git a/sql/sql_class.h b/sql/sql_class.h index b2f7b459cb4..d6433d6fcf8 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2751,7 +2751,6 @@ public: Relay_log_info* wsrep_rli; rpl_group_info* wsrep_rgi; wsrep_ws_handle_t wsrep_ws_handle; - char wsrep_info[128]; /* string for dynamic proc info */ ulong wsrep_retry_counter; // of autocommit char* wsrep_retry_query; size_t wsrep_retry_query_len; @@ -2770,6 +2769,7 @@ public: #endif /* GTID_SUPPORT */ void* wsrep_apply_format; #endif /* WITH_WSREP */ + char wsrep_info[128]; /* string for dynamic proc info */ /** Internal parser state. Note that since the parser is not re-entrant, we keep only one parser From 4521a532f8baed5eda77ae70f2c6f397c8db9787 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Fri, 22 Aug 2014 08:43:57 +0300 Subject: [PATCH 013/153] Fix merge error. --- sql/event_data_objects.cc | 6 +++--- sql/events.cc | 2 +- sql/mdl.cc | 10 +++++----- sql/sql_acl.cc | 9 +++++++++ 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc index 8f00ace7124..96ac599a3b6 100644 --- a/sql/event_data_objects.cc +++ b/sql/event_data_objects.cc @@ -1473,7 +1473,8 @@ end: thd->tx_read_only= false; #ifdef WITH_WSREP - if (WSREP(thd)) { + if (WSREP(thd)) + { // sql_print_information("sizeof(LEX) = %d", sizeof(struct LEX)); // sizeof(LEX) = 4512, so it's relatively safe to allocate it on stack. LEX *old_lex= thd->lex, new_lex; @@ -1486,10 +1487,9 @@ end: ret= Events::drop_event(thd, dbname, name, FALSE); -#ifdef WITH_WSREP WSREP_TO_ISOLATION_END; + error: -#endif thd->tx_read_only= save_tx_read_only; thd->security_ctx->master_access= saved_master_access; } diff --git a/sql/events.cc b/sql/events.cc index 5a5a8893f5e..725a7613e69 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -1131,7 +1131,7 @@ Events::load_events_from_db(THD *thd) #ifdef WITH_WSREP // when SST from master node who initials event, the event status is ENABLED // this is problematic because there are two nodes with same events and both enabled. - if (et->originator != thd->variables.server_id) + if (WSREP(thd) && et->originator != thd->variables.server_id) { store_record(table, record[1]); table->field[ET_FIELD_STATUS]-> diff --git a/sql/mdl.cc b/sql/mdl.cc index 86e893db14e..07130b4d002 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -1910,21 +1910,19 @@ MDL_lock::can_grant_lock(enum_mdl_type type_arg, if (ticket->get_ctx() != requestor_ctx && ticket->is_incompatible_when_granted(type_arg)) { - if (IF_WSREP(!WSREP_ON, 0)) - break; #ifdef WITH_WSREP if (wsrep_thd_is_BF((void *)(requestor_ctx->get_thd()),false) && key.mdl_namespace() == MDL_key::GLOBAL) { WSREP_DEBUG("global lock granted for BF: %lu %s", - wsrep_thd_thread_id(requestor_ctx->get_thd()), + wsrep_thd_thread_id(requestor_ctx->get_thd()), wsrep_thd_query(requestor_ctx->get_thd())); can_grant = true; } else if (!wsrep_grant_mdl_exception(requestor_ctx, ticket)) { wsrep_can_grant= FALSE; - if (wsrep_log_conflicts) + if (wsrep_log_conflicts) { MDL_lock * lock = ticket->get_lock(); WSREP_INFO( @@ -1936,11 +1934,13 @@ MDL_lock::can_grant_lock(enum_mdl_type type_arg, else can_grant= TRUE; /* Continue loop */ +#else + break; #endif /* WITH_WSREP */ } } if ((ticket == NULL) && IF_WSREP(wsrep_can_grant, 1)) - can_grant= TRUE; + can_grant= TRUE; /* Incompatible locks are our own. */ } } #ifdef WITH_WSREP diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index b55b89265c4..e67a019d1f7 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2727,6 +2727,15 @@ bool change_password(THD *thd, const char *host, const char *user, } end: close_mysql_tables(thd); +#ifdef WITH_WSREP + if (WSREP(thd) && !thd->wsrep_applier) + { + WSREP_TO_ISOLATION_END; + + thd->query_string = query_save; + thd->wsrep_exec_mode = LOCAL_STATE; + } +#endif /* WITH_WSREP */ thd->restore_stmt_binlog_format(save_binlog_format); DBUG_RETURN(result); From 62f40f49ca0871af8f4b070a1283deaff89bde41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Fri, 22 Aug 2014 21:59:56 +0300 Subject: [PATCH 014/153] Fix merge errors. --- sql/handler.cc | 9 +++++---- sql/log.cc | 3 +-- sql/log_event.h | 1 - sql/mysqld.cc | 6 +++--- sql/sql_class.cc | 28 ++++++++++++++-------------- sql/sql_show.cc | 2 +- 6 files changed, 24 insertions(+), 25 deletions(-) diff --git a/sql/handler.cc b/sql/handler.cc index 2bc6858df48..e8c3a823a41 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3136,7 +3136,7 @@ int handler::update_auto_increment() variables->auto_increment_increment); auto_inc_intervals_count++; /* Row-based replication does not need to store intervals in binlog */ - if (IF_WSREP((WSREP(thd) && (wsrep_emulate_bin_log || mysql_bin_log.is_open())), mysql_bin_log.is_open()) + if (IF_WSREP(((WSREP(thd) && wsrep_emulate_bin_log ) || mysql_bin_log.is_open()), mysql_bin_log.is_open()) && !thd->is_current_stmt_binlog_format_row()) thd->auto_inc_intervals_in_cur_stmt_for_binlog. append(auto_inc_interval_for_cur_row.minimum(), @@ -5760,8 +5760,9 @@ static bool check_table_binlog_row_based(THD *thd, TABLE *table) table->s->cached_row_logging_check && (thd->variables.option_bits & OPTION_BIN_LOG) && /* applier and replayer should not binlog */ - (IF_WSREP((WSREP_EMULATE_BINLOG(thd) && (thd->wsrep_exec_mode != REPL_RECV)),0) || - mysql_bin_log.is_open())); + (IF_WSREP((WSREP_EMULATE_BINLOG(thd) && + (thd->wsrep_exec_mode != REPL_RECV)) || + mysql_bin_log.is_open(), mysql_bin_log.is_open()))); } @@ -5863,7 +5864,7 @@ static int binlog_log_row(TABLE* table, #ifdef WITH_WSREP /* only InnoDB tables will be replicated through binlog emulation */ - if (WSREP_ON && WSREP_EMULATE_BINLOG(thd) && + if (WSREP_EMULATE_BINLOG(thd) && table->file->partition_ht()->db_type != DB_TYPE_INNODB) return 0; #endif /* WITH_WSREP */ diff --git a/sql/log.cc b/sql/log.cc index 1901efbb6bc..371f9c06cce 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -5829,8 +5829,7 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate) could have changed since. */ /* applier and replayer can skip writing binlog events */ - if (IF_WSREP((WSREP_EMULATE_BINLOG(thd) && (thd->wsrep_exec_mode != REPL_RECV)), 0) || - likely(is_open())) + if (IF_WSREP((WSREP_EMULATE_BINLOG(thd) && (thd->wsrep_exec_mode != REPL_RECV)) || is_open(), likely(is_open()))) { my_off_t UNINIT_VAR(my_org_b_tell); #ifdef HAVE_REPLICATION diff --git a/sql/log_event.h b/sql/log_event.h index 6d0281bd790..212215d97b6 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -1344,7 +1344,6 @@ public: THD_STAGE_INFO(thd, stage_apply_event); res= do_apply_event(rgi); THD_STAGE_INFO(thd, stage_after_apply_event); - res= 0; return res; } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 1288f2c2fc7..97e9cff3b79 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1953,7 +1953,7 @@ static void __cdecl kill_server(int sig_ptr) close_connections(); #ifdef WITH_WSREP - if (WSREP_ON && wsrep_inited == 1) + if (wsrep_inited == 1) wsrep_deinit(true); #endif @@ -2754,7 +2754,7 @@ static void network_init(void) if (mysql_socket_listen(unix_sock,(int) back_log) < 0) sql_print_warning("listen() on Unix socket failed with error %d", socket_errno); -#if defined(WITH_WSREP) && defined(HAVE_FCNTL) +#if defined(WITH_WSREP) && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) if (WSREP_ON) (void) fcntl(mysql_socket_getfd(unix_sock), F_SETFD, FD_CLOEXEC); #endif /* WITH_WSREP */ @@ -2837,7 +2837,7 @@ void dec_connection_count(THD *thd) Do not decrement when its wsrep system thread. wsrep_applier is set for applier as well as rollbacker threads. */ - if (!thd->wsrep_applier) + if (thd->wsrep_applier) return; #endif /* WITH_WSREP */ diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 1f0c19538b2..443da8557ad 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1951,7 +1951,7 @@ bool THD::notify_shared_lock(MDL_context_owner *ctx_in_use, { signalled|= mysql_lock_abort_for_thread(this, thd_table); #if WITH_WSREP - if (WSREP_ON && this && WSREP(this) && wsrep_thd_is_BF((void *)this, FALSE)) + if (this && WSREP(this) && wsrep_thd_is_BF((void *)this, FALSE)) { WSREP_DEBUG("remove_table_from_cache: %llu", (unsigned long long) this->real_id); @@ -2141,7 +2141,7 @@ void THD::cleanup_after_query() table_map_for_update= 0; m_binlog_invoker= INVOKER_NONE; #ifdef WITH_WSREP - if (WSREP_ON && TOTAL_ORDER == wsrep_exec_mode) + if (TOTAL_ORDER == wsrep_exec_mode) { wsrep_exec_mode = LOCAL_STATE; } @@ -2569,7 +2569,7 @@ bool select_send::send_result_set_metadata(List &list, uint flags) { bool res; #ifdef WITH_WSREP - if (WSREP_ON && WSREP(thd) && thd->wsrep_retry_query) + if (WSREP(thd) && thd->wsrep_retry_query) { WSREP_DEBUG("skipping select metadata"); return FALSE; @@ -4320,9 +4320,9 @@ extern "C" int thd_non_transactional_update(const MYSQL_THD thd) extern "C" int thd_binlog_format(const MYSQL_THD thd) { - if (IF_WSREP(((WSREP(thd) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()), - mysql_bin_log.is_open()) && - thd->variables.option_bits & OPTION_BIN_LOG) + if (IF_WSREP(((WSREP(thd) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()), + mysql_bin_log.is_open()) && + thd->variables.option_bits & OPTION_BIN_LOG) return (int) WSREP_FORMAT(thd->variables.binlog_format); else return BINLOG_FORMAT_UNSPEC; @@ -5309,7 +5309,7 @@ int THD::decide_logging_format(TABLE_LIST *tables) 5. Error: Cannot modify table that uses a storage engine limited to row-logging when binlog_format = STATEMENT */ - if (IF_WSREP(WSREP_ON && (!WSREP(this) || wsrep_exec_mode == LOCAL_STATE),1)) + if (IF_WSREP((!WSREP(this) || wsrep_exec_mode == LOCAL_STATE),1)) { my_error((error= ER_BINLOG_STMT_MODE_AND_ROW_ENGINE), MYF(0), ""); } @@ -5663,7 +5663,7 @@ int THD::binlog_write_row(TABLE* table, bool is_trans, { DBUG_ASSERT(is_current_stmt_binlog_format_row() && - IF_WSREP(((WSREP_ON && WSREP(this) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()), + IF_WSREP(((WSREP(this) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()), mysql_bin_log.is_open())); /* Pack records into format for transfer. We are allocating more @@ -5698,7 +5698,7 @@ int THD::binlog_update_row(TABLE* table, bool is_trans, const uchar *after_record) { DBUG_ASSERT(is_current_stmt_binlog_format_row() && - IF_WSREP(((WSREP_ON && WSREP(this) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()), + IF_WSREP(((WSREP(this) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()), mysql_bin_log.is_open())); size_t const before_maxlen = max_row_length(table, before_record); @@ -5749,7 +5749,7 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans, uchar const *record) { DBUG_ASSERT(is_current_stmt_binlog_format_row() && - IF_WSREP(((WSREP_ON && WSREP(this) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()), + IF_WSREP(((WSREP(this) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()), mysql_bin_log.is_open())); /* @@ -5785,7 +5785,7 @@ int THD::binlog_remove_pending_rows_event(bool clear_maps, { DBUG_ENTER("THD::binlog_remove_pending_rows_event"); - IF_WSREP(WSREP_ON && !(WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open()), + IF_WSREP(!(WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open()), !mysql_bin_log.is_open()); DBUG_RETURN(0); @@ -5809,8 +5809,8 @@ int THD::binlog_flush_pending_rows_event(bool stmt_end, bool is_transactional) mode: it might be the case that we left row-based mode before flushing anything (e.g., if we have explicitly locked tables). */ - IF_WSREP(WSREP_ON && !(WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open()), - !mysql_bin_log.is_open()); + if(IF_WSREP(!(WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open()), + !mysql_bin_log.is_open())) DBUG_RETURN(0); /* Ensure that all events in a GTID group are in the same cache */ @@ -6064,7 +6064,7 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg, show_query_type(qtype), (int) query_len, query_arg)); DBUG_ASSERT(query_arg && - IF_WSREP(WSREP_ON && (WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open()), + IF_WSREP((WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open()), mysql_bin_log.is_open())); /* If this is withing a BEGIN ... COMMIT group, don't log it */ diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 6ffb19256bf..bb8ae16189a 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2973,7 +2973,7 @@ static bool show_status_array(THD *thd, const char *wild, DBUG_ASSERT(name_buffer[0] <= 'z'); // WSREP_TODO: remove once lp:1306875 has been addressed. - if (IF_WSREP(WSREP_ON && is_wsrep_var == FALSE, 1) && + if (IF_WSREP(is_wsrep_var == FALSE, 1) && status_var) name_buffer[0]-= 'a' - 'A'; } From 378878e1e929982a829aba27470e4b153cf7970b Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Sun, 24 Aug 2014 12:36:51 +0400 Subject: [PATCH 015/153] MDEV-6634: Wrong estimates for ref(const) and key IS NULL predicate IS [NOT] NULL predicate is sargable within an outer join. Range analysis only uses predicates from ON expressions, which have regular semantics (without null-complemented rows, etc). There is no reason not use IS [NOT] NULL predicates. --- mysql-test/r/join_outer.result | 28 ++++++++++++++++++++++++++++ mysql-test/t/join_outer.test | 24 ++++++++++++++++++++++++ sql/opt_range.cc | 11 +++++++++-- 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index e303c288552..c4770182598 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -2222,4 +2222,32 @@ id select_type table type possible_keys key key_len ref rows filtered Extra Warnings: Note 1003 select `test`.`t1`.`i1` AS `i1`,`test`.`t2`.`i2` AS `i2`,`test`.`t3`.`i3` AS `i3`,`test`.`t3`.`d3` AS `d3` from `test`.`t1` left join (`test`.`t2` join `test`.`t3`) on(((`test`.`t2`.`i2` = `test`.`t1`.`i1`) and (`test`.`t3`.`i3` = `test`.`t1`.`i1`))) where ((`test`.`t3`.`d3` = 0) or isnull(`test`.`t3`.`d3`)) DROP TABLE t1,t2,t3; +# +# MDEV-6634: Wrong estimates for ref(const) and key IS NULL predicate +# +create table t1(a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2 (a int, b int, c int, key(b), key(c)); +insert into t2 select +@a:=A.a + 10*B.a+100*C.a, +IF(@a<900, NULL, @a), +IF(@a<500, NULL, @a) +from t1 A, t1 B, t1 C; +delete from t1 where a=0; +# Check that there are different #rows of NULLs for b and c, both !=10: +explain select * from t2 force index (b) where b is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ref b b 5 const 780 Using index condition +explain select * from t2 force index (c) where c is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ref c c 5 const 393 Using index condition +explain select * from t1 left join t2 on t2.b is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 9 +1 SIMPLE t2 ref b b 5 const 780 Using where +explain select * from t1 left join t2 on t2.c is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 9 +1 SIMPLE t2 ref c c 5 const 393 Using where +drop table t1,t2; SET optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index 7a70c413e8d..8f4554e69b4 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -1777,4 +1777,28 @@ SELECT * FROM t1 LEFT JOIN t2 LEFT JOIN t3 ON i2 = i3 ON i1 = i3 DROP TABLE t1,t2,t3; +--echo # +--echo # MDEV-6634: Wrong estimates for ref(const) and key IS NULL predicate +--echo # +create table t1(a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2 (a int, b int, c int, key(b), key(c)); + +insert into t2 select + @a:=A.a + 10*B.a+100*C.a, + IF(@a<900, NULL, @a), + IF(@a<500, NULL, @a) +from t1 A, t1 B, t1 C; + +delete from t1 where a=0; + +--echo # Check that there are different #rows of NULLs for b and c, both !=10: +explain select * from t2 force index (b) where b is null; +explain select * from t2 force index (c) where c is null; + +explain select * from t1 left join t2 on t2.b is null; +explain select * from t1 left join t2 on t2.c is null; + +drop table t1,t2; + SET optimizer_switch=@save_optimizer_switch; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index fc2aa75e604..2616e044025 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -8132,8 +8132,15 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, param->thd->mem_root= param->old_root; if (!value) // IS NULL or IS NOT NULL { - if (field->table->maybe_null) // Can't use a key on this - goto end; + /* + No check for field->table->maybe_null. It's perfecly fine to use range + access for cases like + + SELECT * FROM t1 LEFT JOIN t2 ON t2.key IS [NOT] NULL + + ON expression is evaluated before considering NULL-complemented rows, so + IS [NOT] NULL has regular semantics. + */ if (!maybe_null) // Not null field { if (type == Item_func::ISNULL_FUNC) From fe4f46727616a6db2cead63a03f2dcb81dfce1f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Tue, 26 Aug 2014 12:32:21 +0300 Subject: [PATCH 016/153] Merge lp:maria/maria-10.0-galera revisions 3867..3869 and 3871..3879. --- client/client_priv.h | 2 - client/mysqldump.c | 24 +- cmake/wsrep.cmake | 4 +- .../include/have_innodb_disallow_writes.inc | 6 + mysql-test/include/have_wsrep.inc | 2 +- mysql-test/include/write_result_to_file.inc | 3 +- mysql-test/r/mysqld--help.result | 10 +- .../suite/galera/r/galera_sst_mode.result | 24 ++ .../suite/galera/t/galera_sst_mode.test | 43 ++++ .../sys_vars/r/wsrep_sync_wait_basic.result | 56 +++++ .../sys_vars/t/wsrep_sync_wait_basic.test | 47 ++++ .../wsrep/r/innodb_load_xa_with_wsrep.result | 19 ++ .../wsrep/t/innodb_load_xa_with_wsrep.opt | 1 + .../wsrep/t/innodb_load_xa_with_wsrep.test | 19 ++ sql/event_data_objects.cc | 9 +- sql/sql_admin.cc | 1 + sql/sql_class.h | 1 + sql/sql_parse.cc | 67 ++++- sql/sys_vars.cc | 19 +- sql/transaction.cc | 2 +- sql/wsrep_mysqld.cc | 24 +- sql/wsrep_mysqld.h | 11 +- sql/wsrep_thd.cc | 34 ++- sql/wsrep_thd.h | 2 + sql/wsrep_var.cc | 24 +- sql/wsrep_var.h | 3 +- storage/innobase/handler/ha_innodb.cc | 123 ++++++--- storage/innobase/include/ha_prototypes.h | 1 + storage/innobase/include/hash0hash.h | 27 ++ storage/innobase/lock/lock0lock.cc | 233 ++++++++++------- storage/innobase/row/row0upd.cc | 21 +- storage/xtradb/handler/ha_innodb.cc | 128 +++++++--- storage/xtradb/include/ha_prototypes.h | 1 + storage/xtradb/include/hash0hash.h | 27 ++ storage/xtradb/lock/lock0lock.cc | 234 +++++++++++------- storage/xtradb/row/row0upd.cc | 21 +- support-files/mysql.server.sh | 5 +- 37 files changed, 931 insertions(+), 347 deletions(-) create mode 100644 mysql-test/include/have_innodb_disallow_writes.inc create mode 100644 mysql-test/suite/galera/r/galera_sst_mode.result create mode 100644 mysql-test/suite/galera/t/galera_sst_mode.test create mode 100644 mysql-test/suite/sys_vars/r/wsrep_sync_wait_basic.result create mode 100644 mysql-test/suite/sys_vars/t/wsrep_sync_wait_basic.test create mode 100644 mysql-test/suite/wsrep/r/innodb_load_xa_with_wsrep.result create mode 100644 mysql-test/suite/wsrep/t/innodb_load_xa_with_wsrep.opt create mode 100644 mysql-test/suite/wsrep/t/innodb_load_xa_with_wsrep.test diff --git a/client/client_priv.h b/client/client_priv.h index dddf934e509..ef93818829e 100644 --- a/client/client_priv.h +++ b/client/client_priv.h @@ -92,9 +92,7 @@ enum options_client OPT_REPORT_PROGRESS, OPT_SKIP_ANNOTATE_ROWS_EVENTS, OPT_SSL_CRL, OPT_SSL_CRLPATH, -#ifdef WITH_WSREP OPT_GALERA_SST_MODE, -#endif OPT_MAX_CLIENT_OPTION /* should be always the last */ }; diff --git a/client/mysqldump.c b/client/mysqldump.c index 3485f9cbd47..eba5bd93671 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -111,9 +111,7 @@ static my_bool verbose= 0, opt_no_create_info= 0, opt_no_data= 0, opt_slave_apply= 0, opt_include_master_host_port= 0, opt_events= 0, opt_comments_used= 0, -#ifdef WITH_WSREP opt_galera_sst_mode= 0, -#endif opt_alltspcs=0, opt_notspcs= 0; static my_bool insert_pat_inited= 0, debug_info_flag= 0, debug_check_flag= 0; static ulong opt_max_allowed_packet, opt_net_buffer_length; @@ -349,14 +347,14 @@ static struct my_option my_long_options[] = {"force", 'f', "Continue even if we get an SQL error.", &ignore_errors, &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, -#ifdef WITH_WSREP - {"galera-sst-mode", OPT_GALERA_SST_MODE, "This mode is normally used " - "in mysqldump snapshot-state transfer in a Galera cluster. If enabled, " - "mysqldump additionally emits statements to turn off binary logging and " - "set global gtid_binlog_state with the current value.", + {"galera-sst-mode", OPT_GALERA_SST_MODE, + "This mode should normally be used in mysqldump snapshot state transfer " + "(SST) in a Galera cluster. If enabled, mysqldump additionally dumps " + "commands to turn off binary logging and SET global gtid_binlog_state " + "with the current value. Note: RESET MASTER needs to be executed on the " + "server receiving the resulting dump.", &opt_galera_sst_mode, &opt_galera_sst_mode, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, -#endif {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"hex-blob", OPT_HEXBLOB, "Dump binary strings (BINARY, " @@ -4810,13 +4808,12 @@ static int dump_selected_tables(char *db, char **table_names, int tables) } /* dump_selected_tables */ -#ifdef WITH_WSREP /** - Additionally emit the following statements : + Add the following statements to the generated dump: a) SET @@session.sql_log_bin=OFF; b) SET @@global.gtid_binlog_state='[N-N-N,...]' */ -static int wsrep_add_sst_mode_cmds(MYSQL *mysql) { +static int wsrep_set_sst_cmds(MYSQL *mysql) { MYSQL_RES *res; MYSQL_ROW row; @@ -4846,7 +4843,6 @@ static int wsrep_add_sst_mode_cmds(MYSQL *mysql) { mysql_free_result(res); return 0; } -#endif static int do_show_master_status(MYSQL *mysql_con, int consistent_binlog_pos) { @@ -5793,10 +5789,8 @@ int main(int argc, char **argv) if (opt_slave_apply && add_stop_slave()) goto err; -#ifdef WITH_WSREP - if (opt_galera_sst_mode && wsrep_add_sst_mode_cmds(mysql)) + if (opt_galera_sst_mode && wsrep_set_sst_cmds(mysql)) goto err; -#endif if (opt_master_data && do_show_master_status(mysql, consistent_binlog_pos)) goto err; diff --git a/cmake/wsrep.cmake b/cmake/wsrep.cmake index 349c8ace9a8..7dc797e9a05 100644 --- a/cmake/wsrep.cmake +++ b/cmake/wsrep.cmake @@ -22,8 +22,8 @@ SET(WSREP_PATCH_VERSION "10") # MariaDB addition: Revision number of the last revision merged from # codership branch visible in @@visible_comment. -# Branch : codership-mysql/5.5 -SET(WSREP_PATCH_REVNO "4002") # Should be updated on every merge. +# Branch : codership-mysql/5.6 +SET(WSREP_PATCH_REVNO "4123") # Should be updated on every merge. # MariaDB addition: Revision number of the last revision merged from # Branch : lp:maria/maria-10.0-galera diff --git a/mysql-test/include/have_innodb_disallow_writes.inc b/mysql-test/include/have_innodb_disallow_writes.inc new file mode 100644 index 00000000000..83b516b7a34 --- /dev/null +++ b/mysql-test/include/have_innodb_disallow_writes.inc @@ -0,0 +1,6 @@ +--source include/have_innodb.inc + +if (`SELECT COUNT(*) = 0 from INFORMATION_SCHEMA.GLOBAL_VARIABLES + WHERE VARIABLE_NAME = 'INNODB_DISALLOW_WRITES'`) { + --skip Test requires 'innodb_disallow_writes' +} diff --git a/mysql-test/include/have_wsrep.inc b/mysql-test/include/have_wsrep.inc index a3ceae41d40..52220edf481 100644 --- a/mysql-test/include/have_wsrep.inc +++ b/mysql-test/include/have_wsrep.inc @@ -3,6 +3,6 @@ if (`SELECT COUNT(*)=0 FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = 'wsrep' AND PLUGIN_STATUS='ACTIVE'`) { - --skip Test required wsrep plugin. + --skip Test requires wsrep plugin. } diff --git a/mysql-test/include/write_result_to_file.inc b/mysql-test/include/write_result_to_file.inc index 3e2ddf48957..db5d546750c 100644 --- a/mysql-test/include/write_result_to_file.inc +++ b/mysql-test/include/write_result_to_file.inc @@ -33,7 +33,8 @@ --let _WRTF_SERVER_NUMBER= $server_number if (!$server_number) { - --let _WRTF_SERVER_NUMBER= `SELECT 1 + @@PORT - $MASTER_MYPORT` + # Note: 2 extra ports are reserved per server for galera use. + --let _WRTF_SERVER_NUMBER= `SELECT 1 + FLOOR((@@PORT - $MASTER_MYPORT) / 3)` } --let $_write_result_msg= [server=$_WRTF_SERVER_NUMBER] diff --git a/mysql-test/r/mysqld--help.result b/mysql-test/r/mysqld--help.result index 3dd58891455..6953a05fd5c 100644 --- a/mysql-test/r/mysqld--help.result +++ b/mysql-test/r/mysqld--help.result @@ -1072,8 +1072,8 @@ The following options may be given as the first argument: variables (Defaults to on; use --skip-wsrep-auto-increment-control to disable.) --wsrep-causal-reads - Enable "strictly synchronous" semantics for read - operations + (DEPRECATED) Setting this variable is equivalent to + setting wsrep_sync_wait READ flag --wsrep-certify-nonPK Certify tables with no primary key (Defaults to on; use --skip-wsrep-certify-nonPK to disable.) @@ -1147,6 +1147,11 @@ The following options may be given as the first argument: Address where node is waiting for SST contact --wsrep-start-position=name global transaction position to start from + --wsrep-sync-wait[=#] + Ensure "synchronous" read view before executing an + operation of the type specified by bitmask: 1 - + READ(includes SELECT, SHOW and BEGIN/START TRANSACTION); + 2 - UPDATE and DELETE; 4 - INSERT and REPLACE Variables (--variable-name=value) allow-suspicious-udfs FALSE @@ -1483,6 +1488,7 @@ wsrep-sst-donor-rejects-queries FALSE wsrep-sst-method rsync wsrep-sst-receive-address AUTO wsrep-start-position 00000000-0000-0000-0000-000000000000:-1 +wsrep-sync-wait 0 To see what values a running MySQL server is using, type 'mysqladmin variables' instead of 'mysqld --verbose --help'. diff --git a/mysql-test/suite/galera/r/galera_sst_mode.result b/mysql-test/suite/galera/r/galera_sst_mode.result new file mode 100644 index 00000000000..ea25b322449 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_sst_mode.result @@ -0,0 +1,24 @@ +# +# Test for mysqldump's galera-sst-mode option +# +# +# MDEV-6490: mysqldump unknown option --galera-sst-mode +# +CREATE DATABASE bug6490; +USE bug6490; +CREATE TABLE t1(c1 INT); +INSERT INTO t1 values (1); +INSERT INTO t1 values (2); +# Save the current gtid_binlog_state. +# Take a dump of bug6490 database +DROP TABLE t1; +# Load the dump +RESET MASTER; +SELECT * from t1; +c1 +1 +2 +# Compare the two gtid_binlog_state's +# Cleanup +DROP DATABASE bug6490; +# End of test diff --git a/mysql-test/suite/galera/t/galera_sst_mode.test b/mysql-test/suite/galera/t/galera_sst_mode.test new file mode 100644 index 00000000000..dd8f9531c9d --- /dev/null +++ b/mysql-test/suite/galera/t/galera_sst_mode.test @@ -0,0 +1,43 @@ +# Embedded server doesn't support external clients +--source include/not_embedded.inc +# Binlog is required +--source include/have_log_bin.inc + +--echo # +--echo # Test for mysqldump's galera-sst-mode option +--echo # + +--echo # +--echo # MDEV-6490: mysqldump unknown option --galera-sst-mode +--echo # +CREATE DATABASE bug6490; +USE bug6490; +CREATE TABLE t1(c1 INT); +INSERT INTO t1 values (1); +INSERT INTO t1 values (2); + +--echo # Save the current gtid_binlog_state. +--let $before= `SELECT @@global.gtid_binlog_state` + +--echo # Take a dump of bug6490 database +--exec $MYSQL_DUMP --galera-sst-mode bug6490 > $MYSQLTEST_VARDIR/tmp/bug6490.sql +DROP TABLE t1; + +--echo # Load the dump +RESET MASTER; +--exec $MYSQL -uroot bug6490 < $MYSQLTEST_VARDIR/tmp/bug6490.sql + +SELECT * from t1; + +--echo # Compare the two gtid_binlog_state's +--let $after= `SELECT @@global.gtid_binlog_state` +if (`SELECT STRCMP($before, $after)`) +{ + --die ERROR: The two gtid_binlog_state's did not match. +} + +--echo # Cleanup +--remove_file $MYSQLTEST_VARDIR/tmp/bug6490.sql +DROP DATABASE bug6490; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_sync_wait_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sync_wait_basic.result new file mode 100644 index 00000000000..1e7b9364570 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_sync_wait_basic.result @@ -0,0 +1,56 @@ +# +# wsrep_sync_wait +# +# save the initial values +SET @wsrep_sync_wait_global_saved = @@global.wsrep_sync_wait; +SET @wsrep_sync_wait_session_saved = @@session.wsrep_sync_wait; +# default +SELECT @@global.wsrep_sync_wait; +@@global.wsrep_sync_wait +0 +SELECT @@session.wsrep_sync_wait; +@@session.wsrep_sync_wait +0 + +# scope and valid values +SET @@global.wsrep_sync_wait=0; +SELECT @@global.wsrep_sync_wait; +@@global.wsrep_sync_wait +0 +SET @@global.wsrep_sync_wait=7; +SELECT @@global.wsrep_sync_wait; +@@global.wsrep_sync_wait +7 +SET @@session.wsrep_sync_wait=0; +SELECT @@session.wsrep_sync_wait; +@@session.wsrep_sync_wait +0 +SET @@session.wsrep_sync_wait=7; +SELECT @@session.wsrep_sync_wait; +@@session.wsrep_sync_wait +7 +SET @@session.wsrep_sync_wait=default; +SELECT @@session.wsrep_sync_wait; +@@session.wsrep_sync_wait +7 +SET @@session.wsrep_sync_wait=8; +Warnings: +Warning 1292 Truncated incorrect wsrep_sync_wait value: '8' +SELECT @@session.wsrep_sync_wait; +@@session.wsrep_sync_wait +7 + +# invalid values +SET @@global.wsrep_sync_wait=NULL; +ERROR 42000: Incorrect argument type to variable 'wsrep_sync_wait' +SET @@global.wsrep_sync_wait='junk'; +ERROR 42000: Incorrect argument type to variable 'wsrep_sync_wait' +SET @@session.wsrep_sync_wait=NULL; +ERROR 42000: Incorrect argument type to variable 'wsrep_sync_wait' +SET @@session.wsrep_sync_wait='junk'; +ERROR 42000: Incorrect argument type to variable 'wsrep_sync_wait' + +# restore the initial values +SET @@global.wsrep_sync_wait = @wsrep_sync_wait_global_saved; +SET @@session.wsrep_sync_wait = @wsrep_sync_wait_session_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_sync_wait_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sync_wait_basic.test new file mode 100644 index 00000000000..cd0d545f80e --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_sync_wait_basic.test @@ -0,0 +1,47 @@ +--source include/have_wsrep.inc + +--echo # +--echo # wsrep_sync_wait +--echo # + +--echo # save the initial values +SET @wsrep_sync_wait_global_saved = @@global.wsrep_sync_wait; +SET @wsrep_sync_wait_session_saved = @@session.wsrep_sync_wait; + +--echo # default +SELECT @@global.wsrep_sync_wait; +SELECT @@session.wsrep_sync_wait; + +--echo +--echo # scope and valid values +SET @@global.wsrep_sync_wait=0; +SELECT @@global.wsrep_sync_wait; +SET @@global.wsrep_sync_wait=7; +SELECT @@global.wsrep_sync_wait; + +SET @@session.wsrep_sync_wait=0; +SELECT @@session.wsrep_sync_wait; +SET @@session.wsrep_sync_wait=7; +SELECT @@session.wsrep_sync_wait; +SET @@session.wsrep_sync_wait=default; +SELECT @@session.wsrep_sync_wait; +SET @@session.wsrep_sync_wait=8; +SELECT @@session.wsrep_sync_wait; + +--echo +--echo # invalid values +--error ER_WRONG_TYPE_FOR_VAR +SET @@global.wsrep_sync_wait=NULL; +--error ER_WRONG_TYPE_FOR_VAR +SET @@global.wsrep_sync_wait='junk'; +--error ER_WRONG_TYPE_FOR_VAR +SET @@session.wsrep_sync_wait=NULL; +--error ER_WRONG_TYPE_FOR_VAR +SET @@session.wsrep_sync_wait='junk'; + +--echo +--echo # restore the initial values +SET @@global.wsrep_sync_wait = @wsrep_sync_wait_global_saved; +SET @@session.wsrep_sync_wait = @wsrep_sync_wait_session_saved; + +--echo # End of test diff --git a/mysql-test/suite/wsrep/r/innodb_load_xa_with_wsrep.result b/mysql-test/suite/wsrep/r/innodb_load_xa_with_wsrep.result new file mode 100644 index 00000000000..90faf766145 --- /dev/null +++ b/mysql-test/suite/wsrep/r/innodb_load_xa_with_wsrep.result @@ -0,0 +1,19 @@ +install plugin innodb soname 'ha_innodb'; +select engine,support,transactions,xa from information_schema.engines where engine='innodb'; +engine support transactions xa +InnoDB YES YES YES +create table t1 (a int) engine=innodb; +start transaction; +insert t1 values (1); +insert t1 values (2); +commit; +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +mysqld-bin.000001 # Gtid # # GTID #-#-# +mysqld-bin.000001 # Query # # use `test`; create table t1 (a int) engine=innodb +mysqld-bin.000001 # Gtid # # BEGIN GTID #-#-# +mysqld-bin.000001 # Query # # use `test`; insert t1 values (1) +mysqld-bin.000001 # Query # # use `test`; insert t1 values (2) +mysqld-bin.000001 # Xid # # COMMIT /* XID */ +drop table t1; +uninstall plugin innodb; diff --git a/mysql-test/suite/wsrep/t/innodb_load_xa_with_wsrep.opt b/mysql-test/suite/wsrep/t/innodb_load_xa_with_wsrep.opt new file mode 100644 index 00000000000..4ff27e659ce --- /dev/null +++ b/mysql-test/suite/wsrep/t/innodb_load_xa_with_wsrep.opt @@ -0,0 +1 @@ +--ignore-builtin-innodb --loose-innodb --log-bin diff --git a/mysql-test/suite/wsrep/t/innodb_load_xa_with_wsrep.test b/mysql-test/suite/wsrep/t/innodb_load_xa_with_wsrep.test new file mode 100644 index 00000000000..413faf54864 --- /dev/null +++ b/mysql-test/suite/wsrep/t/innodb_load_xa_with_wsrep.test @@ -0,0 +1,19 @@ +# +# MDEV-6082 Assertion `0' fails in TC_LOG_DUMMY::log_and_order on DML after installing TokuDB at runtime on server with disabled InnoDB +# +--source include/not_embedded.inc +--source include/have_wsrep.inc + +if (!$HA_INNODB_SO) { + --skip Need InnoDB plugin +} +install plugin innodb soname 'ha_innodb'; +select engine,support,transactions,xa from information_schema.engines where engine='innodb'; +create table t1 (a int) engine=innodb; +start transaction; +insert t1 values (1); +insert t1 values (2); +commit; +--source include/show_binlog_events.inc +drop table t1; +uninstall plugin innodb; diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc index 96ac599a3b6..26d2e1ef985 100644 --- a/sql/event_data_objects.cc +++ b/sql/event_data_objects.cc @@ -1477,11 +1477,12 @@ end: { // sql_print_information("sizeof(LEX) = %d", sizeof(struct LEX)); // sizeof(LEX) = 4512, so it's relatively safe to allocate it on stack. - LEX *old_lex= thd->lex, new_lex; - new_lex.sql_command= SQLCOM_DROP_EVENT; - thd->lex= &new_lex; + LEX lex; + LEX* saved = thd->lex; + lex.sql_command = SQLCOM_DROP_EVENT; + thd->lex = &lex; WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); - thd->lex= old_lex; + thd->lex = saved; } #endif diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index a620ae98c6d..0b610718cd0 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -1199,6 +1199,7 @@ bool Sql_cmd_optimize_table::execute(THD *thd) if (check_table_access(thd, SELECT_ACL | INSERT_ACL, first_table, FALSE, UINT_MAX, FALSE)) goto error; /* purecov: inspected */ + WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL) thd->enable_slow_log= opt_log_slow_admin_statements; res= (specialflag & SPECIAL_NO_NEW_FUNC) ? mysql_recreate_table(thd, first_table, true) : diff --git a/sql/sql_class.h b/sql/sql_class.h index d6433d6fcf8..d3b305d34f4 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -642,6 +642,7 @@ typedef struct system_variables #ifdef WITH_WSREP my_bool wsrep_on; my_bool wsrep_causal_reads; + uint wsrep_sync_wait; ulong wsrep_retry_autocommit; #endif double long_query_time_double; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 87efbabe6f8..066acfb015a 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2719,7 +2719,7 @@ mysql_execute_command(THD *thd) case SQLCOM_SHOW_STATUS: { #ifdef WITH_WSREP - if (WSREP_CLIENT(thd) && wsrep_causal_wait(thd)) + if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error; #endif /* WITH_WSREP */ execute_show_status(thd, all_tables); @@ -2755,7 +2755,7 @@ mysql_execute_command(THD *thd) case SQLCOM_SHOW_STATUS_PROC: case SQLCOM_SHOW_STATUS_FUNC: #ifdef WITH_WSREP - if (WSREP_CLIENT(thd) && wsrep_causal_wait(thd)) + if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error; #endif /* WITH_WSREP */ @@ -2780,7 +2780,7 @@ mysql_execute_command(THD *thd) case SQLCOM_SHOW_INDEX_STATS: case SQLCOM_SELECT: #ifdef WITH_WSREP - if (WSREP_CLIENT(thd) && wsrep_causal_wait(thd)) + if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error; case SQLCOM_SHOW_VARIABLES: case SQLCOM_SHOW_CHARSETS: @@ -2788,7 +2788,7 @@ mysql_execute_command(THD *thd) case SQLCOM_SHOW_STORAGE_ENGINES: case SQLCOM_SHOW_PROFILE: #endif /* WITH_WSREP */ - { + { thd->status_var.last_query_cost= 0.0; /* @@ -2811,7 +2811,7 @@ mysql_execute_command(THD *thd) res= execute_sqlcom_select(thd, all_tables); break; } -case SQLCOM_PREPARE: + case SQLCOM_PREPARE: { mysql_sql_stmt_prepare(thd); break; @@ -3460,15 +3460,16 @@ end_with_restore_list: #endif #endif /* EMBEDDED_LIBRARY */ case SQLCOM_SHOW_CREATE: + { DBUG_ASSERT(first_table == all_tables && first_table != 0); #ifdef DONT_ALLOW_SHOW_COMMANDS my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */ goto error; #else - { + #ifdef WITH_WSREP - if (WSREP_CLIENT(thd) && wsrep_causal_wait(thd)) + if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error; #endif /* WITH_WSREP */ @@ -3529,13 +3530,13 @@ end_with_restore_list: /* Access is granted. Execute the command. */ res= mysqld_show_create(thd, first_table); break; - } #endif + } case SQLCOM_CHECKSUM: { DBUG_ASSERT(first_table == all_tables && first_table != 0); #ifdef WITH_WSREP - if (WSREP_CLIENT(thd) && wsrep_causal_wait(thd)) + if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error; #endif /* WITH_WSREP */ @@ -3550,6 +3551,12 @@ end_with_restore_list: { ha_rows found= 0, updated= 0; DBUG_ASSERT(first_table == all_tables && first_table != 0); +#ifdef WITH_WSREP + if (WSREP_CLIENT(thd) && + wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE)) + goto error; +#endif /* WITH_WSREP */ + if (update_precheck(thd, all_tables)) break; @@ -3586,6 +3593,11 @@ end_with_restore_list: /* if we switched from normal update, rights are checked */ if (up_result != 2) { +#ifdef WITH_WSREP + if (WSREP_CLIENT(thd) && + wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE)) + goto error; +#endif /* WITH_WSREP */ if ((res= multi_update_precheck(thd, all_tables))) break; } @@ -3655,6 +3667,12 @@ end_with_restore_list: break; } case SQLCOM_REPLACE: + { +#ifdef WITH_WSREP + if (WSREP_CLIENT(thd) && + wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE)) + goto error; +#endif /* WITH_WSREP */ #ifndef DBUG_OFF if (mysql_bin_log.is_open()) { @@ -3689,10 +3707,17 @@ end_with_restore_list: DBUG_PRINT("debug", ("Just after generate_incident()")); } #endif + } case SQLCOM_INSERT: { DBUG_ASSERT(first_table == all_tables && first_table != 0); +#ifdef WITH_WSREP + if (WSREP_CLIENT(thd) && + wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE)) + goto error; +#endif /* WITH_WSREP */ + /* Since INSERT DELAYED doesn't support temporary tables, we could not pre-open temporary tables for SQLCOM_INSERT / SQLCOM_REPLACE. @@ -3747,11 +3772,16 @@ end_with_restore_list: select_result *sel_result; bool explain= MY_TEST(lex->describe); DBUG_ASSERT(first_table == all_tables && first_table != 0); +#ifdef WITH_WSREP + if (WSREP_CLIENT(thd) && + wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE)) + goto error; +#endif /* WITH_WSREP */ + if ((res= insert_precheck(thd, all_tables))) break; #ifdef WITH_WSREP - if (WSREP_ON && lex->sql_command == SQLCOM_INSERT_SELECT && - thd->wsrep_consistency_check == CONSISTENCY_CHECK_DECLARED) + if (WSREP(thd) && thd->wsrep_consistency_check == CONSISTENCY_CHECK_DECLARED) { thd->wsrep_consistency_check = CONSISTENCY_CHECK_RUNNING; WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL); @@ -3848,6 +3878,12 @@ end_with_restore_list: { select_result *sel_result=lex->result; DBUG_ASSERT(first_table == all_tables && first_table != 0); +#ifdef WITH_WSREP + if (WSREP_CLIENT(thd) && + wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE)) + goto error; +#endif /* WITH_WSREP */ + if ((res= delete_precheck(thd, all_tables))) break; DBUG_ASSERT(select_lex->offset_limit == 0); @@ -3904,6 +3940,11 @@ end_with_restore_list: DBUG_ASSERT(first_table == all_tables && first_table != 0); TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first; multi_delete *result; +#ifdef WITH_WSREP + if (WSREP_CLIENT(thd) && + wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE)) + goto error; +#endif /* WITH_WSREP */ if ((res= multi_delete_precheck(thd, all_tables))) break; @@ -3975,7 +4016,7 @@ end_with_restore_list: thd->variables.option_bits|= OPTION_KEEP_LOG; } #ifdef WITH_WSREP - if (WSREP_ON) + if (WSREP(thd)) { for (TABLE_LIST *table= all_tables; table; table= table->next_global) { @@ -4002,8 +4043,8 @@ end_with_restore_list: /* DDL and binlog write order are protected by metadata locks. */ res= mysql_rm_table(thd, first_table, lex->check_exists, lex->drop_temporary); + break; } - break; case SQLCOM_SHOW_PROCESSLIST: if (!thd->security_ctx->priv_user[0] && check_global_access(thd,PROCESS_ACL)) diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 2c2d301f622..c76ee5e6358 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -4615,9 +4615,22 @@ static Sys_var_mybool Sys_wsrep_certify_nonPK( CMD_LINE(OPT_ARG), DEFAULT(TRUE)); static Sys_var_mybool Sys_wsrep_causal_reads( - "wsrep_causal_reads", "Enable \"strictly synchronous\" semantics for read operations", - SESSION_VAR(wsrep_causal_reads), - CMD_LINE(OPT_ARG), DEFAULT(FALSE)); + "wsrep_causal_reads", "(DEPRECATED) Setting this variable is equivalent " + "to setting wsrep_sync_wait READ flag", + SESSION_VAR(wsrep_causal_reads), CMD_LINE(OPT_ARG), DEFAULT(FALSE), + NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), + ON_UPDATE(wsrep_causal_reads_update)); + +static Sys_var_uint Sys_wsrep_sync_wait( + "wsrep_sync_wait", "Ensure \"synchronous\" read view before executing " + "an operation of the type specified by bitmask: 1 - READ(includes " + "SELECT, SHOW and BEGIN/START TRANSACTION); 2 - UPDATE and DELETE; 4 - " + "INSERT and REPLACE", + SESSION_VAR(wsrep_sync_wait), CMD_LINE(OPT_ARG), + VALID_RANGE(WSREP_SYNC_WAIT_NONE, WSREP_SYNC_WAIT_MAX), + DEFAULT(WSREP_SYNC_WAIT_NONE), BLOCK_SIZE(1), + NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), + ON_UPDATE(wsrep_sync_wait_update)); static const char *wsrep_OSU_method_names[]= { "TOI", "RSU", NullS }; static Sys_var_enum Sys_wsrep_OSU_method( diff --git a/sql/transaction.cc b/sql/transaction.cc index e7d3c0afc78..9b3507de2eb 100644 --- a/sql/transaction.cc +++ b/sql/transaction.cc @@ -195,7 +195,7 @@ bool trans_begin(THD *thd, uint flags) #ifdef WITH_WSREP thd->wsrep_PA_safe= true; - if (WSREP_CLIENT(thd) && wsrep_causal_wait(thd)) + if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) DBUG_RETURN(TRUE); #endif /* WITH_WSREP */ diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index a77f85cbbdb..a8157082038 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -146,7 +146,7 @@ static void wsrep_log_cb(wsrep_log_level_t level, const char *msg) { sql_print_error("WSREP: %s", msg); break; case WSREP_LOG_DEBUG: - sql_print_information ("[Debug] WSREP: %s", msg); + if (wsrep_debug) sql_print_information ("[Debug] WSREP: %s", msg); default: break; } @@ -808,10 +808,10 @@ void wsrep_filter_new_cluster (int* argc, char* argv[]) { /* make a copy of the argument to convert possible underscores to hyphens. * the copy need not to be longer than WSREP_NEW_CLUSTER option */ - char arg[sizeof(WSREP_NEW_CLUSTER) + 2]= { 0, }; + char arg[sizeof(WSREP_NEW_CLUSTER) + 1]= { 0, }; strncpy(arg, argv[i], sizeof(arg) - 1); - char* underscore; - while (NULL != (underscore= strchr(arg, '_'))) *underscore= '-'; + char* underscore(arg); + while (NULL != (underscore= strchr(underscore, '_'))) *underscore= '-'; if (!strcmp(arg, WSREP_NEW_CLUSTER)) { @@ -893,13 +893,15 @@ bool wsrep_start_replication() return true; } -bool -wsrep_causal_wait (THD* thd) +bool wsrep_sync_wait (THD* thd, uint mask) { - if (thd->variables.wsrep_causal_reads && thd->variables.wsrep_on && + if ((thd->variables.wsrep_sync_wait & mask) && + thd->variables.wsrep_on && !thd->in_active_multi_stmt_transaction() && thd->wsrep_conflict_state != REPLAYING) { + WSREP_DEBUG("wsrep_sync_wait: thd->variables.wsrep_sync_wait = %u, mask = %u", + thd->variables.wsrep_sync_wait, mask); // This allows autocommit SELECTs and a first SELECT after SET AUTOCOMMIT=0 // TODO: modify to check if thd has locked any rows. wsrep_gtid_t gtid; @@ -918,12 +920,12 @@ wsrep_causal_wait (THD* thd) switch (ret) { case WSREP_NOT_IMPLEMENTED: - msg= "consistent reads by wsrep backend. " + msg= "synchronous reads by wsrep backend. " "Please unset wsrep_causal_reads variable."; err= ER_NOT_SUPPORTED_YET; break; default: - msg= "Causal wait failed."; + msg= "Synchronous wait failed."; err= ER_LOCK_WAIT_TIMEOUT; // NOTE: the above msg won't be displayed // with ER_LOCK_WAIT_TIMEOUT } @@ -1818,7 +1820,6 @@ static my_bool have_committing_connections() if (is_committing_connection(tmp)) { - mysql_mutex_unlock(&LOCK_thread_count); return TRUE; } } @@ -2302,6 +2303,9 @@ void wsrep_copy_query(THD *thd) { thd->wsrep_retry_command = thd->get_command(); thd->wsrep_retry_query_len = thd->query_length(); + if (thd->wsrep_retry_query) { + my_free(thd->wsrep_retry_query); + } thd->wsrep_retry_query = (char *)my_malloc( thd->wsrep_retry_query_len + 1, MYF(0)); strncpy(thd->wsrep_retry_query, thd->query(), thd->wsrep_retry_query_len); diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index 18d525d2376..2150ac85bf0 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -115,6 +115,14 @@ extern my_bool wsrep_slave_FK_checks; extern my_bool wsrep_slave_UK_checks; enum enum_wsrep_OSU_method { WSREP_OSU_TOI, WSREP_OSU_RSU }; +enum enum_wsrep_sync_wait { + WSREP_SYNC_WAIT_NONE = 0x0, + // show, select, begin + WSREP_SYNC_WAIT_BEFORE_READ = 0x1, + WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE = 0x2, + WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE = 0x4, + WSREP_SYNC_WAIT_MAX = 0x7 +}; // MySQL status variables extern my_bool wsrep_connected; @@ -188,9 +196,10 @@ extern void wsrep_kill_mysql(THD *thd); /* new defines */ extern void wsrep_stop_replication(THD *thd); extern bool wsrep_start_replication(); -extern bool wsrep_causal_wait(THD* thd); +extern bool wsrep_sync_wait (THD* thd, uint mask = WSREP_SYNC_WAIT_BEFORE_READ); extern int wsrep_check_opts (int argc, char* const* argv); extern void wsrep_prepend_PATH (const char* path); +/* some inline functions are defined in wsrep_mysqld_inl.h */ /* Other global variables */ extern wsrep_seqno_t wsrep_locked_seqno; diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc index b485daa2a9c..6fc91c9fa31 100644 --- a/sql/wsrep_thd.cc +++ b/sql/wsrep_thd.cc @@ -503,17 +503,35 @@ int wsrep_thd_conflict_state(void *thd_ptr, my_bool sync) return state; } -my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync) -{ +my_bool wsrep_thd_is_wsrep(void *thd_ptr) +{ my_bool status = FALSE; - if (thd_ptr) + if (thd_ptr) { THD* thd = (THD*)thd_ptr; - if (sync) mysql_mutex_lock(&thd->LOCK_wsrep_thd); - - status = ((thd->wsrep_exec_mode == REPL_RECV) || - (thd->wsrep_exec_mode == TOTAL_ORDER)); - if (sync) mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + + status = (WSREP(thd) && WSREP_PROVIDER_EXISTS); + } + return status; +} + +my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync) +{ + my_bool status = FALSE; + if (thd_ptr) + { + THD* thd = (THD*)thd_ptr; + // THD can be BF only if provider exists + if (wsrep_thd_is_wsrep(thd_ptr)) + { + if (sync) + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + + status = ((thd->wsrep_exec_mode == REPL_RECV) || + (thd->wsrep_exec_mode == TOTAL_ORDER)); + if (sync) + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } } return status; } diff --git a/sql/wsrep_thd.h b/sql/wsrep_thd.h index 14fdfc97858..c5a497bb428 100644 --- a/sql/wsrep_thd.h +++ b/sql/wsrep_thd.h @@ -29,6 +29,8 @@ int wsrep_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr, extern void wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe); extern my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync); +extern my_bool wsrep_thd_is_wsrep(void *thd_ptr); + extern int wsrep_thd_conflict_state(void *thd_ptr, my_bool sync); //extern "C" my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync); extern "C" my_bool wsrep_thd_is_BF_or_commit(void *thd_ptr, my_bool sync); diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc index b965c26c184..2272945535d 100644 --- a/sql/wsrep_var.cc +++ b/sql/wsrep_var.cc @@ -60,11 +60,29 @@ bool wsrep_on_update (sys_var *self, THD* thd, enum_var_type var_type) return false; } -void wsrep_causal_reads_update (sys_var *self, THD* thd, enum_var_type var_type) +bool wsrep_causal_reads_update (sys_var *self, THD* thd, enum_var_type var_type) { - if (var_type == OPT_GLOBAL) { - thd->variables.wsrep_causal_reads = global_system_variables.wsrep_causal_reads; + // global setting should not affect session setting. + // if (var_type == OPT_GLOBAL) { + // thd->variables.wsrep_causal_reads = global_system_variables.wsrep_causal_reads; + // } + if (thd->variables.wsrep_causal_reads) { + thd->variables.wsrep_sync_wait |= WSREP_SYNC_WAIT_BEFORE_READ; + } else { + thd->variables.wsrep_sync_wait &= ~WSREP_SYNC_WAIT_BEFORE_READ; } + return false; +} + +bool wsrep_sync_wait_update (sys_var* self, THD* thd, enum_var_type var_type) +{ + // global setting should not affect session setting. + // if (var_type == OPT_GLOBAL) { + // thd->variables.wsrep_sync_wait = global_system_variables.wsrep_sync_wait; + // } + thd->variables.wsrep_causal_reads = thd->variables.wsrep_sync_wait & + WSREP_SYNC_WAIT_BEFORE_READ; + return false; } static int wsrep_start_position_verify (const char* start_str) diff --git a/sql/wsrep_var.h b/sql/wsrep_var.h index c62ea7781cc..58d0374baa5 100644 --- a/sql/wsrep_var.h +++ b/sql/wsrep_var.h @@ -35,7 +35,8 @@ int wsrep_init_vars(); #define INIT_ARGS (const char* opt) extern bool wsrep_on_update UPDATE_ARGS; -extern void wsrep_causal_reads_update UPDATE_ARGS; +extern bool wsrep_causal_reads_update UPDATE_ARGS; +extern bool wsrep_sync_wait_update UPDATE_ARGS; extern bool wsrep_start_position_check CHECK_ARGS; extern bool wsrep_start_position_update UPDATE_ARGS; extern void wsrep_start_position_init INIT_ARGS; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 9313a0bf232..a5a0616dc63 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -5757,7 +5757,7 @@ wsrep_innobase_mysql_sort( case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_VARCHAR: { - uchar tmp_str[REC_VERSION_56_MAX_INDEX_COL_LEN]; + uchar tmp_str[REC_VERSION_56_MAX_INDEX_COL_LEN] = {'\0'}; uint tmp_length = REC_VERSION_56_MAX_INDEX_COL_LEN; /* Use the charset number to pick the right charset struct for @@ -5796,11 +5796,11 @@ wsrep_innobase_mysql_sort( } else { /* strnxfrm will expand the destination string, protocols < 3 truncated the sorted sring - protocols > 3 gets full sorted sring + protocols >= 3 gets full sorted sring */ tmp_length = charset->coll->strnxfrm( charset, str, buf_length, - str_length, tmp_str, tmp_length, 0); + str_length, tmp_str, str_length, 0); DBUG_ASSERT(tmp_length <= buf_length); ret_length = tmp_length; } @@ -6343,6 +6343,7 @@ UNIV_INTERN uint wsrep_store_key_val_for_row( /*===============================*/ + THD* thd, TABLE* table, uint keynr, /*!< in: key number */ char* buff, /*!< in/out: buffer for the key value (in MySQL @@ -6357,25 +6358,33 @@ wsrep_store_key_val_for_row( char* buff_start = buff; enum_field_types mysql_type; Field* field; - + uint buff_space = buff_len; + DBUG_ENTER("wsrep_store_key_val_for_row"); memset(buff, 0, buff_len); *key_is_null = TRUE; for (; key_part != end; key_part++) { + uchar sorted[REC_VERSION_56_MAX_INDEX_COL_LEN] = {'\0'}; ibool part_is_null = FALSE; if (key_part->null_bit) { - if (record[key_part->null_offset] & - key_part->null_bit) { - *buff = 1; - part_is_null = TRUE; + if (buff_space > 0) { + if (record[key_part->null_offset] + & key_part->null_bit) { + *buff = 1; + part_is_null = TRUE; + } else { + *buff = 0; + } + buff++; + buff_space--; } else { - *buff = 0; + fprintf (stderr, "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); } - buff++; } if (!part_is_null) *key_is_null = FALSE; @@ -6395,8 +6404,15 @@ wsrep_store_key_val_for_row( key_len = key_part->length; if (part_is_null) { - buff += key_len + 2; - + true_len = key_len + 2; + if (true_len > buff_space) { + fprintf (stderr, + "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); + true_len = buff_space; + } + buff += true_len; + buff_space -= true_len; continue; } cs = field->charset(); @@ -6436,13 +6452,20 @@ wsrep_store_key_val_for_row( REC_VERSION_56_MAX_INDEX_COL_LEN); if (wsrep_protocol_version > 1) { - memcpy(buff, sorted, true_len); - /* Note that we always reserve the maximum possible - length of the true VARCHAR in the key value, though - only len first bytes after the 2 length bytes contain - actual data. The rest of the space was reset to zero - in the bzero() call above. */ - buff += true_len; + /* Note that we always reserve the maximum possible + length of the true VARCHAR in the key value, though + only len first bytes after the 2 length bytes contain + actual data. The rest of the space was reset to zero + in the bzero() call above. */ + if (true_len > buff_space) { + fprintf (stderr, + "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); + true_len = buff_space; + } + memcpy(buff, sorted, true_len); + buff += true_len; + buff_space -= true_len; } else { buff += key_len; } @@ -6466,7 +6489,15 @@ wsrep_store_key_val_for_row( key_len = key_part->length; if (part_is_null) { - buff += key_len + 2; + true_len = key_len + 2; + if (true_len > buff_space) { + fprintf (stderr, + "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); + true_len = buff_space; + } + buff += true_len; + buff_space -= true_len; continue; } @@ -6509,15 +6540,22 @@ wsrep_store_key_val_for_row( mysql_type, cs->number, sorted, true_len, REC_VERSION_56_MAX_INDEX_COL_LEN); - memcpy(buff, sorted, true_len); /* Note that we always reserve the maximum possible length of the BLOB prefix in the key value. */ if (wsrep_protocol_version > 1) { - buff += true_len; - } else { - buff += key_len; - } + if (true_len > buff_space) { + fprintf (stderr, + "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); + true_len = buff_space; + } + buff += true_len; + buff_space -= true_len; + } else { + buff += key_len; + } + memcpy(buff, sorted, true_len); } else { /* Here we handle all other data types except the true VARCHAR, BLOB and TEXT. Note that the column @@ -6534,9 +6572,17 @@ wsrep_store_key_val_for_row( key_len = key_part->length; if (part_is_null) { - buff += key_len; + true_len = key_len; + if (true_len > buff_space) { + fprintf (stderr, + "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); + true_len = buff_space; + } + buff += true_len; + buff_space -= true_len; - continue; + continue; } src_start = record + key_part->offset; @@ -6574,12 +6620,18 @@ wsrep_store_key_val_for_row( mysql_type, cs->number, sorted, true_len, REC_VERSION_56_MAX_INDEX_COL_LEN); + if (true_len > buff_space) { + fprintf (stderr, + "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); + true_len = buff_space; + } memcpy(buff, sorted, true_len); } else { memcpy(buff, src_start, true_len); } - buff += true_len; - + buff += true_len; + buff_space -= true_len; } } @@ -9782,7 +9834,8 @@ ha_innobase::wsrep_append_keys( ibool is_null; len = wsrep_store_key_val_for_row( - table, 0, key, key_info->key_length, record0, &is_null); + thd, table, 0, key, WSREP_MAX_SUPPORTED_KEY_LENGTH, + record0, &is_null); if (!is_null) { rcode = wsrep_append_key( @@ -9804,9 +9857,6 @@ ha_innobase::wsrep_append_keys( KEY* key_info = table->key_info + i; if (key_info->flags & HA_NOSAME) { hasPK = true; - if (i != table->s->primary_key) { - wsrep_thd_set_PA_safe(thd, FALSE); - } } } @@ -9837,7 +9887,8 @@ ha_innobase::wsrep_append_keys( (!tab && referenced_by_foreign_key()))) { len = wsrep_store_key_val_for_row( - table, i, key0, key_info->key_length, + thd, table, i, key0, + WSREP_MAX_SUPPORTED_KEY_LENGTH, record0, &is_null); if (!is_null) { rcode = wsrep_append_key( @@ -9847,7 +9898,6 @@ ha_innobase::wsrep_append_keys( if (key_info->flags & HA_NOSAME || shared) key_appended = true; - } else { @@ -9856,7 +9906,8 @@ ha_innobase::wsrep_append_keys( } if (record1) { len = wsrep_store_key_val_for_row( - table, i, key1, key_info->key_length, + thd, table, i, key1, + WSREP_MAX_SUPPORTED_KEY_LENGTH, record1, &is_null); if (!is_null && memcmp(key0, key1, len)) { rcode = wsrep_append_key( diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h index 336ff92a619..563a01f747d 100644 --- a/storage/innobase/include/ha_prototypes.h +++ b/storage/innobase/include/ha_prototypes.h @@ -294,6 +294,7 @@ wsrep_innobase_kill_one_trx(void *thd_ptr, my_bool wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe); int wsrep_thd_conflict_state(void *thd_ptr, my_bool sync); my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync); +my_bool wsrep_thd_is_wsrep(void *thd_ptr); int wsrep_trx_order_before(void *thd1, void *thd2); int wsrep_innobase_mysql_sort(int mysql_type, uint charset_number, unsigned char* str, unsigned int str_length, diff --git a/storage/innobase/include/hash0hash.h b/storage/innobase/include/hash0hash.h index 6f9a628df5d..9a4077befb1 100644 --- a/storage/innobase/include/hash0hash.h +++ b/storage/innobase/include/hash0hash.h @@ -144,6 +144,33 @@ do {\ }\ } while (0) +#ifdef WITH_WSREP +/*******************************************************************//** +Inserts a struct to the head of hash table. */ + +#define HASH_PREPEND(TYPE, NAME, TABLE, FOLD, DATA) \ +do { \ + hash_cell_t* cell3333; \ + TYPE* struct3333; \ + \ + HASH_ASSERT_OWN(TABLE, FOLD) \ + \ + (DATA)->NAME = NULL; \ + \ + cell3333 = hash_get_nth_cell(TABLE, hash_calc_hash(FOLD, TABLE));\ + \ + if (cell3333->node == NULL) { \ + cell3333->node = DATA; \ + DATA->NAME = NULL; \ + } else { \ + struct3333 = (TYPE*) cell3333->node; \ + \ + DATA->NAME = struct3333; \ + \ + cell3333->node = DATA; \ + } \ +} while (0) +#endif /*WITH_WSREP */ #ifdef UNIV_HASH_DEBUG # define HASH_ASSERT_VALID(DATA) ut_a((void*) (DATA) != (void*) -1) # define HASH_INVALIDATE(DATA, NAME) *(void**) (&DATA->NAME) = (void*) -1 diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 14ebb68fa9e..ce107dda077 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -1035,22 +1035,23 @@ lock_rec_has_to_wait( lock_rec_print(stderr, lock2); } - if (wsrep_trx_order_before(trx->mysql_thd, + if (wsrep_trx_order_before(trx->mysql_thd, lock2->trx->mysql_thd) && (type_mode & LOCK_MODE_MASK) == LOCK_X && (lock2->type_mode & LOCK_MODE_MASK) == LOCK_X) { /* exclusive lock conflicts are not accepted */ - fprintf(stderr, "BF-BF X lock conflict," - "type_mode: %lu supremum: %lu\n", + fprintf(stderr, "BF-BF X lock conflict," + "type_mode: %lu supremum: %lu\n", type_mode, lock_is_on_supremum); - fprintf(stderr, "conflicts states: my %d locked %d\n", - wsrep_thd_conflict_state(trx->mysql_thd, FALSE), + fprintf(stderr, "conflicts states: my %d locked %d\n", + wsrep_thd_conflict_state(trx->mysql_thd, FALSE), wsrep_thd_conflict_state(lock2->trx->mysql_thd, FALSE) ); lock_rec_print(stderr, lock2); - abort(); + return FALSE; + //abort(); } else { - /* if lock2->index->n_uniq <= + /* if lock2->index->n_uniq <= lock2->index->n_user_defined_cols operation is on uniq index */ @@ -1060,7 +1061,7 @@ lock_rec_has_to_wait( type_mode, lock2->type_mode, lock2->index->name, lock2->index->table_name, - lock2->index->n_uniq, + lock2->index->n_uniq, lock2->index->n_user_defined_cols); return FALSE; } @@ -1623,8 +1624,12 @@ lock_rec_other_has_expl_req( #endif /* UNIV_DEBUG */ #ifdef WITH_WSREP -static void -wsrep_kill_victim(const trx_t * const trx, const lock_t *lock) { +static +void +wsrep_kill_victim( + const trx_t * const trx, + const lock_t *lock) +{ ut_ad(lock_mutex_own()); ut_ad(trx_mutex_own(lock->trx)); my_bool bf_this = wsrep_thd_is_BF(trx->mysql_thd, FALSE); @@ -1633,32 +1638,38 @@ wsrep_kill_victim(const trx_t * const trx, const lock_t *lock) { if ((bf_this && !bf_other) || (bf_this && bf_other && wsrep_trx_order_before( trx->mysql_thd, lock->trx->mysql_thd))) { - + if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { - if (wsrep_debug) + if (wsrep_debug) { fprintf(stderr, "WSREP: BF victim waiting\n"); + } /* cannot release lock, until our lock is in the queue*/ } else if (lock->trx != trx) { if (wsrep_log_conflicts) { mutex_enter(&trx_sys->mutex); - if (bf_this) - fputs("\n*** Priority TRANSACTION:\n", + if (bf_this) { + fputs("\n*** Priority TRANSACTION:\n", stderr); - else - fputs("\n*** Victim TRANSACTION:\n", + } else { + fputs("\n*** Victim TRANSACTION:\n", stderr); + } + trx_print_latched(stderr, trx, 3000); - if (bf_other) - fputs("\n*** Priority TRANSACTION:\n", + if (bf_other) { + fputs("\n*** Priority TRANSACTION:\n", stderr); - else - fputs("\n*** Victim TRANSACTION:\n", + } else { + fputs("\n*** Victim TRANSACTION:\n", stderr); + } + trx_print_latched(stderr, lock->trx, 3000); mutex_exit(&trx_sys->mutex); + fputs("*** WAITING FOR THIS LOCK TO BE GRANTED:\n", stderr); @@ -1668,6 +1679,7 @@ wsrep_kill_victim(const trx_t * const trx, const lock_t *lock) { lock_table_print(stderr, lock); } } + wsrep_innobase_kill_one_trx(trx->mysql_thd, (const trx_t*) trx, lock->trx, TRUE); } @@ -1997,7 +2009,7 @@ lock_rec_create( ut_ad(index->table->n_ref_count > 0 || !index->table->can_be_evicted); #ifdef WITH_WSREP - if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { lock_t *hash = (lock_t *)c_lock->hash; lock_t *prev = NULL; @@ -2024,7 +2036,9 @@ lock_rec_create( c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE; - if (wsrep_debug) wsrep_print_wait_locks(c_lock); + if (wsrep_debug) { + wsrep_print_wait_locks(c_lock); + } trx->lock.que_state = TRX_QUE_LOCK_WAIT; lock_set_lock_and_trx_wait(lock, trx); @@ -2038,10 +2052,15 @@ lock_rec_create( victim lock release. This will eventually call lock_grant, which wants to grant trx mutex again */ - if (caller_owns_trx_mutex) trx_mutex_exit(trx); + if (caller_owns_trx_mutex) { + trx_mutex_exit(trx); + } lock_cancel_waiting_and_release( c_lock->trx->lock.wait_lock); - if (caller_owns_trx_mutex) trx_mutex_enter(trx); + + if (caller_owns_trx_mutex) { + trx_mutex_enter(trx); + } /* trx might not wait for c_lock, but some other lock does not matter if wait_lock was released above @@ -2049,17 +2068,23 @@ lock_rec_create( if (c_lock->trx->lock.wait_lock == c_lock) { lock_reset_lock_and_trx_wait(lock); } + trx_mutex_exit(c_lock->trx); - if (wsrep_debug) fprintf( - stderr, - "WSREP: c_lock canceled %llu\n", - (ulonglong) c_lock->trx->id); + if (wsrep_debug) { + fprintf( + stderr, + "WSREP: c_lock canceled %llu\n", + (ulonglong) c_lock->trx->id); + } /* have to bail out here to avoid lock_set_lock... */ return(lock); } trx_mutex_exit(c_lock->trx); + } else if (wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + HASH_PREPEND(lock_t, hash, lock_sys->rec_hash, + lock_rec_fold(space, page_no), lock); } else { HASH_INSERT(lock_t, hash, lock_sys->rec_hash, lock_rec_fold(space, page_no), lock); @@ -2075,7 +2100,6 @@ lock_rec_create( ut_ad(trx_mutex_own(trx)); if (type_mode & LOCK_WAIT) { - lock_set_lock_and_trx_wait(lock, trx); } @@ -2087,7 +2111,6 @@ lock_rec_create( MONITOR_INC(MONITOR_RECLOCK_CREATED); MONITOR_INC(MONITOR_NUM_RECLOCK); - return(lock); } @@ -2267,7 +2290,7 @@ lock_rec_add_to_queue( block, heap_no, trx); #ifdef WITH_WSREP /* this can potentionally assert with wsrep */ - if (wsrep_on(trx->mysql_thd)) { + if (wsrep_thd_is_wsrep(trx->mysql_thd)) { if (wsrep_debug && other_lock) { fprintf(stderr, "WSREP: InnoDB assert ignored\n"); @@ -2305,7 +2328,16 @@ lock_rec_add_to_queue( if (lock_get_wait(lock) && lock_rec_get_nth_bit(lock, heap_no)) { - +#ifdef WITH_WSREP + if (wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + if (wsrep_debug) { + fprintf(stderr, + "BF skipping wait: %lu\n", + trx->id); + lock_rec_print(stderr, lock); + } + } else +#endif goto somebody_waits; } } @@ -2503,8 +2535,8 @@ lock_rec_lock_slow( /* c_lock is NULL here if jump to enqueue_waiting happened but it's ok because lock is not NULL in that case and c_lock is not used. */ - err= - lock_rec_enqueue_waiting(c_lock, mode, block, heap_no, index, thr); + err = lock_rec_enqueue_waiting(c_lock, + mode, block, heap_no, index, thr); #else err = lock_rec_enqueue_waiting( mode, block, heap_no, index, thr); @@ -2614,7 +2646,13 @@ lock_rec_has_to_wait_in_queue( if (heap_no < lock_rec_get_n_bits(lock) && (p[bit_offset] & bit_mask) && lock_has_to_wait(wait_lock, lock)) { - +#ifdef WITH_WSREP + if (wsrep_thd_is_BF(wait_lock->trx->mysql_thd, FALSE) && + wsrep_thd_is_BF(lock->trx->mysql_thd, TRUE)) { + /* don't wait for another BF lock */ + continue; + } +#endif return(lock); } } @@ -3999,19 +4037,21 @@ lock_deadlock_select_victim( choose it as the victim and roll it back. */ #ifdef WITH_WSREP - if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) - return(ctx->wait_lock->trx); - else + if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) { + return(ctx->wait_lock->trx); + } + else #endif /* WITH_WSREP */ - return(ctx->start); + return(ctx->start); } #ifdef WITH_WSREP - if (wsrep_thd_is_BF(ctx->wait_lock->trx->mysql_thd, TRUE)) + if (wsrep_thd_is_BF(ctx->wait_lock->trx->mysql_thd, TRUE)) { return(ctx->start); + } else #endif /* WITH_WSREP */ - return(ctx->wait_lock->trx); + return(ctx->wait_lock->trx); } /********************************************************************//** @@ -4141,12 +4181,13 @@ lock_deadlock_search( ctx->too_deep = TRUE; #ifdef WITH_WSREP - if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) + if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) { return(ctx->wait_lock->trx->id); + } else #endif /* WITH_WSREP */ /* Select the joining transaction as the victim. */ - return(ctx->start->id); + return(ctx->start->id); } else if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { @@ -4383,42 +4424,54 @@ lock_table_create( UT_LIST_ADD_LAST(trx_locks, trx->lock.trx_locks, lock); #ifdef WITH_WSREP - if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { - UT_LIST_INSERT_AFTER( - un_member.tab_lock.locks, table->locks, c_lock, lock); - } else { - UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); - } - - if (c_lock) trx_mutex_enter(c_lock->trx); - if (c_lock && c_lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { - - c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE; - - if (wsrep_debug) wsrep_print_wait_locks(c_lock); - - /* have to release trx mutex for the duration of - victim lock release. This will eventually call - lock_grant, which wants to grant trx mutex again - */ - /* caller has trx_mutex, have to release for lock cancel */ - trx_mutex_exit(trx); - lock_cancel_waiting_and_release(c_lock->trx->lock.wait_lock); - trx_mutex_enter(trx); - - /* trx might not wait for c_lock, but some other lock - does not matter if wait_lock was released above - */ - if (c_lock->trx->lock.wait_lock == c_lock) { - lock_reset_lock_and_trx_wait(lock); + if (wsrep_thd_is_wsrep(trx->mysql_thd)) { + if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + UT_LIST_INSERT_AFTER( + un_member.tab_lock.locks, table->locks, c_lock, lock); + } else { + UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); } - if (wsrep_debug) { - fprintf(stderr, "WSREP: c_lock canceled %llu\n", - (ulonglong) c_lock->trx->id); + if (c_lock) { + trx_mutex_enter(c_lock->trx); } + + if (c_lock && c_lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { + + c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE; + + if (wsrep_debug) { + wsrep_print_wait_locks(c_lock); + wsrep_print_wait_locks(c_lock->trx->lock.wait_lock); + } + + /* have to release trx mutex for the duration of + victim lock release. This will eventually call + lock_grant, which wants to grant trx mutex again + */ + /* caller has trx_mutex, have to release for lock cancel */ + trx_mutex_exit(trx); + lock_cancel_waiting_and_release(c_lock->trx->lock.wait_lock); + trx_mutex_enter(trx); + + /* trx might not wait for c_lock, but some other lock + does not matter if wait_lock was released above + */ + if (c_lock->trx->lock.wait_lock == c_lock) { + lock_reset_lock_and_trx_wait(lock); + } + + if (wsrep_debug) { + fprintf(stderr, "WSREP: c_lock canceled %llu\n", + (ulonglong) c_lock->trx->id); + } + } + if (c_lock) { + trx_mutex_exit(c_lock->trx); + } + } else { + UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); } - if (c_lock) trx_mutex_exit(c_lock->trx); #else UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); #endif /* WITH_WSREP */ @@ -4705,11 +4758,15 @@ lock_table_other_has_incompatible( && (wait || !lock_get_wait(lock))) { #ifdef WITH_WSREP - if (wsrep_debug) - fprintf(stderr, "WSREP: table lock abort"); - trx_mutex_enter(lock->trx); - wsrep_kill_victim((trx_t *)trx, (lock_t *)lock); - trx_mutex_exit(lock->trx); + if(wsrep_thd_is_wsrep(trx->mysql_thd)) { + if (wsrep_debug) { + fprintf(stderr, "WSREP: trx %ld table lock abort\n", + trx->id); + } + trx_mutex_enter(lock->trx); + wsrep_kill_victim((trx_t *)trx, (lock_t *)lock); + trx_mutex_exit(lock->trx); + } #endif return(lock); @@ -5965,15 +6022,17 @@ lock_rec_queue_validate( if (!lock_rec_get_gap(lock) && !lock_get_wait(lock)) { #ifndef WITH_WSREP - enum lock_mode mode; + if (wsrep_thd_is_wsrep(lock->trx->mysql_thd)) { + enum lock_mode mode; - if (lock_get_mode(lock) == LOCK_S) { - mode = LOCK_X; - } else { - mode = LOCK_S; + if (lock_get_mode(lock) == LOCK_S) { + mode = LOCK_X; + } else { + mode = LOCK_S; + } + ut_a(!lock_rec_other_has_expl_req( + mode, 0, 0, block, heap_no, lock->trx)); } - ut_a(!lock_rec_other_has_expl_req( - mode, 0, 0, block, heap_no, lock->trx)); #endif /* WITH_WSREP */ } else if (lock_get_wait(lock) && !lock_rec_get_gap(lock)) { diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index 7cbd91b65cd..adced7059e4 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -417,12 +417,9 @@ wsrep_row_upd_check_foreign_constraints( } if (foreign->referenced_table) { - mutex_enter(&(dict_sys->mutex)); - - (foreign->referenced_table - ->n_foreign_key_checks_running)++; - - mutex_exit(&(dict_sys->mutex)); + os_inc_counter(dict_sys->mutex, + foreign->referenced_table + ->n_foreign_key_checks_running); } /* NOTE that if the thread ends up waiting for a lock @@ -434,20 +431,14 @@ wsrep_row_upd_check_foreign_constraints( TRUE, foreign, table, entry, thr); if (foreign->referenced_table) { - mutex_enter(&(dict_sys->mutex)); - - ut_a(foreign->referenced_table - ->n_foreign_key_checks_running > 0); - - (foreign->referenced_table - ->n_foreign_key_checks_running)--; + os_dec_counter(dict_sys->mutex, + foreign->referenced_table + ->n_foreign_key_checks_running); if (opened == TRUE) { dict_table_close(foreign->referenced_table, TRUE, FALSE); opened = FALSE; } - - mutex_exit(&(dict_sys->mutex)); } if (err != DB_SUCCESS) { diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 73834705232..91322b91aa6 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -6204,7 +6204,7 @@ wsrep_innobase_mysql_sort( case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_VARCHAR: { - uchar tmp_str[REC_VERSION_56_MAX_INDEX_COL_LEN]; + uchar tmp_str[REC_VERSION_56_MAX_INDEX_COL_LEN] = {'\0'}; uint tmp_length = REC_VERSION_56_MAX_INDEX_COL_LEN; /* Use the charset number to pick the right charset struct for @@ -6243,11 +6243,11 @@ wsrep_innobase_mysql_sort( } else { /* strnxfrm will expand the destination string, protocols < 3 truncated the sorted sring - protocols > 3 gets full sorted sring + protocols >= 3 gets full sorted sring */ tmp_length = charset->coll->strnxfrm( charset, str, buf_length, - str_length, tmp_str, tmp_length, 0); + str_length, tmp_str, str_length, 0); DBUG_ASSERT(tmp_length <= buf_length); ret_length = tmp_length; } @@ -6790,6 +6790,7 @@ UNIV_INTERN uint wsrep_store_key_val_for_row( /*===============================*/ + THD* thd, TABLE* table, uint keynr, /*!< in: key number */ char* buff, /*!< in/out: buffer for the key value (in MySQL @@ -6804,25 +6805,33 @@ wsrep_store_key_val_for_row( char* buff_start = buff; enum_field_types mysql_type; Field* field; - + uint buff_space = buff_len; + DBUG_ENTER("wsrep_store_key_val_for_row"); memset(buff, 0, buff_len); *key_is_null = TRUE; for (; key_part != end; key_part++) { + uchar sorted[REC_VERSION_56_MAX_INDEX_COL_LEN] = {'\0'}; ibool part_is_null = FALSE; if (key_part->null_bit) { - if (record[key_part->null_offset] & - key_part->null_bit) { - *buff = 1; - part_is_null = TRUE; + if (buff_space > 0) { + if (record[key_part->null_offset] + & key_part->null_bit) { + *buff = 1; + part_is_null = TRUE; + } else { + *buff = 0; + } + buff++; + buff_space--; } else { - *buff = 0; + fprintf (stderr, "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); } - buff++; } if (!part_is_null) *key_is_null = FALSE; @@ -6842,8 +6851,15 @@ wsrep_store_key_val_for_row( key_len = key_part->length; if (part_is_null) { - buff += key_len + 2; - + true_len = key_len + 2; + if (true_len > buff_space) { + fprintf (stderr, + "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); + true_len = buff_space; + } + buff += true_len; + buff_space -= true_len; continue; } cs = field->charset(); @@ -6883,13 +6899,20 @@ wsrep_store_key_val_for_row( REC_VERSION_56_MAX_INDEX_COL_LEN); if (wsrep_protocol_version > 1) { - memcpy(buff, sorted, true_len); - /* Note that we always reserve the maximum possible - length of the true VARCHAR in the key value, though - only len first bytes after the 2 length bytes contain - actual data. The rest of the space was reset to zero - in the bzero() call above. */ - buff += true_len; + /* Note that we always reserve the maximum possible + length of the true VARCHAR in the key value, though + only len first bytes after the 2 length bytes contain + actual data. The rest of the space was reset to zero + in the bzero() call above. */ + if (true_len > buff_space) { + fprintf (stderr, + "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); + true_len = buff_space; + } + memcpy(buff, sorted, true_len); + buff += true_len; + buff_space -= true_len; } else { buff += key_len; } @@ -6913,7 +6936,15 @@ wsrep_store_key_val_for_row( key_len = key_part->length; if (part_is_null) { - buff += key_len + 2; + true_len = key_len + 2; + if (true_len > buff_space) { + fprintf (stderr, + "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); + true_len = buff_space; + } + buff += true_len; + buff_space -= true_len; continue; } @@ -6956,15 +6987,22 @@ wsrep_store_key_val_for_row( mysql_type, cs->number, sorted, true_len, REC_VERSION_56_MAX_INDEX_COL_LEN); - memcpy(buff, sorted, true_len); /* Note that we always reserve the maximum possible length of the BLOB prefix in the key value. */ if (wsrep_protocol_version > 1) { - buff += true_len; - } else { - buff += key_len; - } + if (true_len > buff_space) { + fprintf (stderr, + "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); + true_len = buff_space; + } + buff += true_len; + buff_space -= true_len; + } else { + buff += key_len; + } + memcpy(buff, sorted, true_len); } else { /* Here we handle all other data types except the true VARCHAR, BLOB and TEXT. Note that the column @@ -6981,9 +7019,17 @@ wsrep_store_key_val_for_row( key_len = key_part->length; if (part_is_null) { - buff += key_len; + true_len = key_len; + if (true_len > buff_space) { + fprintf (stderr, + "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); + true_len = buff_space; + } + buff += true_len; + buff_space -= true_len; - continue; + continue; } src_start = record + key_part->offset; @@ -7021,12 +7067,18 @@ wsrep_store_key_val_for_row( mysql_type, cs->number, sorted, true_len, REC_VERSION_56_MAX_INDEX_COL_LEN); + if (true_len > buff_space) { + fprintf (stderr, + "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); + true_len = buff_space; + } memcpy(buff, sorted, true_len); } else { memcpy(buff, src_start, true_len); } - buff += true_len; - + buff += true_len; + buff_space -= true_len; } } @@ -10223,7 +10275,7 @@ wsrep_append_key( DBUG_ENTER("wsrep_append_key"); bool const copy = true; #ifdef WSREP_DEBUG_PRINT - fprintf(stderr, "%s conn %ld, trx %llu, keylen %d, table %s ", + fprintf(stderr, "%s conn %ld, trx %lu, keylen %d, table %s ", (shared) ? "Shared" : "Exclusive", wsrep_thd_thread_id(thd), (long long)trx->id, key_len, table_share->table_name.str); @@ -10293,11 +10345,11 @@ ha_innobase::wsrep_append_keys( uint len; char keyval[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; char *key = &keyval[0]; - KEY *key_info = table->key_info; ibool is_null; len = wsrep_store_key_val_for_row( - table, 0, key, key_info->key_length, record0, &is_null); + thd, table, 0, key, WSREP_MAX_SUPPORTED_KEY_LENGTH, + record0, &is_null); if (!is_null) { rcode = wsrep_append_key( @@ -10319,9 +10371,6 @@ ha_innobase::wsrep_append_keys( KEY* key_info = table->key_info + i; if (key_info->flags & HA_NOSAME) { hasPK = true; - if (i != table->s->primary_key) { - wsrep_thd_set_PA_safe(thd, FALSE); - } } } @@ -10352,7 +10401,8 @@ ha_innobase::wsrep_append_keys( (!tab && referenced_by_foreign_key()))) { len = wsrep_store_key_val_for_row( - table, i, key0, key_info->key_length, + thd, table, i, key0, + WSREP_MAX_SUPPORTED_KEY_LENGTH, record0, &is_null); if (!is_null) { rcode = wsrep_append_key( @@ -10362,7 +10412,6 @@ ha_innobase::wsrep_append_keys( if (key_info->flags & HA_NOSAME || shared) key_appended = true; - } else { @@ -10371,7 +10420,8 @@ ha_innobase::wsrep_append_keys( } if (record1) { len = wsrep_store_key_val_for_row( - table, i, key1, key_info->key_length, + thd, table, i, key1, + WSREP_MAX_SUPPORTED_KEY_LENGTH, record1, &is_null); if (!is_null && memcmp(key0, key1, len)) { rcode = wsrep_append_key( @@ -18472,7 +18522,7 @@ wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd, wsrep_thd_LOCK(victim_thd); wsrep_thd_set_conflict_state(victim_thd, MUST_ABORT); wsrep_thd_UNLOCK(victim_thd); - wsrep_thd_awake(victim_thd, signal); + wsrep_thd_awake(victim_thd, signal); } DBUG_RETURN(-1); } diff --git a/storage/xtradb/include/ha_prototypes.h b/storage/xtradb/include/ha_prototypes.h index 1dd109eb940..4ebaee3c89e 100644 --- a/storage/xtradb/include/ha_prototypes.h +++ b/storage/xtradb/include/ha_prototypes.h @@ -293,6 +293,7 @@ wsrep_innobase_kill_one_trx(void *thd_ptr, my_bool wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe); int wsrep_thd_conflict_state(void *thd_ptr, my_bool sync); my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync); +my_bool wsrep_thd_is_wsrep(void *thd_ptr); int wsrep_trx_order_before(void *thd1, void *thd2); int wsrep_innobase_mysql_sort(int mysql_type, uint charset_number, unsigned char* str, unsigned int str_length, diff --git a/storage/xtradb/include/hash0hash.h b/storage/xtradb/include/hash0hash.h index a6fe4e680a1..68d3c6ace4e 100644 --- a/storage/xtradb/include/hash0hash.h +++ b/storage/xtradb/include/hash0hash.h @@ -144,6 +144,33 @@ do {\ }\ } while (0) +#ifdef WITH_WSREP +/*******************************************************************//** +Inserts a struct to the head of hash table. */ + +#define HASH_PREPEND(TYPE, NAME, TABLE, FOLD, DATA) \ +do { \ + hash_cell_t* cell3333; \ + TYPE* struct3333; \ + \ + HASH_ASSERT_OWN(TABLE, FOLD) \ + \ + (DATA)->NAME = NULL; \ + \ + cell3333 = hash_get_nth_cell(TABLE, hash_calc_hash(FOLD, TABLE));\ + \ + if (cell3333->node == NULL) { \ + cell3333->node = DATA; \ + DATA->NAME = NULL; \ + } else { \ + struct3333 = (TYPE*) cell3333->node; \ + \ + DATA->NAME = struct3333; \ + \ + cell3333->node = DATA; \ + } \ +} while (0) +#endif /*WITH_WSREP */ #ifdef UNIV_HASH_DEBUG # define HASH_ASSERT_VALID(DATA) ut_a((void*) (DATA) != (void*) -1) # define HASH_INVALIDATE(DATA, NAME) *(void**) (&DATA->NAME) = (void*) -1 diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc index 0a9f4780c2e..8f7724daad9 100644 --- a/storage/xtradb/lock/lock0lock.cc +++ b/storage/xtradb/lock/lock0lock.cc @@ -1036,22 +1036,23 @@ lock_rec_has_to_wait( lock_rec_print(stderr, lock2); } - if (wsrep_trx_order_before(trx->mysql_thd, + if (wsrep_trx_order_before(trx->mysql_thd, lock2->trx->mysql_thd) && (type_mode & LOCK_MODE_MASK) == LOCK_X && (lock2->type_mode & LOCK_MODE_MASK) == LOCK_X) { /* exclusive lock conflicts are not accepted */ - fprintf(stderr, "BF-BF X lock conflict," - "type_mode: %lu supremum: %lu\n", + fprintf(stderr, "BF-BF X lock conflict," + "type_mode: %lu supremum: %lu\n", type_mode, lock_is_on_supremum); - fprintf(stderr, "conflicts states: my %d locked %d\n", - wsrep_thd_conflict_state(trx->mysql_thd, FALSE), + fprintf(stderr, "conflicts states: my %d locked %d\n", + wsrep_thd_conflict_state(trx->mysql_thd, FALSE), wsrep_thd_conflict_state(lock2->trx->mysql_thd, FALSE) ); lock_rec_print(stderr, lock2); - abort(); + return FALSE; + //abort(); } else { - /* if lock2->index->n_uniq <= + /* if lock2->index->n_uniq <= lock2->index->n_user_defined_cols operation is on uniq index */ @@ -1061,7 +1062,7 @@ lock_rec_has_to_wait( type_mode, lock2->type_mode, lock2->index->name, lock2->index->table_name, - lock2->index->n_uniq, + lock2->index->n_uniq, lock2->index->n_user_defined_cols); return FALSE; } @@ -1622,8 +1623,12 @@ lock_rec_other_has_expl_req( #endif /* UNIV_DEBUG */ #ifdef WITH_WSREP -static void -wsrep_kill_victim(const trx_t * const trx, const lock_t *lock) { +static +void +wsrep_kill_victim( + const trx_t * const trx, + const lock_t *lock) +{ ut_ad(lock_mutex_own()); ut_ad(trx_mutex_own(lock->trx)); my_bool bf_this = wsrep_thd_is_BF(trx->mysql_thd, FALSE); @@ -1632,32 +1637,38 @@ wsrep_kill_victim(const trx_t * const trx, const lock_t *lock) { if ((bf_this && !bf_other) || (bf_this && bf_other && wsrep_trx_order_before( trx->mysql_thd, lock->trx->mysql_thd))) { - + if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { - if (wsrep_debug) + if (wsrep_debug) { fprintf(stderr, "WSREP: BF victim waiting\n"); + } /* cannot release lock, until our lock is in the queue*/ } else if (lock->trx != trx) { if (wsrep_log_conflicts) { mutex_enter(&trx_sys->mutex); - if (bf_this) - fputs("\n*** Priority TRANSACTION:\n", + if (bf_this) { + fputs("\n*** Priority TRANSACTION:\n", stderr); - else - fputs("\n*** Victim TRANSACTION:\n", + } else { + fputs("\n*** Victim TRANSACTION:\n", stderr); + } + trx_print_latched(stderr, trx, 3000); - if (bf_other) - fputs("\n*** Priority TRANSACTION:\n", + if (bf_other) { + fputs("\n*** Priority TRANSACTION:\n", stderr); - else - fputs("\n*** Victim TRANSACTION:\n", + } else { + fputs("\n*** Victim TRANSACTION:\n", stderr); + } + trx_print_latched(stderr, lock->trx, 3000); mutex_exit(&trx_sys->mutex); + fputs("*** WAITING FOR THIS LOCK TO BE GRANTED:\n", stderr); @@ -1667,6 +1678,7 @@ wsrep_kill_victim(const trx_t * const trx, const lock_t *lock) { lock_table_print(stderr, lock); } } + wsrep_innobase_kill_one_trx(trx->mysql_thd, (const trx_t*) trx, lock->trx, TRUE); } @@ -2008,7 +2020,7 @@ lock_rec_create( ut_ad(index->table->n_ref_count > 0 || !index->table->can_be_evicted); #ifdef WITH_WSREP - if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { lock_t *hash = (lock_t *)c_lock->hash; lock_t *prev = NULL; @@ -2035,7 +2047,9 @@ lock_rec_create( c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE; - if (wsrep_debug) wsrep_print_wait_locks(c_lock); + if (wsrep_debug) { + wsrep_print_wait_locks(c_lock); + } trx->lock.que_state = TRX_QUE_LOCK_WAIT; lock_set_lock_and_trx_wait(lock, trx); @@ -2049,10 +2063,15 @@ lock_rec_create( victim lock release. This will eventually call lock_grant, which wants to grant trx mutex again */ - if (caller_owns_trx_mutex) trx_mutex_exit(trx); + if (caller_owns_trx_mutex) { + trx_mutex_exit(trx); + } lock_cancel_waiting_and_release( c_lock->trx->lock.wait_lock); - if (caller_owns_trx_mutex) trx_mutex_enter(trx); + + if (caller_owns_trx_mutex) { + trx_mutex_enter(trx); + } /* trx might not wait for c_lock, but some other lock does not matter if wait_lock was released above @@ -2060,17 +2079,23 @@ lock_rec_create( if (c_lock->trx->lock.wait_lock == c_lock) { lock_reset_lock_and_trx_wait(lock); } + trx_mutex_exit(c_lock->trx); - if (wsrep_debug) fprintf( - stderr, - "WSREP: c_lock canceled %llu\n", - (ulonglong) c_lock->trx->id); + if (wsrep_debug) { + fprintf( + stderr, + "WSREP: c_lock canceled %llu\n", + (ulonglong) c_lock->trx->id); + } /* have to bail out here to avoid lock_set_lock... */ return(lock); } trx_mutex_exit(c_lock->trx); + } else if (wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + HASH_PREPEND(lock_t, hash, lock_sys->rec_hash, + lock_rec_fold(space, page_no), lock); } else { HASH_INSERT(lock_t, hash, lock_sys->rec_hash, lock_rec_fold(space, page_no), lock); @@ -2088,7 +2113,6 @@ lock_rec_create( ut_ad(trx_mutex_own(trx)); if (type_mode & LOCK_WAIT) { - lock_set_lock_and_trx_wait(lock, trx); } @@ -2100,7 +2124,6 @@ lock_rec_create( MONITOR_INC(MONITOR_RECLOCK_CREATED); MONITOR_INC(MONITOR_NUM_RECLOCK); - return(lock); } @@ -2288,7 +2311,7 @@ lock_rec_add_to_queue( block, heap_no, trx->id); #ifdef WITH_WSREP /* this can potentionally assert with wsrep */ - if (wsrep_on(trx->mysql_thd)) { + if (wsrep_thd_is_wsrep(trx->mysql_thd)) { if (wsrep_debug && other_lock) { fprintf(stderr, "WSREP: InnoDB assert ignored\n"); @@ -2326,7 +2349,16 @@ lock_rec_add_to_queue( if (lock_get_wait(lock) && lock_rec_get_nth_bit(lock, heap_no)) { - +#ifdef WITH_WSREP + if (wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + if (wsrep_debug) { + fprintf(stderr, + "BF skipping wait: %lu\n", + trx->id); + lock_rec_print(stderr, lock); + } + } else +#endif goto somebody_waits; } } @@ -2526,8 +2558,8 @@ lock_rec_lock_slow( /* c_lock is NULL here if jump to enqueue_waiting happened but it's ok because lock is not NULL in that case and c_lock is not used. */ - err= - lock_rec_enqueue_waiting(c_lock, mode, block, heap_no, index, thr); + err = lock_rec_enqueue_waiting(c_lock, + mode, block, heap_no, index, thr); #else err = lock_rec_enqueue_waiting( mode, block, heap_no, index, thr); @@ -2638,7 +2670,13 @@ lock_rec_has_to_wait_in_queue( if (heap_no < lock_rec_get_n_bits(lock) && (p[bit_offset] & bit_mask) && lock_has_to_wait(wait_lock, lock)) { - +#ifdef WITH_WSREP + if (wsrep_thd_is_BF(wait_lock->trx->mysql_thd, FALSE) && + wsrep_thd_is_BF(lock->trx->mysql_thd, TRUE)) { + /* don't wait for another BF lock */ + continue; + } +#endif return(lock); } } @@ -4025,19 +4063,21 @@ lock_deadlock_select_victim( choose it as the victim and roll it back. */ #ifdef WITH_WSREP - if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) - return(ctx->wait_lock->trx); - else + if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) { + return(ctx->wait_lock->trx); + } + else #endif /* WITH_WSREP */ - return(ctx->start); + return(ctx->start); } #ifdef WITH_WSREP - if (wsrep_thd_is_BF(ctx->wait_lock->trx->mysql_thd, TRUE)) + if (wsrep_thd_is_BF(ctx->wait_lock->trx->mysql_thd, TRUE)) { return(ctx->start); + } else #endif /* WITH_WSREP */ - return(ctx->wait_lock->trx); + return(ctx->wait_lock->trx); } /********************************************************************//** @@ -4167,12 +4207,13 @@ lock_deadlock_search( ctx->too_deep = TRUE; #ifdef WITH_WSREP - if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) + if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) { return(ctx->wait_lock->trx->id); + } else #endif /* WITH_WSREP */ /* Select the joining transaction as the victim. */ - return(ctx->start->id); + return(ctx->start->id); } else if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { @@ -4411,42 +4452,54 @@ lock_table_create( UT_LIST_ADD_LAST(trx_locks, trx->lock.trx_locks, lock); #ifdef WITH_WSREP - if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { - UT_LIST_INSERT_AFTER( - un_member.tab_lock.locks, table->locks, c_lock, lock); - } else { - UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); - } - - if (c_lock) trx_mutex_enter(c_lock->trx); - if (c_lock && c_lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { - - c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE; - - if (wsrep_debug) wsrep_print_wait_locks(c_lock); - - /* have to release trx mutex for the duration of - victim lock release. This will eventually call - lock_grant, which wants to grant trx mutex again - */ - /* caller has trx_mutex, have to release for lock cancel */ - trx_mutex_exit(trx); - lock_cancel_waiting_and_release(c_lock->trx->lock.wait_lock); - trx_mutex_enter(trx); - - /* trx might not wait for c_lock, but some other lock - does not matter if wait_lock was released above - */ - if (c_lock->trx->lock.wait_lock == c_lock) { - lock_reset_lock_and_trx_wait(lock); + if (wsrep_thd_is_wsrep(trx->mysql_thd)) { + if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + UT_LIST_INSERT_AFTER( + un_member.tab_lock.locks, table->locks, c_lock, lock); + } else { + UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); } - if (wsrep_debug) { - fprintf(stderr, "WSREP: c_lock canceled %llu\n", - (ulonglong) c_lock->trx->id); + if (c_lock) { + trx_mutex_enter(c_lock->trx); } + + if (c_lock && c_lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { + + c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE; + + if (wsrep_debug) { + wsrep_print_wait_locks(c_lock); + wsrep_print_wait_locks(c_lock->trx->lock.wait_lock); + } + + /* have to release trx mutex for the duration of + victim lock release. This will eventually call + lock_grant, which wants to grant trx mutex again + */ + /* caller has trx_mutex, have to release for lock cancel */ + trx_mutex_exit(trx); + lock_cancel_waiting_and_release(c_lock->trx->lock.wait_lock); + trx_mutex_enter(trx); + + /* trx might not wait for c_lock, but some other lock + does not matter if wait_lock was released above + */ + if (c_lock->trx->lock.wait_lock == c_lock) { + lock_reset_lock_and_trx_wait(lock); + } + + if (wsrep_debug) { + fprintf(stderr, "WSREP: c_lock canceled %llu\n", + (ulonglong) c_lock->trx->id); + } + } + if (c_lock) { + trx_mutex_exit(c_lock->trx); + } + } else { + UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); } - if (c_lock) trx_mutex_exit(c_lock->trx); #else UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); #endif /* WITH_WSREP */ @@ -4740,11 +4793,15 @@ lock_table_other_has_incompatible( && (wait || !lock_get_wait(lock))) { #ifdef WITH_WSREP - if (wsrep_debug) - fprintf(stderr, "WSREP: table lock abort"); - trx_mutex_enter(lock->trx); - wsrep_kill_victim((trx_t *)trx, (lock_t *)lock); - trx_mutex_exit(lock->trx); + if(wsrep_thd_is_wsrep(trx->mysql_thd)) { + if (wsrep_debug) { + fprintf(stderr, "WSREP: trx %ld table lock abort\n", + trx->id); + } + trx_mutex_enter(lock->trx); + wsrep_kill_victim((trx_t *)trx, (lock_t *)lock); + trx_mutex_exit(lock->trx); + } #endif return(lock); @@ -6014,15 +6071,18 @@ lock_rec_queue_validate( if (!lock_rec_get_gap(lock) && !lock_get_wait(lock)) { #ifndef WITH_WSREP - enum lock_mode mode; + if (wsrep_thd_is_wsrep(lock->trx->mysql_thd)) { + enum lock_mode mode; - if (lock_get_mode(lock) == LOCK_S) { - mode = LOCK_X; - } else { - mode = LOCK_S; - } - ut_a(!lock_rec_other_has_expl_req( + + if (lock_get_mode(lock) == LOCK_S) { + mode = LOCK_X; + } else { + mode = LOCK_S; + } + ut_a(!lock_rec_other_has_expl_req( mode, 0, 0, block, heap_no, lock->trx->id)); + } #endif /* WITH_WSREP */ } else if (lock_get_wait(lock) && !lock_rec_get_gap(lock)) { diff --git a/storage/xtradb/row/row0upd.cc b/storage/xtradb/row/row0upd.cc index 4b8dff7b47f..bdd2a691368 100644 --- a/storage/xtradb/row/row0upd.cc +++ b/storage/xtradb/row/row0upd.cc @@ -419,12 +419,9 @@ wsrep_row_upd_check_foreign_constraints( } if (foreign->referenced_table) { - mutex_enter(&(dict_sys->mutex)); - - (foreign->referenced_table - ->n_foreign_key_checks_running)++; - - mutex_exit(&(dict_sys->mutex)); + os_inc_counter(dict_sys->mutex, + foreign->referenced_table + ->n_foreign_key_checks_running); } /* NOTE that if the thread ends up waiting for a lock @@ -436,20 +433,14 @@ wsrep_row_upd_check_foreign_constraints( TRUE, foreign, table, entry, thr); if (foreign->referenced_table) { - mutex_enter(&(dict_sys->mutex)); - - ut_a(foreign->referenced_table - ->n_foreign_key_checks_running > 0); - - (foreign->referenced_table - ->n_foreign_key_checks_running)--; + os_dec_counter(dict_sys->mutex, + foreign->referenced_table + ->n_foreign_key_checks_running); if (opened == TRUE) { dict_table_close(foreign->referenced_table, TRUE, FALSE); opened = FALSE; } - - mutex_exit(&(dict_sys->mutex)); } if (err != DB_SUCCESS) { diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh index d758f12d2ab..c98c8284a97 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -356,7 +356,10 @@ case "$mode" in # Stop the service and regardless of whether it was # running or not, start it again. if $0 stop $other_args; then - $0 start $other_args + if ! $0 start $other_args; then + log_failure_msg "Failed to restart server." + exit 1 + fi else log_failure_msg "Failed to stop running server, so refusing to try to start." exit 1 From bb11eb82d5dce664e151519577df173acb31ee91 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Tue, 26 Aug 2014 14:57:09 +0400 Subject: [PATCH 017/153] MDEV-6305 - UNINIT_VAR emits code in non-debug builds Reverted workaround for gcc bug, which was fixed 3 years ago: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34772 --- configure.cmake | 2 +- include/my_global.h | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/configure.cmake b/configure.cmake index 7ec87f6e9a8..4adc977b192 100644 --- a/configure.cmake +++ b/configure.cmake @@ -55,7 +55,7 @@ ENDIF() # Always enable -Wall for gnu C/C++ IF(CMAKE_COMPILER_IS_GNUCXX AND NOT CMAKE_CXX_FLAGS MATCHES ".*-Wall.*") - SET(CMAKE_CXX_FLAGS "-Wall ${CMAKE_CXX_FLAGS} -Wall -Wno-unused-parameter") + SET(CMAKE_CXX_FLAGS "-Wall ${CMAKE_CXX_FLAGS} -Wall -Wno-unused-parameter -Wno-init-self") ENDIF() IF(CMAKE_COMPILER_IS_GNUCC AND NOT CMAKE_C_FLAGS MATCHES ".*-Wall.*") SET(CMAKE_C_FLAGS "-Wall ${CMAKE_C_FLAGS} -Wall") diff --git a/include/my_global.h b/include/my_global.h index e9a472e686e..bec5fb027eb 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -480,16 +480,14 @@ extern "C" int madvise(void *addr, size_t len, int behav); /* Suppress uninitialized variable warning without generating code. - - The _cplusplus is a temporary workaround for C++ code pending a fix - for a g++ bug (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34772). */ -#if defined(_lint) || defined(FORCE_INIT_OF_VARS) || \ - defined(__cplusplus) || !defined(__GNUC__) -#define UNINIT_VAR(x) x= 0 -#else +#if defined(__GNUC__) /* GCC specific self-initialization which inhibits the warning. */ #define UNINIT_VAR(x) x= x +#elif defined(_lint) || defined(FORCE_INIT_OF_VARS) +#define UNINIT_VAR(x) x= 0 +#else +#define UNINIT_VAR(x) x #endif #if !defined(HAVE_UINT) From ea4103d94d4b4c298d55a7a0076d075aa4d45700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Tue, 26 Aug 2014 14:32:15 +0300 Subject: [PATCH 018/153] Add missing test files for new configuration variables. Added a new functions to handler API to forcefully abort_transaction, producing fake_trx_id, get_checkpoint and set_checkpoint for XA. These were added for future possiblity to add more storage engines that could use galera replication. --- .../r/innodb_disallow_writes_basic.result | 45 +++++++++++++++++++ .../r/wsrep_slave_fk_checks_basic.result | 45 +++++++++++++++++++ .../r/wsrep_slave_uk_checks_basic.result | 45 +++++++++++++++++++ .../t/innodb_disallow_writes_basic.test | 42 +++++++++++++++++ .../t/wsrep_slave_fk_checks_basic.test | 42 +++++++++++++++++ .../t/wsrep_slave_uk_checks_basic.test | 42 +++++++++++++++++ sql/handler.cc | 18 ++++---- sql/handler.h | 16 +++---- sql/sql_insert.cc | 2 +- sql/wsrep_mysqld.cc | 9 ++-- sql/wsrep_thd.cc | 2 +- storage/innobase/handler/ha_innodb.cc | 9 ++-- storage/xtradb/handler/ha_innodb.cc | 8 ++-- 13 files changed, 291 insertions(+), 34 deletions(-) create mode 100644 mysql-test/suite/sys_vars/r/innodb_disallow_writes_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_slave_fk_checks_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_slave_uk_checks_basic.result create mode 100644 mysql-test/suite/sys_vars/t/innodb_disallow_writes_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_slave_fk_checks_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_slave_uk_checks_basic.test diff --git a/mysql-test/suite/sys_vars/r/innodb_disallow_writes_basic.result b/mysql-test/suite/sys_vars/r/innodb_disallow_writes_basic.result new file mode 100644 index 00000000000..bfb6b67b5d8 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/innodb_disallow_writes_basic.result @@ -0,0 +1,45 @@ +# +# innodb_disallow_writes +# +# save the initial value +SET @innodb_disallow_writes_global_saved = @@global.innodb_disallow_writes; +# default +SELECT @@global.innodb_disallow_writes; +@@global.innodb_disallow_writes +0 + +# scope +SELECT @@session.innodb_disallow_writes; +ERROR HY000: Variable 'innodb_disallow_writes' is a GLOBAL variable +SET @@global.innodb_disallow_writes=OFF; +SELECT @@global.innodb_disallow_writes; +@@global.innodb_disallow_writes +0 +SET @@global.innodb_disallow_writes=ON; +SELECT @@global.innodb_disallow_writes; +@@global.innodb_disallow_writes +1 + +# valid values +SET @@global.innodb_disallow_writes='OFF'; +SELECT @@global.innodb_disallow_writes; +@@global.innodb_disallow_writes +0 +SET @@global.innodb_disallow_writes=ON; +SELECT @@global.innodb_disallow_writes; +@@global.innodb_disallow_writes +1 +SET @@global.innodb_disallow_writes=default; +SELECT @@global.innodb_disallow_writes; +@@global.innodb_disallow_writes +0 + +# invalid values +SET @@global.innodb_disallow_writes=NULL; +ERROR 42000: Variable 'innodb_disallow_writes' can't be set to the value of 'NULL' +SET @@global.innodb_disallow_writes='junk'; +ERROR 42000: Variable 'innodb_disallow_writes' can't be set to the value of 'junk' + +# restore the initial value +SET @@global.innodb_disallow_writes = @innodb_disallow_writes_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_slave_fk_checks_basic.result b/mysql-test/suite/sys_vars/r/wsrep_slave_fk_checks_basic.result new file mode 100644 index 00000000000..40b3270e221 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_slave_fk_checks_basic.result @@ -0,0 +1,45 @@ +# +# wsrep_slave_fk_checks +# +# save the initial value +SET @wsrep_slave_fk_checks_global_saved = @@global.wsrep_slave_fk_checks; +# default +SELECT @@global.wsrep_slave_fk_checks; +@@global.wsrep_slave_fk_checks +1 + +# scope +SELECT @@session.wsrep_slave_fk_checks; +ERROR HY000: Variable 'wsrep_slave_FK_checks' is a GLOBAL variable +SET @@global.wsrep_slave_fk_checks=OFF; +SELECT @@global.wsrep_slave_fk_checks; +@@global.wsrep_slave_fk_checks +0 +SET @@global.wsrep_slave_fk_checks=ON; +SELECT @@global.wsrep_slave_fk_checks; +@@global.wsrep_slave_fk_checks +1 + +# valid values +SET @@global.wsrep_slave_fk_checks='OFF'; +SELECT @@global.wsrep_slave_fk_checks; +@@global.wsrep_slave_fk_checks +0 +SET @@global.wsrep_slave_fk_checks=ON; +SELECT @@global.wsrep_slave_fk_checks; +@@global.wsrep_slave_fk_checks +1 +SET @@global.wsrep_slave_fk_checks=default; +SELECT @@global.wsrep_slave_fk_checks; +@@global.wsrep_slave_fk_checks +1 + +# invalid values +SET @@global.wsrep_slave_fk_checks=NULL; +ERROR 42000: Variable 'wsrep_slave_FK_checks' can't be set to the value of 'NULL' +SET @@global.wsrep_slave_fk_checks='junk'; +ERROR 42000: Variable 'wsrep_slave_FK_checks' can't be set to the value of 'junk' + +# restore the initial value +SET @@global.wsrep_slave_fk_checks = @wsrep_slave_fk_checks_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_slave_uk_checks_basic.result b/mysql-test/suite/sys_vars/r/wsrep_slave_uk_checks_basic.result new file mode 100644 index 00000000000..b78a83b547d --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_slave_uk_checks_basic.result @@ -0,0 +1,45 @@ +# +# wsrep_slave_uk_checks +# +# save the initial value +SET @wsrep_slave_uk_checks_global_saved = @@global.wsrep_slave_uk_checks; +# default +SELECT @@global.wsrep_slave_uk_checks; +@@global.wsrep_slave_uk_checks +0 + +# scope +SELECT @@session.wsrep_slave_uk_checks; +ERROR HY000: Variable 'wsrep_slave_UK_checks' is a GLOBAL variable +SET @@global.wsrep_slave_uk_checks=OFF; +SELECT @@global.wsrep_slave_uk_checks; +@@global.wsrep_slave_uk_checks +0 +SET @@global.wsrep_slave_uk_checks=ON; +SELECT @@global.wsrep_slave_uk_checks; +@@global.wsrep_slave_uk_checks +1 + +# valid values +SET @@global.wsrep_slave_uk_checks='OFF'; +SELECT @@global.wsrep_slave_uk_checks; +@@global.wsrep_slave_uk_checks +0 +SET @@global.wsrep_slave_uk_checks=ON; +SELECT @@global.wsrep_slave_uk_checks; +@@global.wsrep_slave_uk_checks +1 +SET @@global.wsrep_slave_uk_checks=default; +SELECT @@global.wsrep_slave_uk_checks; +@@global.wsrep_slave_uk_checks +0 + +# invalid values +SET @@global.wsrep_slave_uk_checks=NULL; +ERROR 42000: Variable 'wsrep_slave_UK_checks' can't be set to the value of 'NULL' +SET @@global.wsrep_slave_uk_checks='junk'; +ERROR 42000: Variable 'wsrep_slave_UK_checks' can't be set to the value of 'junk' + +# restore the initial value +SET @@global.wsrep_slave_uk_checks = @wsrep_slave_uk_checks_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/t/innodb_disallow_writes_basic.test b/mysql-test/suite/sys_vars/t/innodb_disallow_writes_basic.test new file mode 100644 index 00000000000..b8e5c127377 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_disallow_writes_basic.test @@ -0,0 +1,42 @@ +--source include/have_innodb_disallow_writes.inc + +--echo # +--echo # innodb_disallow_writes +--echo # + +--echo # save the initial value +SET @innodb_disallow_writes_global_saved = @@global.innodb_disallow_writes; + +--echo # default +SELECT @@global.innodb_disallow_writes; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.innodb_disallow_writes; +SET @@global.innodb_disallow_writes=OFF; +SELECT @@global.innodb_disallow_writes; +SET @@global.innodb_disallow_writes=ON; +SELECT @@global.innodb_disallow_writes; + +--echo +--echo # valid values +SET @@global.innodb_disallow_writes='OFF'; +SELECT @@global.innodb_disallow_writes; +SET @@global.innodb_disallow_writes=ON; +SELECT @@global.innodb_disallow_writes; +SET @@global.innodb_disallow_writes=default; +SELECT @@global.innodb_disallow_writes; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.innodb_disallow_writes=NULL; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.innodb_disallow_writes='junk'; + +--echo +--echo # restore the initial value +SET @@global.innodb_disallow_writes = @innodb_disallow_writes_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_slave_fk_checks_basic.test b/mysql-test/suite/sys_vars/t/wsrep_slave_fk_checks_basic.test new file mode 100644 index 00000000000..dd60eb8694b --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_slave_fk_checks_basic.test @@ -0,0 +1,42 @@ +--source include/have_wsrep.inc + +--echo # +--echo # wsrep_slave_fk_checks +--echo # + +--echo # save the initial value +SET @wsrep_slave_fk_checks_global_saved = @@global.wsrep_slave_fk_checks; + +--echo # default +SELECT @@global.wsrep_slave_fk_checks; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_slave_fk_checks; +SET @@global.wsrep_slave_fk_checks=OFF; +SELECT @@global.wsrep_slave_fk_checks; +SET @@global.wsrep_slave_fk_checks=ON; +SELECT @@global.wsrep_slave_fk_checks; + +--echo +--echo # valid values +SET @@global.wsrep_slave_fk_checks='OFF'; +SELECT @@global.wsrep_slave_fk_checks; +SET @@global.wsrep_slave_fk_checks=ON; +SELECT @@global.wsrep_slave_fk_checks; +SET @@global.wsrep_slave_fk_checks=default; +SELECT @@global.wsrep_slave_fk_checks; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_slave_fk_checks=NULL; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_slave_fk_checks='junk'; + +--echo +--echo # restore the initial value +SET @@global.wsrep_slave_fk_checks = @wsrep_slave_fk_checks_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_slave_uk_checks_basic.test b/mysql-test/suite/sys_vars/t/wsrep_slave_uk_checks_basic.test new file mode 100644 index 00000000000..c9012954371 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_slave_uk_checks_basic.test @@ -0,0 +1,42 @@ +--source include/have_wsrep.inc + +--echo # +--echo # wsrep_slave_uk_checks +--echo # + +--echo # save the initial value +SET @wsrep_slave_uk_checks_global_saved = @@global.wsrep_slave_uk_checks; + +--echo # default +SELECT @@global.wsrep_slave_uk_checks; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_slave_uk_checks; +SET @@global.wsrep_slave_uk_checks=OFF; +SELECT @@global.wsrep_slave_uk_checks; +SET @@global.wsrep_slave_uk_checks=ON; +SELECT @@global.wsrep_slave_uk_checks; + +--echo +--echo # valid values +SET @@global.wsrep_slave_uk_checks='OFF'; +SELECT @@global.wsrep_slave_uk_checks; +SET @@global.wsrep_slave_uk_checks=ON; +SELECT @@global.wsrep_slave_uk_checks; +SET @@global.wsrep_slave_uk_checks=default; +SELECT @@global.wsrep_slave_uk_checks; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_slave_uk_checks=NULL; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_slave_uk_checks='junk'; + +--echo +--echo # restore the initial value +SET @@global.wsrep_slave_uk_checks = @wsrep_slave_uk_checks_global_saved; + +--echo # End of test diff --git a/sql/handler.cc b/sql/handler.cc index e8c3a823a41..63ddb9c6d6e 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6212,9 +6212,9 @@ void handler::set_lock_type(enum thr_lock_type lock) always 0 */ -int ha_wsrep_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal) +int ha_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal) { - DBUG_ENTER("ha_wsrep_abort_transaction"); + DBUG_ENTER("ha_abort_transaction"); if (!WSREP(bf_thd) && !(wsrep_OSU_method_options == WSREP_OSU_RSU && bf_thd->wsrep_exec_mode == TOTAL_ORDER)) { @@ -6227,21 +6227,21 @@ int ha_wsrep_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal) for (; ha_info; ha_info= ha_info_next) { handlerton *hton= ha_info->ht(); - if (!hton->wsrep_abort_transaction) + if (!hton->abort_transaction) { - WSREP_WARN("cannot abort WRESP transaction"); + WSREP_WARN("cannot abort transaction"); } else - hton->wsrep_abort_transaction(hton, bf_thd, victim_thd, signal); + hton->abort_transaction(hton, bf_thd, victim_thd, signal); ha_info_next= ha_info->next(); ha_info->reset(); /* keep it conveniently zero-filled */ } DBUG_RETURN(0); } -void ha_wsrep_fake_trx_id(THD *thd) +void ha_fake_trx_id(THD *thd) { - DBUG_ENTER("ha_wsrep_fake_trx_id"); + DBUG_ENTER("ha_fake_trx_id"); if (!WSREP(thd)) { DBUG_VOID_RETURN; @@ -6253,12 +6253,12 @@ void ha_wsrep_fake_trx_id(THD *thd) for (; ha_info; ha_info= ha_info_next) { handlerton *hton= ha_info->ht(); - if (!hton->wsrep_fake_trx_id) + if (!hton->fake_trx_id) { WSREP_WARN("cannot get fake InnoDB transaction ID"); } else - hton->wsrep_fake_trx_id(hton, thd); + hton->fake_trx_id(hton, thd); ha_info_next= ha_info->next(); ha_info->reset(); /* keep it conveniently zero-filled */ } diff --git a/sql/handler.h b/sql/handler.h index 9622cef3a11..169ed209403 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1230,13 +1230,11 @@ struct handlerton enum handler_create_iterator_result (*create_iterator)(handlerton *hton, enum handler_iterator_type type, struct handler_iterator *fill_this_in); -#ifdef WITH_WSREP - int (*wsrep_abort_transaction)(handlerton *hton, THD *bf_thd, - THD *victim_thd, my_bool signal); - int (*wsrep_set_checkpoint)(handlerton *hton, const XID* xid); - int (*wsrep_get_checkpoint)(handlerton *hton, XID* xid); - void (*wsrep_fake_trx_id)(handlerton *hton, THD *thd); -#endif /* WITH_WSREP */ + int (*abort_transaction)(handlerton *hton, THD *bf_thd, + THD *victim_thd, my_bool signal); + int (*set_checkpoint)(handlerton *hton, const XID* xid); + int (*get_checkpoint)(handlerton *hton, XID* xid); + void (*fake_trx_id)(handlerton *hton, THD *thd); /* Optional clauses in the CREATE/ALTER TABLE */ @@ -4091,8 +4089,8 @@ bool ha_rollback_to_savepoint_can_release_mdl(THD *thd); int ha_savepoint(THD *thd, SAVEPOINT *sv); int ha_release_savepoint(THD *thd, SAVEPOINT *sv); #ifdef WITH_WSREP -int ha_wsrep_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal); -void ha_wsrep_fake_trx_id(THD *thd); +int ha_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal); +void ha_fake_trx_id(THD *thd); #endif /* WITH_WSREP */ /* these are called by storage engines */ diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 5ee341435cf..f90e9cd2439 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -4194,7 +4194,7 @@ select_create::binlog_show_create_table(TABLE **tables, uint count) errcode); } - IF_WSREP(ha_wsrep_fake_trx_id(thd), ); + IF_WSREP(ha_fake_trx_id(thd), ); return result; } diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index a8157082038..c1b15bd02c2 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -176,14 +176,14 @@ static my_bool set_SE_checkpoint(THD* unused, plugin_ref plugin, void* arg) { XID* xid= reinterpret_cast(arg); handlerton* hton= plugin_data(plugin, handlerton *); - if (hton->db_type == DB_TYPE_INNODB) + if (hton->set_checkpoint) { const wsrep_uuid_t* uuid(wsrep_xid_uuid(xid)); char uuid_str[40] = {0, }; wsrep_uuid_print(uuid, uuid_str, sizeof(uuid_str)); WSREP_DEBUG("Set WSREPXid for InnoDB: %s:%lld", uuid_str, (long long)wsrep_xid_seqno(xid)); - hton->wsrep_set_checkpoint(hton, xid); + hton->set_checkpoint(hton, xid); } return FALSE; } @@ -197,15 +197,14 @@ static my_bool get_SE_checkpoint(THD* unused, plugin_ref plugin, void* arg) { XID* xid= reinterpret_cast(arg); handlerton* hton= plugin_data(plugin, handlerton *); - if (hton->db_type == DB_TYPE_INNODB) + if (hton->get_checkpoint) { - hton->wsrep_get_checkpoint(hton, xid); + hton->get_checkpoint(hton, xid); const wsrep_uuid_t* uuid(wsrep_xid_uuid(xid)); char uuid_str[40] = {0, }; wsrep_uuid_print(uuid, uuid_str, sizeof(uuid_str)); WSREP_DEBUG("Read WSREPXid from InnoDB: %s:%lld", uuid_str, (long long)wsrep_xid_seqno(xid)); - } return FALSE; } diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc index 6fc91c9fa31..fabced2d11a 100644 --- a/sql/wsrep_thd.cc +++ b/sql/wsrep_thd.cc @@ -581,7 +581,7 @@ int wsrep_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr, my_bool signal) { WSREP_DEBUG("wsrep_abort_thd, by: %llu, victim: %llu", (bf_thd) ? (long long)bf_thd->real_id : 0, (long long)victim_thd->real_id); - ha_wsrep_abort_transaction(bf_thd, victim_thd, signal); + ha_abort_transaction(bf_thd, victim_thd, signal); } else { diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index a5a0616dc63..970127a7420 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -3018,10 +3018,10 @@ innobase_init( innobase_hton->release_temporary_latches = innobase_release_temporary_latches; #ifdef WITH_WSREP - innobase_hton->wsrep_abort_transaction=wsrep_abort_transaction; - innobase_hton->wsrep_set_checkpoint=innobase_wsrep_set_checkpoint; - innobase_hton->wsrep_get_checkpoint=innobase_wsrep_get_checkpoint; - innobase_hton->wsrep_fake_trx_id=wsrep_fake_trx_id; + innobase_hton->abort_transaction=wsrep_abort_transaction; + innobase_hton->set_checkpoint=innobase_wsrep_set_checkpoint; + innobase_hton->get_checkpoint=innobase_wsrep_get_checkpoint; + innobase_hton->fake_trx_id=wsrep_fake_trx_id; #endif /* WITH_WSREP */ innobase_hton->kill_query = innobase_kill_query; @@ -9830,7 +9830,6 @@ ha_innobase::wsrep_append_keys( uint len; char keyval[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; char *key = &keyval[0]; - KEY *key_info = table->key_info; ibool is_null; len = wsrep_store_key_val_for_row( diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 91322b91aa6..4c4bccd15e1 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -3373,10 +3373,10 @@ innobase_init( innobase_hton->table_options = innodb_table_option_list; #ifdef WITH_WSREP - innobase_hton->wsrep_abort_transaction=wsrep_abort_transaction; - innobase_hton->wsrep_set_checkpoint=innobase_wsrep_set_checkpoint; - innobase_hton->wsrep_get_checkpoint=innobase_wsrep_get_checkpoint; - innobase_hton->wsrep_fake_trx_id=wsrep_fake_trx_id; + innobase_hton->abort_transaction=wsrep_abort_transaction; + innobase_hton->set_checkpoint=innobase_wsrep_set_checkpoint; + innobase_hton->get_checkpoint=innobase_wsrep_get_checkpoint; + innobase_hton->fake_trx_id=wsrep_fake_trx_id; #endif /* WITH_WSREP */ ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR); From 9534fd83ce6dc402132cc304c121c9205b430dda Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Tue, 26 Aug 2014 16:24:40 +0400 Subject: [PATCH 019/153] MDEV-6634: Wrong estimates for ref(const): Update test result --- mysql-test/r/join_outer_jcl6.result | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/mysql-test/r/join_outer_jcl6.result b/mysql-test/r/join_outer_jcl6.result index 88f2fd7c630..862fc194a7a 100644 --- a/mysql-test/r/join_outer_jcl6.result +++ b/mysql-test/r/join_outer_jcl6.result @@ -2233,6 +2233,34 @@ id select_type table type possible_keys key key_len ref rows filtered Extra Warnings: Note 1003 select `test`.`t1`.`i1` AS `i1`,`test`.`t2`.`i2` AS `i2`,`test`.`t3`.`i3` AS `i3`,`test`.`t3`.`d3` AS `d3` from `test`.`t1` left join (`test`.`t2` join `test`.`t3`) on(((`test`.`t2`.`i2` = `test`.`t1`.`i1`) and (`test`.`t3`.`i3` = `test`.`t1`.`i1`))) where ((`test`.`t3`.`d3` = 0) or isnull(`test`.`t3`.`d3`)) DROP TABLE t1,t2,t3; +# +# MDEV-6634: Wrong estimates for ref(const) and key IS NULL predicate +# +create table t1(a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2 (a int, b int, c int, key(b), key(c)); +insert into t2 select +@a:=A.a + 10*B.a+100*C.a, +IF(@a<900, NULL, @a), +IF(@a<500, NULL, @a) +from t1 A, t1 B, t1 C; +delete from t1 where a=0; +# Check that there are different #rows of NULLs for b and c, both !=10: +explain select * from t2 force index (b) where b is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ref b b 5 const 780 Using index condition +explain select * from t2 force index (c) where c is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ref c c 5 const 393 Using index condition +explain select * from t1 left join t2 on t2.b is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 9 +1 SIMPLE t2 ref b b 5 const 780 Using where +explain select * from t1 left join t2 on t2.c is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 9 +1 SIMPLE t2 ref c c 5 const 393 Using where +drop table t1,t2; SET optimizer_switch=@save_optimizer_switch; set join_cache_level=default; show variables like 'join_cache_level'; From df4dd593f29aec8e2116aec1775ad4b8833d8c93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 6 Aug 2014 15:39:15 +0300 Subject: [PATCH 020/153] MDEV-6247: Merge 10.0-galera to 10.1. Merged lp:maria/maria-10.0-galera up to revision 3879. Added a new functions to handler API to forcefully abort_transaction, producing fake_trx_id, get_checkpoint and set_checkpoint for XA. These were added for future possiblity to add more storage engines that could use galera replication. --- .bzrignore | 1 + BUILD/SETUP.sh | 2 +- BUILD/compile-amd64-debug-wsrep | 11 + BUILD/compile-amd64-wsrep | 9 + BUILD/compile-pentium-debug-wsrep | 12 + BUILD/compile-pentium-wsrep | 11 + BUILD/compile-pentium64-wsrep | 28 + CMakeLists.txt | 11 + Docs/README-wsrep | 488 ++++ client/client_priv.h | 1 + client/mysql_upgrade.c | 5 + client/mysqlcheck.c | 6 + client/mysqldump.c | 49 + cmake/cpack_rpm.cmake | 7 +- cmake/plugin.cmake | 22 +- cmake/wsrep.cmake | 76 + debian/dist/Debian/control | 2 +- debian/dist/Ubuntu/control | 2 +- include/mysql/service_logger.h | 2 +- include/mysqld_default_groups.h | 3 + include/thr_lock.h | 13 +- include/wsrep.h | 58 + mysql-test/extra/binlog_tests/binlog.test | 9 +- mysql-test/include/galera_cluster.inc | 10 + mysql-test/include/galera_connect.inc | 45 + mysql-test/include/galera_diff.inc | 100 + mysql-test/include/galera_end.inc | 25 + mysql-test/include/galera_init.inc | 26 + .../include/have_innodb_disallow_writes.inc | 6 + mysql-test/include/have_wsrep.inc | 8 + mysql-test/include/have_wsrep_enabled.inc | 9 + mysql-test/include/mtr_check.sql | 1 + mysql-test/include/mtr_warnings.sql | 8 + mysql-test/include/not_wsrep.inc | 7 + mysql-test/include/write_result_to_file.inc | 3 +- mysql-test/lib/My/ConfigFactory.pm | 3 + mysql-test/lib/mtr_cases.pm | 3 + mysql-test/mysql-test-run.pl | 58 + mysql-test/r/have_wsrep.require | 2 + .../r/mysql_tzinfo_to_sql_symlink.result | 1 + mysql-test/r/mysqld--help.result | 125 + mysql-test/r/not_wsrep.require | 2 + .../suite/binlog/r/binlog_row_binlog.result | 12 +- .../suite/binlog/r/binlog_stm_binlog.result | 12 +- mysql-test/suite/galera/galera_2nodes.cnf | 24 + mysql-test/suite/galera/my.cnf | 1 + mysql-test/suite/galera/r/basic.result | 30 + .../suite/galera/r/galera_sst_mode.result | 24 + mysql-test/suite/galera/r/grant.result | 17 + mysql-test/suite/galera/r/partition.result | 23 + mysql-test/suite/galera/r/unique_key.result | 47 + mysql-test/suite/galera/t/basic.test | 26 + .../suite/galera/t/galera_sst_mode.test | 43 + mysql-test/suite/galera/t/grant.test | 25 + mysql-test/suite/galera/t/partition.test | 31 + mysql-test/suite/galera/t/unique_key.test | 54 + .../suite/innodb/r/innodb-autoinc.result | 44 +- mysql-test/suite/innodb/t/innodb-autoinc.test | 44 +- .../suite/parts/r/partition_exch_qa_10.result | 2 +- .../suite/parts/t/partition_exch_qa_10.test | 2 +- .../suite/percona/innodb_sys_index.result | 2 +- .../suite/percona/innodb_sys_index.test | 3 +- .../suite/perfschema/r/rpl_statements.result | 6 +- .../suite/perfschema/t/rpl_statements.test | 4 +- .../r/innodb_disallow_writes_basic.result | 45 + .../wsrep_auto_increment_control_basic.result | 8 + .../r/wsrep_causal_reads_basic.result | 8 + .../r/wsrep_certify_nonpk_basic.result | 8 + .../r/wsrep_cluster_address_basic.result | 45 + .../r/wsrep_cluster_name_basic.result | 7 + .../r/wsrep_convert_lock_to_trx_basic.result | 8 + .../r/wsrep_data_home_dir_basic.result | 48 + .../sys_vars/r/wsrep_dbug_option_basic.result | 6 + .../suite/sys_vars/r/wsrep_debug_basic.result | 8 + .../sys_vars/r/wsrep_desync_basic.result | 3 + ...srep_drupal_282555_workaround_basic.result | 8 + .../r/wsrep_forced_binlog_format_basic.result | 8 + .../r/wsrep_load_data_splitting_basic.result | 8 + .../r/wsrep_log_conflicts_basic.result | 8 + .../sys_vars/r/wsrep_max_ws_rows_basic.result | 17 + .../sys_vars/r/wsrep_max_ws_size_basic.result | 17 + ...srep_mysql_replication_bundle_basic.result | 18 + .../r/wsrep_node_address_basic.result | 45 + .../wsrep_node_incoming_address_basic.result | 45 + .../sys_vars/r/wsrep_node_name_basic.result | 6 + .../sys_vars/r/wsrep_notify_cmd_basic.result | 6 + .../suite/sys_vars/r/wsrep_on_basic.result | 8 + .../sys_vars/r/wsrep_osu_method_basic.result | 12 + .../sys_vars/r/wsrep_provider_basic.result | 4 + .../r/wsrep_provider_options_basic.result | 4 + .../sys_vars/r/wsrep_recover_basic.result | 49 + .../r/wsrep_replicate_myisam_basic.result | 8 + .../r/wsrep_restart_slave_basic.result | 8 + .../r/wsrep_retry_autocommit_basic.result | 8 + .../r/wsrep_slave_fk_checks_basic.result | 45 + .../r/wsrep_slave_threads_basic.result | 20 + .../r/wsrep_slave_uk_checks_basic.result | 45 + .../sys_vars/r/wsrep_sst_auth_basic.result | 3 + .../sys_vars/r/wsrep_sst_donor_basic.result | 10 + ...rep_sst_donor_rejects_queries_basic.result | 8 + .../sys_vars/r/wsrep_sst_method_basic.result | 12 + .../r/wsrep_sst_receive_address_basic.result | 8 + .../r/wsrep_start_position_basic.result | 8 + .../sys_vars/r/wsrep_sync_wait_basic.result | 56 + .../t/innodb_disallow_writes_basic.test | 42 + .../t/wsrep_auto_increment_control_basic.test | 13 + .../sys_vars/t/wsrep_causal_reads_basic.test | 13 + .../suite/sys_vars/t/wsrep_certify_nonpk | 13 + .../sys_vars/t/wsrep_certify_nonpk_basic.test | 13 + .../t/wsrep_cluster_address_basic.test | 44 + .../sys_vars/t/wsrep_cluster_name_basic.test | 12 + .../t/wsrep_convert_lock_to_trx_basic.test | 13 + .../sys_vars/t/wsrep_data_home_dir_basic.test | 48 + .../sys_vars/t/wsrep_dbug_option_basic.test | 11 + .../suite/sys_vars/t/wsrep_debug_basic.test | 13 + .../sys_vars/t/wsrep_debug_option_basic.test | 13 + .../suite/sys_vars/t/wsrep_desync_basic.test | 4 + .../wsrep_drupal_282555_workaround_basic.test | 13 + .../t/wsrep_forced_binlog_format_basic.test | 14 + .../t/wsrep_load_data_splitting_basic.test | 13 + .../sys_vars/t/wsrep_log_conflicts_basic.test | 13 + .../sys_vars/t/wsrep_max_ws_rows_basic.test | 14 + .../sys_vars/t/wsrep_max_ws_size_basic.test | 14 + .../wsrep_mysql_replication_bundle_basic.test | 16 + .../sys_vars/t/wsrep_node_address_basic.test | 42 + .../t/wsrep_node_incoming_address_basic.test | 42 + .../sys_vars/t/wsrep_node_name_basic.test | 11 + .../sys_vars/t/wsrep_notify_cmd_basic.test | 11 + .../suite/sys_vars/t/wsrep_on_basic.test | 13 + .../sys_vars/t/wsrep_osu_method_basic.test | 18 + .../sys_vars/t/wsrep_provider_basic.test | 5 + .../t/wsrep_provider_options_basic.test | 5 + .../suite/sys_vars/t/wsrep_recover_basic.test | 47 + .../t/wsrep_replicate_myisam_basic.test | 13 + .../sys_vars/t/wsrep_restart_slave_basic.test | 13 + .../t/wsrep_retry_autocommit_basic.test | 13 + .../t/wsrep_slave_fk_checks_basic.test | 42 + .../sys_vars/t/wsrep_slave_threads_basic.test | 16 + .../t/wsrep_slave_uk_checks_basic.test | 42 + .../sys_vars/t/wsrep_sst_auth_basic.test | 12 + .../sys_vars/t/wsrep_sst_donor_basic.test | 12 + ...wsrep_sst_donor_rejects_queries_basic.test | 13 + .../sys_vars/t/wsrep_sst_method_basic.test | 17 + .../t/wsrep_sst_receive_address_basic.test | 13 + .../t/wsrep_start_position_basic.test | 14 + .../sys_vars/t/wsrep_sync_wait_basic.test | 47 + .../t/wsrep_wsrep_provider_basic.test | 11 + mysql-test/suite/wsrep/README | 7 + mysql-test/suite/wsrep/r/binlog_format.result | 35 + .../wsrep/r/innodb_load_xa_with_wsrep.result | 19 + .../r/mysql_tzinfo_to_sql_symlink.result | 70 + .../suite/wsrep/r/pool_of_threads.result | 8 + mysql-test/suite/wsrep/r/trans.result | 9 + mysql-test/suite/wsrep/r/variables.result | 222 ++ mysql-test/suite/wsrep/t/binlog_format.opt | 1 + mysql-test/suite/wsrep/t/binlog_format.test | 27 + .../wsrep/t/innodb_load_xa_with_wsrep.opt | 1 + .../wsrep/t/innodb_load_xa_with_wsrep.test | 19 + .../wsrep/t/mysql_tzinfo_to_sql_symlink.test | 40 + mysql-test/suite/wsrep/t/pool_of_threads.opt | 1 + mysql-test/suite/wsrep/t/pool_of_threads.test | 11 + mysql-test/suite/wsrep/t/trans.test | 14 + mysql-test/suite/wsrep/t/variables.test | 146 + mysql-test/t/mysql_tzinfo_to_sql_symlink.test | 11 + mysql-test/t/mysqld--help.test | 3 +- mysys/CMakeLists.txt | 4 + mysys/my_default.c | 12 + mysys/my_static.c | 4 + mysys/mysys_priv.h | 2 + mysys/thr_lock.c | 128 + plugin/feedback/CMakeLists.txt | 1 + scripts/CMakeLists.txt | 10 + scripts/mysqld_multi.sh | 8 +- scripts/mysqld_safe.sh | 122 +- scripts/wsrep_sst_common | 157 ++ scripts/wsrep_sst_common.sh | 157 ++ scripts/wsrep_sst_mysqldump | 131 + scripts/wsrep_sst_mysqldump.sh | 131 + scripts/wsrep_sst_rsync | 335 +++ scripts/wsrep_sst_rsync.sh | 335 +++ scripts/wsrep_sst_xtrabackup | 715 +++++ scripts/wsrep_sst_xtrabackup-v2 | 930 +++++++ scripts/wsrep_sst_xtrabackup-v2.sh | 930 +++++++ scripts/wsrep_sst_xtrabackup.sh | 715 +++++ sql/CMakeLists.txt | 22 + sql/event_data_objects.cc | 17 + sql/events.cc | 56 +- sql/ha_partition.cc | 9 + sql/ha_partition.h | 4 +- sql/handler.cc | 159 +- sql/handler.h | 15 + sql/item_func.cc | 14 +- sql/lock.cc | 46 + sql/log.cc | 141 +- sql/log.h | 8 +- sql/log_event.cc | 164 +- sql/log_event.h | 6 +- sql/mdl.cc | 141 +- sql/mdl.h | 12 +- sql/mysqld.cc | 400 ++- sql/mysqld.h | 18 + sql/protocol.cc | 2 + sql/rpl_record.cc | 21 +- sql/set_var.cc | 4 + sql/set_var.h | 6 + sql/slave.cc | 41 +- sql/sp.cc | 7 +- sql/sp.h | 15 + sql/sql_acl.cc | 54 +- sql/sql_admin.cc | 4 + sql/sql_alter.cc | 17 + sql/sql_base.cc | 42 +- sql/sql_builtin.cc.in | 9 +- sql/sql_class.cc | 129 +- sql/sql_class.h | 57 +- sql/sql_connect.cc | 25 +- sql/sql_delete.cc | 17 +- sql/sql_insert.cc | 46 +- sql/sql_lex.cc | 13 +- sql/sql_parse.cc | 603 +++- sql/sql_parse.h | 1 - sql/sql_partition_admin.cc | 18 + sql/sql_plugin.cc | 18 +- sql/sql_prepare.cc | 24 +- sql/sql_reload.cc | 13 +- sql/sql_repl.cc | 3 +- sql/sql_show.cc | 33 +- sql/sql_table.cc | 9 + sql/sql_trigger.cc | 4 +- sql/sql_truncate.cc | 7 + sql/sql_update.cc | 11 +- sql/sql_yacc.yy | 12 +- sql/sys_vars.cc | 286 ++ sql/table.cc | 1 + sql/transaction.cc | 65 + sql/tztime.cc | 12 + sql/wsrep_applier.cc | 387 +++ sql/wsrep_applier.h | 38 + sql/wsrep_binlog.cc | 414 +++ sql/wsrep_binlog.h | 59 + sql/wsrep_check_opts.cc | 379 +++ sql/wsrep_hton.cc | 577 ++++ sql/wsrep_mysqld.cc | 2433 +++++++++++++++++ sql/wsrep_mysqld.h | 370 +++ sql/wsrep_notify.cc | 111 + sql/wsrep_priv.h | 53 + sql/wsrep_sst.cc | 1127 ++++++++ sql/wsrep_sst.h | 68 + sql/wsrep_thd.cc | 602 ++++ sql/wsrep_thd.h | 40 + sql/wsrep_utils.cc | 524 ++++ sql/wsrep_utils.h | 208 ++ sql/wsrep_var.cc | 602 ++++ sql/wsrep_var.h | 86 + storage/innobase/CMakeLists.txt | 25 + storage/innobase/buf/buf0rea.cc | 6 +- storage/innobase/dict/dict0dict.cc | 24 +- storage/innobase/fil/fil0pagecompress.cc | 2 + storage/innobase/handler/ha_innodb.cc | 1454 ++++++++++ storage/innobase/handler/ha_innodb.h | 42 +- storage/innobase/handler/handler0alter.cc | 4 + storage/innobase/include/dict0mem.h | 3 + storage/innobase/include/ha_prototypes.h | 17 + storage/innobase/include/hash0hash.h | 27 + storage/innobase/include/lock0lock.h | 10 + storage/innobase/include/rem0rec.h | 9 + storage/innobase/include/srv0srv.h | 12 + storage/innobase/include/sync0sync.ic | 3 + storage/innobase/include/trx0sys.h | 33 + storage/innobase/include/trx0sys.ic | 3 + storage/innobase/include/trx0trx.h | 3 + storage/innobase/lock/lock0lock.cc | 491 +++- storage/innobase/os/os0file.cc | 23 +- storage/innobase/rem/rem0rec.cc | 134 + storage/innobase/row/row0ins.cc | 31 +- storage/innobase/row/row0upd.cc | 288 ++ storage/innobase/srv/srv0conc.cc | 93 +- storage/innobase/srv/srv0srv.cc | 29 + storage/innobase/trx/trx0sys.cc | 134 + storage/innobase/trx/trx0trx.cc | 35 +- storage/innobase/wsrep/md5.cc | 74 + storage/innobase/wsrep/wsrep_md5.h | 26 + storage/perfschema/CMakeLists.txt | 4 + storage/xtradb/CMakeLists.txt | 25 + storage/xtradb/dict/dict0dict.cc | 24 +- storage/xtradb/fil/fil0fil.cc | 32 +- storage/xtradb/fil/fil0pagecompress.cc | 2 + storage/xtradb/handler/ha_innodb.cc | 1481 +++++++++- storage/xtradb/handler/ha_innodb.h | 41 + storage/xtradb/handler/handler0alter.cc | 4 + storage/xtradb/include/dict0mem.h | 3 + storage/xtradb/include/ha_prototypes.h | 17 + storage/xtradb/include/hash0hash.h | 27 + storage/xtradb/include/rem0rec.h | 9 + storage/xtradb/include/srv0srv.h | 13 + storage/xtradb/include/sync0sync.ic | 3 + storage/xtradb/include/trx0sys.h | 33 + storage/xtradb/include/trx0sys.ic | 3 + storage/xtradb/include/trx0trx.h | 3 + storage/xtradb/lock/lock0lock.cc | 490 +++- storage/xtradb/lock/lock0wait.cc | 35 +- storage/xtradb/os/os0file.cc | 24 +- storage/xtradb/rem/rem0rec.cc | 139 +- storage/xtradb/row/row0ins.cc | 31 +- storage/xtradb/row/row0upd.cc | 288 ++ storage/xtradb/srv/srv0conc.cc | 93 +- storage/xtradb/srv/srv0srv.cc | 33 + storage/xtradb/trx/trx0roll.cc | 16 + storage/xtradb/trx/trx0sys.cc | 134 + storage/xtradb/trx/trx0trx.cc | 43 +- storage/xtradb/wsrep/md5.cc | 74 + storage/xtradb/wsrep/wsrep_md5.h | 26 + support-files/CMakeLists.txt | 3 +- support-files/mysql.server.sh | 20 +- support-files/mysql.spec.sh | 61 +- support-files/rpm/server.cnf | 16 + support-files/wsrep.cnf | 129 + support-files/wsrep.cnf.sh | 129 + support-files/wsrep.cnf.sh.moved | 129 + support-files/wsrep_notify | 102 + support-files/wsrep_notify.sh | 102 + wsrep/CMakeLists.txt | 25 + wsrep/wsrep_api.h | 1118 ++++++++ wsrep/wsrep_dummy.c | 407 +++ wsrep/wsrep_gtid.c | 74 + wsrep/wsrep_loader.c | 203 ++ wsrep/wsrep_uuid.c | 83 + 327 files changed, 28127 insertions(+), 332 deletions(-) create mode 100644 BUILD/compile-amd64-debug-wsrep create mode 100644 BUILD/compile-amd64-wsrep create mode 100644 BUILD/compile-pentium-debug-wsrep create mode 100644 BUILD/compile-pentium-wsrep create mode 100644 BUILD/compile-pentium64-wsrep create mode 100644 Docs/README-wsrep create mode 100644 cmake/wsrep.cmake create mode 100644 include/wsrep.h create mode 100644 mysql-test/include/galera_cluster.inc create mode 100644 mysql-test/include/galera_connect.inc create mode 100644 mysql-test/include/galera_diff.inc create mode 100644 mysql-test/include/galera_end.inc create mode 100644 mysql-test/include/galera_init.inc create mode 100644 mysql-test/include/have_innodb_disallow_writes.inc create mode 100644 mysql-test/include/have_wsrep.inc create mode 100644 mysql-test/include/have_wsrep_enabled.inc create mode 100644 mysql-test/include/not_wsrep.inc create mode 100644 mysql-test/r/have_wsrep.require create mode 100644 mysql-test/r/not_wsrep.require create mode 100644 mysql-test/suite/galera/galera_2nodes.cnf create mode 100644 mysql-test/suite/galera/my.cnf create mode 100644 mysql-test/suite/galera/r/basic.result create mode 100644 mysql-test/suite/galera/r/galera_sst_mode.result create mode 100644 mysql-test/suite/galera/r/grant.result create mode 100644 mysql-test/suite/galera/r/partition.result create mode 100644 mysql-test/suite/galera/r/unique_key.result create mode 100644 mysql-test/suite/galera/t/basic.test create mode 100644 mysql-test/suite/galera/t/galera_sst_mode.test create mode 100644 mysql-test/suite/galera/t/grant.test create mode 100644 mysql-test/suite/galera/t/partition.test create mode 100644 mysql-test/suite/galera/t/unique_key.test mode change 100755 => 100644 mysql-test/suite/parts/r/partition_exch_qa_10.result create mode 100644 mysql-test/suite/sys_vars/r/innodb_disallow_writes_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_auto_increment_control_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_causal_reads_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_certify_nonpk_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_cluster_address_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_cluster_name_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_convert_lock_to_trx_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_data_home_dir_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_dbug_option_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_debug_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_desync_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_drupal_282555_workaround_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_forced_binlog_format_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_load_data_splitting_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_log_conflicts_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_max_ws_rows_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_max_ws_size_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_mysql_replication_bundle_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_node_address_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_node_incoming_address_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_node_name_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_notify_cmd_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_on_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_osu_method_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_provider_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_provider_options_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_recover_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_replicate_myisam_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_restart_slave_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_retry_autocommit_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_slave_fk_checks_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_slave_threads_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_slave_uk_checks_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_sst_auth_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_sst_donor_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_sst_donor_rejects_queries_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_sst_method_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_sst_receive_address_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_start_position_basic.result create mode 100644 mysql-test/suite/sys_vars/r/wsrep_sync_wait_basic.result create mode 100644 mysql-test/suite/sys_vars/t/innodb_disallow_writes_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_auto_increment_control_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_causal_reads_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_certify_nonpk create mode 100644 mysql-test/suite/sys_vars/t/wsrep_certify_nonpk_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_cluster_address_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_cluster_name_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_convert_lock_to_trx_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_data_home_dir_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_dbug_option_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_debug_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_debug_option_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_desync_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_drupal_282555_workaround_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_forced_binlog_format_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_load_data_splitting_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_log_conflicts_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_max_ws_rows_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_max_ws_size_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_mysql_replication_bundle_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_node_address_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_node_incoming_address_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_node_name_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_notify_cmd_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_on_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_osu_method_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_provider_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_provider_options_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_recover_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_replicate_myisam_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_restart_slave_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_retry_autocommit_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_slave_fk_checks_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_slave_threads_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_slave_uk_checks_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_sst_auth_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_sst_donor_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_sst_donor_rejects_queries_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_sst_method_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_sst_receive_address_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_start_position_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_sync_wait_basic.test create mode 100644 mysql-test/suite/sys_vars/t/wsrep_wsrep_provider_basic.test create mode 100644 mysql-test/suite/wsrep/README create mode 100644 mysql-test/suite/wsrep/r/binlog_format.result create mode 100644 mysql-test/suite/wsrep/r/innodb_load_xa_with_wsrep.result create mode 100644 mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink.result create mode 100644 mysql-test/suite/wsrep/r/pool_of_threads.result create mode 100644 mysql-test/suite/wsrep/r/trans.result create mode 100644 mysql-test/suite/wsrep/r/variables.result create mode 100644 mysql-test/suite/wsrep/t/binlog_format.opt create mode 100644 mysql-test/suite/wsrep/t/binlog_format.test create mode 100644 mysql-test/suite/wsrep/t/innodb_load_xa_with_wsrep.opt create mode 100644 mysql-test/suite/wsrep/t/innodb_load_xa_with_wsrep.test create mode 100644 mysql-test/suite/wsrep/t/mysql_tzinfo_to_sql_symlink.test create mode 100644 mysql-test/suite/wsrep/t/pool_of_threads.opt create mode 100644 mysql-test/suite/wsrep/t/pool_of_threads.test create mode 100644 mysql-test/suite/wsrep/t/trans.test create mode 100644 mysql-test/suite/wsrep/t/variables.test create mode 100755 scripts/wsrep_sst_common create mode 100644 scripts/wsrep_sst_common.sh create mode 100755 scripts/wsrep_sst_mysqldump create mode 100644 scripts/wsrep_sst_mysqldump.sh create mode 100755 scripts/wsrep_sst_rsync create mode 100644 scripts/wsrep_sst_rsync.sh create mode 100755 scripts/wsrep_sst_xtrabackup create mode 100755 scripts/wsrep_sst_xtrabackup-v2 create mode 100644 scripts/wsrep_sst_xtrabackup-v2.sh create mode 100644 scripts/wsrep_sst_xtrabackup.sh create mode 100644 sql/wsrep_applier.cc create mode 100644 sql/wsrep_applier.h create mode 100644 sql/wsrep_binlog.cc create mode 100644 sql/wsrep_binlog.h create mode 100644 sql/wsrep_check_opts.cc create mode 100644 sql/wsrep_hton.cc create mode 100644 sql/wsrep_mysqld.cc create mode 100644 sql/wsrep_mysqld.h create mode 100644 sql/wsrep_notify.cc create mode 100644 sql/wsrep_priv.h create mode 100644 sql/wsrep_sst.cc create mode 100644 sql/wsrep_sst.h create mode 100644 sql/wsrep_thd.cc create mode 100644 sql/wsrep_thd.h create mode 100644 sql/wsrep_utils.cc create mode 100644 sql/wsrep_utils.h create mode 100644 sql/wsrep_var.cc create mode 100644 sql/wsrep_var.h create mode 100644 storage/innobase/wsrep/md5.cc create mode 100644 storage/innobase/wsrep/wsrep_md5.h create mode 100644 storage/xtradb/wsrep/md5.cc create mode 100644 storage/xtradb/wsrep/wsrep_md5.h create mode 100644 support-files/wsrep.cnf create mode 100644 support-files/wsrep.cnf.sh create mode 100644 support-files/wsrep.cnf.sh.moved create mode 100644 support-files/wsrep_notify create mode 100644 support-files/wsrep_notify.sh create mode 100644 wsrep/CMakeLists.txt create mode 100644 wsrep/wsrep_api.h create mode 100644 wsrep/wsrep_dummy.c create mode 100644 wsrep/wsrep_gtid.c create mode 100644 wsrep/wsrep_loader.c create mode 100644 wsrep/wsrep_uuid.c diff --git a/.bzrignore b/.bzrignore index d5874ebf0f2..ba23211d3a3 100644 --- a/.bzrignore +++ b/.bzrignore @@ -12,6 +12,7 @@ *.dll *.dsp *.dylib +*.diff *.exe *.exp *.gcda diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index bde095b0aa8..860560767a7 100755 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -215,7 +215,7 @@ all_configs="$SSL_LIBRARY --with-plugins=max --with-plugin-ndbcluster --with-emb alpha_cflags="$check_cpu_cflags -Wa,-m$cpu_flag" amd64_cflags="$check_cpu_cflags" amd64_cxxflags="" # If dropping '--with-big-tables', add here "-DBIG_TABLES" -pentium_cflags="$check_cpu_cflags" +pentium_cflags="$check_cpu_cflags -m32" pentium64_cflags="$check_cpu_cflags -m64" ppc_cflags="$check_cpu_cflags" sparc_cflags="" diff --git a/BUILD/compile-amd64-debug-wsrep b/BUILD/compile-amd64-debug-wsrep new file mode 100644 index 00000000000..995a8afcca9 --- /dev/null +++ b/BUILD/compile-amd64-debug-wsrep @@ -0,0 +1,11 @@ +#! /bin/sh + +path=`dirname $0` +. "$path/SETUP.sh" + +extra_flags="$amd64_cflags $debug_cflags -g -O0 $wsrep_cflags" +c_warnings="$c_warnings $debug_extra_warnings" +cxx_warnings="$cxx_warnings $debug_extra_warnings" +extra_configs="$amd64_configs $debug_configs $wsrep_configs --with-wsrep" + +. "$path/FINISH.sh" diff --git a/BUILD/compile-amd64-wsrep b/BUILD/compile-amd64-wsrep new file mode 100644 index 00000000000..57dfbdd6da2 --- /dev/null +++ b/BUILD/compile-amd64-wsrep @@ -0,0 +1,9 @@ +#! /bin/sh + +path=`dirname $0` +. "$path/SETUP.sh" + +extra_flags="$amd64_cflags $fast_cflags -g $wsrep_cflags" +extra_configs="$amd64_configs $wsrep_configs --with-wsrep" + +. "$path/FINISH.sh" diff --git a/BUILD/compile-pentium-debug-wsrep b/BUILD/compile-pentium-debug-wsrep new file mode 100644 index 00000000000..ee68e3fd0c1 --- /dev/null +++ b/BUILD/compile-pentium-debug-wsrep @@ -0,0 +1,12 @@ +#! /bin/sh -x + +path=`dirname $0` +set -- "$@" --with-debug=full +. "$path/SETUP.sh" + +extra_flags="$pentium_cflags $debug_cflags -g -O0 $wsrep_cflags" +c_warnings="$c_warnings $debug_extra_warnings" +cxx_warnings="$cxx_warnings $debug_extra_warnings" +extra_configs="$pentium_configs $debug_configs $wsrep_configs --with-wsrep" + +. "$path/FINISH.sh" diff --git a/BUILD/compile-pentium-wsrep b/BUILD/compile-pentium-wsrep new file mode 100644 index 00000000000..eeb14310e4e --- /dev/null +++ b/BUILD/compile-pentium-wsrep @@ -0,0 +1,11 @@ +#! /bin/sh + +path=`dirname $0` +. "$path/SETUP.sh" + +extra_flags="$pentium_cflags $fast_cflags $wsrep_cflags" +extra_configs="$pentium_configs $wsrep_configs --with-wsrep" + +#strip=yes + +. "$path/FINISH.sh" diff --git a/BUILD/compile-pentium64-wsrep b/BUILD/compile-pentium64-wsrep new file mode 100644 index 00000000000..0bccb34e753 --- /dev/null +++ b/BUILD/compile-pentium64-wsrep @@ -0,0 +1,28 @@ +#! /bin/sh + +# Copyright (C) 2006, 2007 MySQL AB +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +# MA 02111-1307, USA + +path=`dirname $0` +. "$path/SETUP.sh" + +extra_flags="$pentium64_cflags $fast_cflags -g $wsrep_cflags" +extra_configs="$pentium_configs $static_link $wsrep_configs --with-wsrep" +CC="$CC --pipe" +strip=yes + +. "$path/FINISH.sh" diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b5c73b6e6c..68f3b01eb28 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -158,6 +158,7 @@ INCLUDE(ctest) INCLUDE(plugin) INCLUDE(install_macros) INCLUDE(mysql_add_executable) +INCLUDE(wsrep) # Handle options OPTION(DISABLE_SHARED @@ -235,6 +236,12 @@ OPTION(ENABLED_LOCAL_INFILE OPTION(WITH_FAST_MUTEXES "Compile with fast mutexes" OFF) MARK_AS_ADVANCED(WITH_FAST_MUTEXES) +OPTION(WITH_INNODB_DISALLOW_WRITES "InnoDB freeze writes patch from Google" ${WITH_WSREP}) +IF (WITH_INNODB_DISALLOW_WRITES) + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWITH_INNODB_DISALLOW_WRITES") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWITH_INNODB_DISALLOW_WRITES") +ENDIF() + # Set DBUG_OFF and other optional release-only flags for non-debug project types FOREACH(BUILD_TYPE RELEASE RELWITHDEBINFO MINSIZEREL) FOREACH(LANG C CXX) @@ -369,6 +376,9 @@ ADD_SUBDIRECTORY(vio) ADD_SUBDIRECTORY(mysys) ADD_SUBDIRECTORY(mysys_ssl) ADD_SUBDIRECTORY(libmysql) +IF(WITH_WSREP) + ADD_SUBDIRECTORY(wsrep) +ENDIF() ADD_SUBDIRECTORY(client) ADD_SUBDIRECTORY(extra) ADD_SUBDIRECTORY(libservices) @@ -447,6 +457,7 @@ INSTALL_DOCUMENTATION(${CMAKE_BINARY_DIR}/Docs/INFO_SRC IF(UNIX) INSTALL_DOCUMENTATION(Docs/INSTALL-BINARY COMPONENT Readme) + INSTALL_DOCUMENTATION(Docs/INSTALL-BINARY Docs/README-wsrep COMPONENT Readme) ENDIF() INCLUDE(CPack) diff --git a/Docs/README-wsrep b/Docs/README-wsrep new file mode 100644 index 00000000000..422ec52f48a --- /dev/null +++ b/Docs/README-wsrep @@ -0,0 +1,488 @@ +Codership Oy +http://www.codership.com + + +DISCLAIMER + +THIS SOFTWARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER +EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +IN NO EVENT SHALL CODERSHIP OY BE HELD LIABLE TO ANY PARTY FOR ANY DAMAGES +RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE. + +Trademark Information. + +MySQL is a trademark or registered trademark of Oracle and/or its affiliates. +Other trademarks are the property of their respective owners. + +Licensing Information. + +Please see file COPYING that came with this distribution + +Source code can be found at +wsrep API: https://launchpad.net/wsrep +MySQL patch: https://launchpad.net/codership-mysql + + +ABOUT THIS DOCUMENT + +This document covers installation and configuration issues specific to this +wsrep-patched MySQL distribution by Codership. It does not cover the use or +administration of MySQL server per se. The reader is assumed to know how to +install, configure, administer and use standard MySQL server version 5.1.xx. + + + MYSQL-5.5.x/wsrep-23.x + +CONTENTS: +========= +1. WHAT IS WSREP PATCH FOR MYSQL +2. INSTALLATION +3. FIRST TIME SETUP + 3.1 CONFIGURATION FILES + 3.2 DATABASE PRIVILEGES + 3.3 CHECK AND CORRECT FIREWALL SETTINGS + 3.4 SELINUX + 3.5 APPARMOR + 3.6 CONNECT TO CLUSTER +4. UPGRADING FROM MySQL 5.1.x +5. CONFIGURATION OPTIONS + 5.1 MANDATORY MYSQL OPTIONS + 5.2 WSREP OPTIONS +6. ONLINE SCHEMA UPGRADE + 6.1 TOTAL ORDER ISOLATION (TOI) + 6.2 ROLLING SCHEMA UPGRADE (RSU) +7. LIMITATIONS + + +1. WHAT IS WSREP PATCH FOR MYSQL/INNODB + +Wsrep API developed by Codership Oy is a modern generic (database-agnostic) +replication API for transactional databases with a goal to make database +replication/logging subsystem completely modular and pluggable. It is developed +with flexibility and completeness in mind to satisfy broad range of modern +replication scenarios. It is equally suitable for synchronous and asynchronous, +master-slave and multi-master replication. + +wsrep stands for Write Set REPlication. + +Wsrep patch for MySQL/InnoDB allows MySQL server to load and use various wsrep +API implementations ("wsrep providers") with different qualities of service. +Without wsrep provider MySQL-wsrep server will function like a regular +standalone server. + + +2. INSTALLATION + +In the examples below mysql authentication options are omitted for brevity. + +2.1 Download and install mysql-wsrep package. + +Download binary package for your Linux distribution from +https://launchpad.net/codership-mysql/ + +2.1.1 On Debian and Debian-derived distributions. + +Upgrade from mysql-server-5.0 to mysql-wsrep is not supported yet, please +upgrade to mysql-server-5.1 first. + +If you're installing over an existing mysql installation, mysql-server-wsrep +will conflict with mysql-server-5.1 package, so remove it first: + +$ sudo apt-get remove mysql-server-5.1 mysql-server-core-5.1 + +mysql-server-wsrep requires psmisc and mysql-client-5.1.47 (or later). +MySQL 5.1 packages can be found from backports repositories. +For further information about configuring and using Debian or Ubuntu +backports, see: + +* http://backports.debian.org + +* https://help.ubuntu.com/community/UbuntuBackports + +For example, installation of required packages on Debian Lenny: + +$ sudo apt-get install psmisc +$ sudo apt-get -t lenny-backports install mysql-client-5.1 + +Now you should be able to install mysql-wsrep package: + +$ sudo dpkg -i + +2.1.2 On CentOS and similar RPM-based distributions. + +If you're migrating from existing MySQL installation, there are two variants: + + a) If you're already using official MySQL-server-community 5.1.x RPM from + Oracle: + + # rpm -e mysql-server + + b) If you're upgrading from the stock mysql-5.0.77 on CentOS: + + 1) Make sure that the following packages are not installed: + # rpm --nodeps --allmatches -e mysql-server mysql-test mysql-bench + + 2) Install *official* MySQL-shared-compat-5.1.x from + http://dev.mysql.com/downloads/mysql/5.1.html + +Actual installation: + + # rpm -Uvh + + If this fails due to unsatisfied dependencies, install missing packages + (e.g. yum install perl-DBI) and retry. + +Additional packages to consider (if not yet installed): + * galera (multi-master replication provider, https://launchpad.net/galera) + * MySQL-client-community (for connecting to server and mysqldump-based SST) + * rsync (for rsync-based SST) + * xtrabackup and nc (for xtrabackup-based SST) + +2.2 Upgrade system tables. + +If you're upgrading a previous MySQL installation, it might be advisable to +upgrade system tables. To do that start mysqld and run mysql_upgrade command. +Consult MySQL documentation in case of errors. Normally they are not critical +and can be ignored unless specific functionality is needed. + + +3. FIRST TIME SETUP + +Unless you're upgrading an already installed mysql-wsrep package, you will need +to set up a few things to prepare server for operation. + +3.1 CONFIGURATION FILES + +* Make sure system-wide my.cnf does not bind mysqld to 127.0.0.1. That is, if + you have the following line in [mysqld] section, comment it out: + + #bind-address = 127.0.0.1 + +* Make sure system-wide my.cnf contains "!includedir /etc/mysql/conf.d/" line. + +* Edit /etc/mysql/conf.d/wsrep.cnf and set wsrep_provider option by specifying + a path to provider library. If you don't have a provider, leave it as it is. + +* When a new node joins the cluster it'll have to receive a state snapshot from + one of the peers. This requires a privileged MySQL account with access from + the rest of the cluster. Edit /etc/mysql/conf.d/wsrep.cnf and set mysql + login/password pair for SST, for example: + + wsrep_sst_auth=wsrep_sst:wspass + +* See CONFIGURATION section below about other configuration parameters that you + might want to change at this point. + +3.2 DATABASE PRIVILEGES + +Restart MySQL server and connect to it as root to grant privileges to SST +account (empty users confuse MySQL authentication matching rules, we need to +delete them too): + +$ mysql -e "SET wsrep_on=OFF; DELETE FROM mysql.user WHERE user='';" +$ mysql -e "SET wsrep_on=OFF; GRANT ALL ON *.* TO wsrep_sst@'%' IDENTIFIED BY 'wspass'"; + +3.3 CHECK AND CORRECT FIREWALL SETTINGS. + +MySQL-wsrep server needs to be accessible from other cluster members through +its client listening socket and through wsrep provider socket. See your +distribution and wsrep provider documentation for details. For example on +CentOS you might need to do something along these lines: + +# iptables --insert RH-Firewall-1-INPUT 1 --proto tcp --source /24 --destination /32 --dport 3306 -j ACCEPT +# iptables --insert RH-Firewall-1-INPUT 1 --proto tcp --source /24 --destination /32 --dport 4567 -j ACCEPT + +If there is a NAT firewall between the nodes, it must be configured to allow +direct connections between the nodes (e.g. via port forwarding). + +3.4 SELINUX + +If you have SELinux enabled, it may block mysqld from doing required operations. +You'll need to either disable it or configure to allow mysqld to run external +programs and open listen sockets at unprivileged ports (i.e. things that +an unprivileged user can do). See SELinux documentation about it. + +To quickly disable SELinux: +1) run 'setenforce 0' as root. +2) set 'SELINUX=permissive' in /etc/selinux/config + +3.5 APPARMOR + +AppArmor automatically comes with Ubuntu and may also prevent mysqld to from +opening additional ports or run scripts. See AppArmor documentation about its +configuration. To disable AppArmor for mysqld: + +$ cd /etc/apparmor.d/disable/ +$ sudo ln -s /etc/apparmor.d/usr.sbin.mysqld +$ sudo service apparmor restart + + +3.6 CONNECT TO CLUSTER + +Now you're ready to connect to cluster by setting wsrep_cluster_address variable +and monitor status of wsrep provider: + +mysql> SET GLOBAL wsrep_cluster_address=''; +mysql> SHOW STATUS LIKE 'wsrep%'; + + +4 UPGRADING FROM MySQL 5.1.x + +!!! THESE INSTRUCTIONS ARE PRELIMINARY AND INCOMPLETE !!! + +1) BEFORE UPGRADE (while running 5.1.x): + - comment out 'wsrep_provider' setting from configuration files + (my.cnf and/or wsrep.cnf) + - If performing a rolling upgrade on a running cluster, set + wsrep_sst_method=mysqldump. + You might also need to configure wsrep_sst_receive_address and + wsrep_sst_auth appropriately. mysqldump is the only way to transfer data + from 5.1.x to 5.5.x reliably. + - remove innodb_plugin settings from configuration files. + +2) Perform upgrade as usual: + http://dev.mysql.com/doc/refman/5.5/en/upgrading-from-previous-series.html + Don't forget to run 'mysql_upgrade' command. + +3) AFTER UPGRADING individual node: + - uncomment 'wsrep_provider' line in configuration file. + - restart the server and join the cluster. + +4) AFTER UPGRADING the whole cluster: + - revert to usual wsrep SST settings if not 'mysqldump'. + + +5. CONFIGURATION OPTIONS + +5.1 MANDATORY MYSQL OPTIONS + +binlog_format=ROW + This option is required to use row-level replication as opposed to + statement-level. For performance and consistency considerations don't change + that. As a side effect, binlog, if turned on, can be ROW only. In future this + option won't have special meaning. + +innodb_autoinc_lock_mode=2 + This is a required parameter. Without it INSERTs into tables with + AUTO_INCREMENT column may fail. + autoinc lock modes 0 and 1 can cause unresolved deadlock, and make + system unresponsive. + +innodb_locks_unsafe_for_binlog=1 + This option is required for parallel applying. + +5.2 WSREP OPTIONS + +All options are optional except for wsrep_provider, wsrep_cluster_address, and +wsrep_sst_auth. + +wsrep_provider=none + A full path to the library that implements WSREP interface. If none is + specified, the server behaves like a regular mysqld. + +wsrep_provider_options= + Provider-specific option string. Check wsrep provider documentation or + http://www.codership.com/wiki + +wsrep_cluster_address= + Provider-specific cluster address string. This is used to connect a node to + the desired cluster. This option can be given either on mysqld startup or set + during runtime. See wsrep provider documentation for possible values. + +wsrep_cluster_name="my_wsrep_cluster" + Logical cluster name, must be the same for all nodes of the cluster. + +wsrep_node_address= + An option to explicitly specify the network address of the node in the form +
[:port] if autoguessing for some reason does not produce desirable + results (multiple network interfaces, NAT, etc.) + If not explicitly overridden by wsrep_sst_receive_address, the
part + will be used to listen for SST (see below). And the whole
[:port] + will be passed to wsrep provider to be used as a base address in its + communications. + +wsrep_node_name= + Human readable node name (for easier log reading only). Defaults to hostname. + +wsrep_slave_threads=1 + Number of threads dedicated to processing of writesets from other nodes. + For best performance should be few per CPU core. + +wsrep_dbug_option + Options for the built-in DBUG library (independent from what MySQL uses). + Empty by default. Not currently in use. + +wsrep_debug=0 + Enable debug-level logging. + +wsrep_convert_LOCK_to_trx=0 + Implicitly convert locking sessions into transactions inside mysqld. By + itself it does not mean support for locking sessions, but it prevents the + database from going into logically inconsistent state. Note however, that + loading large database dump with LOCK statements might result in abnormally + large transactions and cause an out-of-memory condition + +wsrep_retry_autocommit=1 + Retry autocommit queries and single statement transactions should they fail + certification test. This is analogous to rescheduling an autocommit query + should it go into deadlock with other transactions in the database lock + manager. + +wsrep_auto_increment_control=1 + Automatically adjust auto_increment_increment and auto_increment_offset + variables based on the number of nodes in the cluster. Significantly reduces + certification conflict rate for INSERTS. + +wsrep_drupal_282555_workaround=1 + MySQL seems to have an obscure bug when INSERT into table with + AUTO_INCREMENT column with NULL value for that column can fail with a + duplicate key error. When this option is on, it retries such INSERTs. + Required for stable Drupal operation. Documented at: + http://bugs.mysql.com/bug.php?id=41984 + http://drupal.org/node/282555 + +wsrep_causal_reads=0 + Enforce strict READ COMMITTED semantics on reads and transactions. May + result in additional latencies. It is a session variable. + +wsrep_OSU_method=TOI + Online Schema Upgrade (OSU) can be performed with two alternative methods: + Total Order Isolation (TOI) runs DDL statement in all cluster nodes in + same total order sequence locking the affected table for the duration of the + operation. This may result in the whole cluster being blocked for the + duration of the operation. + Rolling Schema Upgrade (RSU) executes the DDL statement only locally, thus + blocking only one cluster node. During the DDL processing, the node + is not replicating and may be unable to process replication events (due to + table lock). Once DDL operation is complete, the node will catch up and sync + with the cluster to become fully operational again. The DDL statement or + its effects are not replicated, so it is user's responsibility to manually + perform this operation on each of the nodes. + +wsrep_forced_binlog_format=none + Force every transaction to use given binlog format. When this variable is + set to something else than NONE, all transactions will use the given forced + format, regardless of what the client session has specified in binlog_format. + Valid choices for wsrep_forced_binlog_format are: ROW, STATEMENT, MIXED and + special value NONE, meaning that there is no forced binlog format in effect. + This variable was intruduced to support STATEMENT format replication during + rolling schema upgrade processing. However, in most cases ROW replication + is valid for asymmetrict schema replication. + +State snapshot transfer options. + +When a new node joins the cluster it has to synchronize its initial state with +the other cluster members by transferring state snapshot from one of them. +The options below govern how this happens and should be set up before attempting +to join or start a cluster. + +wsrep_sst_method=rsync + What method to use to copy database state to a newly joined node. Supported + methods: + - mysqldump: slow (except for small datasets) but allows for upgrade + between major MySQL versions or InnoDB features. + - rsync: much faster on large datasets (default). + - rsync_wan: same as rsync but with deltaxfer to minimize network traffic. + - xtrabackup: very fast and practically non-blocking SST method based on + Percona's xtrabackup tool. + + (for xtrabackup to work the following settings must be present in my.cnf + on all nodes: + [mysqld] + wsrep_sst_auth=root: + datadir= + [client] + socket= + ) + +wsrep_sst_receive_address= + Address (hostname:port) at which this node wants to receive state snapshot. + Defaults to mysqld bind address, and if that is not specified (0.0.0.0) - + to the first IP of eth0 + mysqld bind port. + NOTE: check that your firewall allows connections to this address from other + cluster nodes. + +wsrep_sst_auth= + Authentication information needed for state transfer. Depends on the state + transfer method. For mysqldump-based SST it is + : + and should be the same on all nodes - it is used to authenticate with both + state snapshot receiver and state snapshot donor. + +wsrep_sst_donor= + A name of the node which should serve as state snapshot donor. This allows + to control which node will serve state snapshot request. By default the + most suitable node is chosen by wsrep provider. This is the same as given in + wsrep_node_name. + + +6. ONLINE SCHEMA UPGRADE + + Schema upgrades mean any data definition statements (DDL statemnents) run + for the database. They change the database structure and are non- + transactional. + + Release 22.3 brings a new method for performing schema upgrades. User can + now choose whether to use the traditional total order isolation or new + rolling schema upgrade method. The OSU method choice is done by global + parameter: 'wsrep_OSU_method'. + +6.1 Total Order Isolation (TOI) + + With earlier releases, DDL processing happened always by Total Order + Isolation (TOI) method. With TOI, the DDL was scheduled to be processed in + same transaction seqeuncing 'slot' in each cluster node. + The processing is secured by locking the affected table from any other use. + With TOI method, the whole cluster has part of the database locked for the + duration of the DDL processing. + +6.2 Rolling Schema Upgrade (RSU) + + Rolling schema upgrade is new DDL processing method, where DDL will be + processed locally for the node. The node is disconnected of the replication + for the duration of the DDL processing, so that there is only DDL statement + processing in the node and it does not block the rest of the cluster. When + the DDL processing is complete, the node applies delayed replication events + and synchronizes back with the cluster. + The DDL can then be executed cluster-wide by running the same DDL statement + for each node in turn. When this rolling schema upgrade proceeds, part of + the cluster will have old schema structure and part of the cluster will have + new schema structure. + + +7. LIMITATIONS + +1) Currently replication works only with InnoDB storage engine. Any writes to + tables of other types, including system (mysql.*) tables are not replicated. + However, DDL statements are replicated in statement level, and changes + to mysql.* tables will get replicated that way. + So, you can safely issue: CREATE USER..., + but issuing: INSERT INTO mysql.user..., will not be replicated. + +2) DELETE operation is unsupported on tables without primary key. Also rows in + tables without primary key may appear in different order on different nodes. + As a result SELECT...LIMIT... may return slightly different sets. + +3) Unsupported queries: + * LOCK/UNLOCK TABLES cannot be supported in multi-master setups. + * lock functions (GET_LOCK(), RELEASE_LOCK()... ) + +4) Query log cannot be directed to table. If you enable query logging, + you must forward the log to a file: + log_output = FILE + Use general_log and general_log_file to choose query logging and the + log file name + +5) Maximum allowed transaction size is defined by wsrep_max_ws_rows and + wsrep_max_ws_size. Anything bigger (e.g. huge LOAD DATA) will be rejected. + +6) Due to cluster level optimistic concurrency control, transaction issuing + COMMIT may still be aborted at that stage. There can be two transactions. + writing to same rows and committing in separate cluster nodes, and only one + of the them can successfully commit. The failing one will be aborted. + For cluster level aborts, MySQL/galera cluster gives back deadlock error. + code (Error: 1213 SQLSTATE: 40001 (ER_LOCK_DEADLOCK)). + +7) XA transactions can not be supported due to possible rollback on commit. + diff --git a/client/client_priv.h b/client/client_priv.h index 656c8fcf32a..ef93818829e 100644 --- a/client/client_priv.h +++ b/client/client_priv.h @@ -92,6 +92,7 @@ enum options_client OPT_REPORT_PROGRESS, OPT_SKIP_ANNOTATE_ROWS_EVENTS, OPT_SSL_CRL, OPT_SSL_CRLPATH, + OPT_GALERA_SST_MODE, OPT_MAX_CLIENT_OPTION /* should be always the last */ }; diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index 80d57ce9faa..bf33397efdb 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -523,7 +523,12 @@ static int run_query(const char *query, DYNAMIC_STRING *ds_res, int ret; File fd; char query_file_path[FN_REFLEN]; +#ifdef WITH_WSREP + /* Note: wsrep_on=ON implicitly enables binary logging. */ + const uchar sql_log_bin[]= "SET SQL_LOG_BIN=0, WSREP_ON=OFF;"; +#else const uchar sql_log_bin[]= "SET SQL_LOG_BIN=0;"; +#endif /* WITH_WSREP */ DBUG_ENTER("run_query"); DBUG_PRINT("enter", ("query: %s", query)); diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index 57b7ce09ab5..f7ae0783e5e 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -731,9 +731,15 @@ static int use_db(char *database) DBUG_RETURN(0); } /* use_db */ +/* Do not send commands to replication slaves. */ static int disable_binlog() { +#ifdef WITH_WSREP + /* Additionally turn off @@wsrep_on to disable implicit binary logging. */ + const char *stmt= "SET SQL_LOG_BIN=0, WSREP_ON=OFF"; +#else const char *stmt= "SET SQL_LOG_BIN=0"; +#endif /* WITH_WSREP */ return run_query(stmt); } diff --git a/client/mysqldump.c b/client/mysqldump.c index cb4fa022d4f..eba5bd93671 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -111,6 +111,7 @@ static my_bool verbose= 0, opt_no_create_info= 0, opt_no_data= 0, opt_slave_apply= 0, opt_include_master_host_port= 0, opt_events= 0, opt_comments_used= 0, + opt_galera_sst_mode= 0, opt_alltspcs=0, opt_notspcs= 0; static my_bool insert_pat_inited= 0, debug_info_flag= 0, debug_check_flag= 0; static ulong opt_max_allowed_packet, opt_net_buffer_length; @@ -346,6 +347,14 @@ static struct my_option my_long_options[] = {"force", 'f', "Continue even if we get an SQL error.", &ignore_errors, &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"galera-sst-mode", OPT_GALERA_SST_MODE, + "This mode should normally be used in mysqldump snapshot state transfer " + "(SST) in a Galera cluster. If enabled, mysqldump additionally dumps " + "commands to turn off binary logging and SET global gtid_binlog_state " + "with the current value. Note: RESET MASTER needs to be executed on the " + "server receiving the resulting dump.", + &opt_galera_sst_mode, &opt_galera_sst_mode, 0, GET_BOOL, NO_ARG, 0, 0, 0, + 0, 0, 0}, {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"hex-blob", OPT_HEXBLOB, "Dump binary strings (BINARY, " @@ -4799,6 +4808,42 @@ static int dump_selected_tables(char *db, char **table_names, int tables) } /* dump_selected_tables */ +/** + Add the following statements to the generated dump: + a) SET @@session.sql_log_bin=OFF; + b) SET @@global.gtid_binlog_state='[N-N-N,...]' +*/ +static int wsrep_set_sst_cmds(MYSQL *mysql) { + MYSQL_RES *res; + MYSQL_ROW row; + + if (mysql_get_server_version(mysql) < 100005) { + /* @@gtid_binlog_state does not exist. */ + return 0; + } + + if (mysql_query_with_error_report(mysql, &res, "SELECT " + "@@global.gtid_binlog_state")) + return 1; + + if (mysql_num_rows(res) != 1) + /* No entry for @@global.gtid_binlog_state, nothing needs to be done. */ + return 0; + + if (!(row= mysql_fetch_row(res)) || !(char *)row[0]) + return 1; + + /* first, add a command to turn off binary logging, */ + fprintf(md_result_file, "SET @@session.sql_log_bin=OFF;\n"); + + /* followed by, a command to set global gtid_binlog_state. */ + fprintf(md_result_file, "SET @@global.gtid_binlog_state='%s';\n", + (char*)row[0]); + + mysql_free_result(res); + return 0; +} + static int do_show_master_status(MYSQL *mysql_con, int consistent_binlog_pos) { MYSQL_ROW row; @@ -5743,6 +5788,10 @@ int main(int argc, char **argv) /* Add 'STOP SLAVE to beginning of dump */ if (opt_slave_apply && add_stop_slave()) goto err; + + if (opt_galera_sst_mode && wsrep_set_sst_cmds(mysql)) + goto err; + if (opt_master_data && do_show_master_status(mysql, consistent_binlog_pos)) goto err; if (opt_slave_data && do_show_slave_status(mysql)) diff --git a/cmake/cpack_rpm.cmake b/cmake/cpack_rpm.cmake index 30924120526..d8f659ec5ea 100644 --- a/cmake/cpack_rpm.cmake +++ b/cmake/cpack_rpm.cmake @@ -147,9 +147,10 @@ SETA(CPACK_RPM_test_PACKAGE_OBSOLETES SETA(CPACK_RPM_test_PACKAGE_PROVIDES "MySQL-test") -SETA(CPACK_RPM_server_PACKAGE_REQUIRES - ${CPACK_RPM_PACKAGE_REQUIRES} - "MariaDB-client") +SETA(CPACK_RPM_server_PACKAGE_REQUIRES + "${CPACK_RPM_PACKAGE_REQUIRES}" + "MariaDB-client" "galera" "rsync" "lsof" "socat" "grep" "gawk" "iproute" + "coreutils" "findutils") SET(CPACK_RPM_server_PRE_INSTALL_SCRIPT_FILE ${CMAKE_SOURCE_DIR}/support-files/rpm/server-prein.sh) SET(CPACK_RPM_server_PRE_UNINSTALL_SCRIPT_FILE ${CMAKE_SOURCE_DIR}/support-files/rpm/server-preun.sh) diff --git a/cmake/plugin.cmake b/cmake/plugin.cmake index b550695b796..2dc88782937 100644 --- a/cmake/plugin.cmake +++ b/cmake/plugin.cmake @@ -153,6 +153,14 @@ MACRO(MYSQL_ADD_PLUGIN) ADD_DEPENDENCIES(${target}_embedded GenError) ENDIF() ENDIF() + + IF (WITH_WSREP) + # Set compile definitions for non-embedded plugins + LIST(APPEND wsrep_definitions "WITH_WSREP") + LIST(APPEND wsrep_definitions "WSREP_PROC_INFO") + SET_TARGET_PROPERTIES(${target} PROPERTIES + COMPILE_DEFINITIONS "${wsrep_definitions}") + ENDIF() IF(ARG_STATIC_OUTPUT_NAME) SET_TARGET_PROPERTIES(${target} PROPERTIES @@ -185,8 +193,17 @@ MACRO(MYSQL_ADD_PLUGIN) ADD_VERSION_INFO(${target} MODULE SOURCES) ADD_LIBRARY(${target} MODULE ${SOURCES}) DTRACE_INSTRUMENT(${target}) + + LIST(APPEND dyn_compile_definitions "MYSQL_DYNAMIC_PLUGIN") + + IF (WITH_WSREP) + LIST(APPEND dyn_compile_definitions "WITH_WSREP") + LIST(APPEND dyn_compile_definitions "WSREP_PROC_INFO") + ENDIF() + SET_TARGET_PROPERTIES (${target} PROPERTIES PREFIX "" - COMPILE_DEFINITIONS "MYSQL_DYNAMIC_PLUGIN") + COMPILE_DEFINITIONS "${dyn_compile_definitions}") + TARGET_LINK_LIBRARIES (${target} mysqlservices ${ARG_LINK_LIBRARIES}) # Plugin uses symbols defined in mysqld executable. @@ -207,7 +224,8 @@ MACRO(MYSQL_ADD_PLUGIN) OUTPUT_NAME "${ARG_MODULE_OUTPUT_NAME}") # Install dynamic library IF(ARG_COMPONENT) - IF(CPACK_COMPONENTS_ALL AND NOT CPACK_COMPONENTS_ALL MATCHES ${ARG_COMPONENT}) + IF(CPACK_COMPONENTS_ALL AND + NOT CPACK_COMPONENTS_ALL MATCHES ${ARG_COMPONENT}) SET(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} ${ARG_COMPONENT} PARENT_SCOPE) SET(CPACK_RPM_${ARG_COMPONENT}_PACKAGE_REQUIRES "MariaDB-server" PARENT_SCOPE) diff --git a/cmake/wsrep.cmake b/cmake/wsrep.cmake new file mode 100644 index 00000000000..7dc797e9a05 --- /dev/null +++ b/cmake/wsrep.cmake @@ -0,0 +1,76 @@ +# Copyright (c) 2011, Codership Oy . +# Copyright (c) 2013, Monty Program Ab. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +# We need to generate a proper spec file even without --with-wsrep flag, +# so WSREP_VERSION is produced regardless + +# Set the patch version +SET(WSREP_PATCH_VERSION "10") + +# MariaDB addition: Revision number of the last revision merged from +# codership branch visible in @@visible_comment. +# Branch : codership-mysql/5.6 +SET(WSREP_PATCH_REVNO "4123") # Should be updated on every merge. + +# MariaDB addition: Revision number of the last revision merged from +# Branch : lp:maria/maria-10.0-galera +SET(WSREP_PATCH_REVNO2 "3867") # Should be updated on every merge. + +# MariaDB: Obtain patch revision number: +# Update WSREP_PATCH_REVNO if WSREP_REV environment variable is set. +IF (DEFINED ENV{WSREP_REV}) + SET(WSREP_PATCH_REVNO $ENV{WSREP_REV}) +ENDIF() + +# Obtain wsrep API version +EXECUTE_PROCESS( + COMMAND sh -c "grep WSREP_INTERFACE_VERSION ${MySQL_SOURCE_DIR}/wsrep/wsrep_api.h | cut -d '\"' -f 2" + OUTPUT_VARIABLE WSREP_API_VERSION + RESULT_VARIABLE RESULT +) +#FILE(WRITE "wsrep_config" "Debug: WSREP_API_VERSION result: ${RESULT}\n") +STRING(REGEX REPLACE "(\r?\n)+$" "" WSREP_API_VERSION "${WSREP_API_VERSION}") + +IF(NOT WSREP_PATCH_REVNO) + MESSAGE(WARNING "Could not determine bzr revision number, WSREP_VERSION will " + "not contain the revision number.") + SET(WSREP_VERSION + "${WSREP_API_VERSION}.${WSREP_PATCH_VERSION}" + ) +ELSE() + SET(WSREP_VERSION + "${WSREP_API_VERSION}.${WSREP_PATCH_VERSION}.r${WSREP_PATCH_REVNO}" + ) +ENDIF() + +# +# Galera library does not compile with windows and solaris +# +IF(UNIX) +OPTION(WITH_WSREP "WSREP replication API (to use, e.g. Galera Replication library)" ON) +ELSE() +OPTION(WITH_WSREP "WSREP replication API (to use, e.g. Galera Replication library)" OFF) +ENDIF() + +MACRO (BUILD_WITH_WSREP) + SET(WSREP_C_FLAGS "-DWITH_WSREP -DWSREP_PROC_INFO -DMYSQL_MAX_VARIABLE_VALUE_LEN=2048") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WSREP_C_FLAGS}") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WSREP_C_FLAGS}") + SET(COMPILATION_COMMENT "${COMPILATION_COMMENT}, wsrep_${WSREP_VERSION}") + #SET(WITH_EMBEDDED_SERVER OFF CACHE INTERNAL "" FORCE) +ENDMACRO() + +# diff --git a/debian/dist/Debian/control b/debian/dist/Debian/control index bbee264ffc3..869e9be032c 100644 --- a/debian/dist/Debian/control +++ b/debian/dist/Debian/control @@ -192,7 +192,7 @@ Architecture: any Suggests: tinyca, mailx, mariadb-test Recommends: libhtml-template-perl Pre-Depends: mariadb-common, adduser (>= 3.40), debconf -Depends: mariadb-client-10.1 (>= ${source:Version}), libdbi-perl, perl (>= 5.6), ${shlibs:Depends}, ${misc:Depends}, psmisc, passwd, lsb-base (>= 3.0-10), mariadb-server-core-10.1 (>= ${binary:Version}) +Depends: mariadb-client-10.1 (>= ${source:Version}), libdbi-perl, perl (>= 5.6), ${shlibs:Depends}, ${misc:Depends}, psmisc, passwd, lsb-base (>= 3.0-10), mariadb-server-core-10.1 (>= ${binary:Version}), galera (>=25.2) rsync, lsof, socat, grep, gawk, iproute, coreutils, findutils Provides: mariadb-server, mysql-server, virtual-mysql-server Conflicts: mariadb-server (<< ${source:Version}), mysql-server (<< ${source:Version}), mysql-server-4.1, mysql-server-5.0, mysql-server-5.1, mysql-server-5.5, diff --git a/debian/dist/Ubuntu/control b/debian/dist/Ubuntu/control index ffcd1e5dca6..941f756ea3c 100644 --- a/debian/dist/Ubuntu/control +++ b/debian/dist/Ubuntu/control @@ -186,7 +186,7 @@ Architecture: any Suggests: tinyca, mailx, mariadb-test Recommends: libhtml-template-perl Pre-Depends: mariadb-common, adduser (>= 3.40), debconf -Depends: mariadb-client-10.1 (>= ${source:Version}), libdbi-perl, perl (>= 5.6), ${shlibs:Depends}, ${misc:Depends}, psmisc, passwd, lsb-base (>= 3.0-10), mariadb-server-core-10.1 (>= ${binary:Version}) +Depends: mariadb-client-10.1 (>= ${source:Version}), libdbi-perl, perl (>= 5.6), ${shlibs:Depends}, ${misc:Depends}, psmisc, passwd, lsb-base (>= 3.0-10), mariadb-server-core-10.1 (>= ${binary:Version}), galera (>=25.2) rsync, lsof, socat, grep, gawk, iproute, coreutils, findutils Provides: mariadb-server, mysql-server, virtual-mysql-server Conflicts: mariadb-server (<< ${source:Version}), mysql-server (<< ${source:Version}), mysql-server-4.1, mysql-server-5.0, mysql-server-5.1, mysql-server-5.5, diff --git a/include/mysql/service_logger.h b/include/mysql/service_logger.h index 962ab2fbc0b..d14b28da712 100644 --- a/include/mysql/service_logger.h +++ b/include/mysql/service_logger.h @@ -71,7 +71,7 @@ extern struct logger_service_st { int (*rotate)(LOGGER_HANDLE *log); } *logger_service; -#if MYSQL_DYNAMIC_PLUGIN +#ifdef MYSQL_DYNAMIC_PLUGIN #define logger_init_mutexes logger_service->logger_init_mutexes #define logger_open(path, size_limit, rotations) \ diff --git a/include/mysqld_default_groups.h b/include/mysqld_default_groups.h index a2e94ddd854..30dfdae1338 100644 --- a/include/mysqld_default_groups.h +++ b/include/mysqld_default_groups.h @@ -5,4 +5,7 @@ const char *load_default_groups[]= { "mysqld", "server", MYSQL_BASE_VERSION, "mariadb", MARIADB_BASE_VERSION, "client-server", +#ifdef WITH_WSREP +"galera", +#endif 0, 0}; diff --git a/include/thr_lock.h b/include/thr_lock.h index 3f7a5ca988f..2561709285f 100644 --- a/include/thr_lock.h +++ b/include/thr_lock.h @@ -20,7 +20,6 @@ #ifdef __cplusplus extern "C" { #endif - #include #include @@ -95,6 +94,7 @@ typedef struct st_thr_lock_info { pthread_t thread; my_thread_id thread_id; + void *mysql_thd; // THD pointer } THR_LOCK_INFO; @@ -164,6 +164,17 @@ my_bool thr_reschedule_write_lock(THR_LOCK_DATA *data, ulong lock_wait_timeout); void thr_set_lock_wait_callback(void (*before_wait)(void), void (*after_wait)(void)); + +#ifdef WITH_WSREP +#include + typedef my_bool (* wsrep_thd_is_brute_force_fun)(void *, my_bool); + typedef int (* wsrep_abort_thd_fun)(void *, void *, my_bool); + typedef int (* wsrep_on_fun)(void *); + void wsrep_thr_lock_init( + wsrep_thd_is_brute_force_fun bf_fun, wsrep_abort_thd_fun abort_fun, + my_bool debug, my_bool convert_LOCK_to_trx, wsrep_on_fun on_fun); +#endif + #ifdef __cplusplus } #endif diff --git a/include/wsrep.h b/include/wsrep.h new file mode 100644 index 00000000000..c261d9c4b5f --- /dev/null +++ b/include/wsrep.h @@ -0,0 +1,58 @@ +/* Copyright 2014 Codership Oy & SkySQL Ab + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef WSREP_INCLUDED +#define WSERP_INCLUDED + +#ifdef WITH_WSREP +#define IF_WSREP(A,B) A +#define DBUG_ASSERT_IF_WSREP(A) DBUG_ASSERT(A) + +#if !defined(EMBEDDED_LIBRARY) +#define WSREP_FORMAT(my_format) \ + ((wsrep_forced_binlog_format != BINLOG_FORMAT_UNSPEC) ? \ + wsrep_forced_binlog_format : my_format) +#else +#define WSREP_FORMAT(my_format) my_format +#endif /* && !EMBEDDED_LIBRARY */ + +#define WSREP_MYSQL_DB (char *)"mysql" +#define WSREP_TO_ISOLATION_BEGIN(db_, table_, table_list_) \ + if (WSREP_ON && WSREP(thd) && wsrep_to_isolation_begin(thd, db_, table_, table_list_)) \ + goto error; + +#define WSREP_TO_ISOLATION_END \ + if (WSREP_ON && (WSREP(thd) || (thd && thd->wsrep_exec_mode==TOTAL_ORDER))) \ + wsrep_to_isolation_end(thd); + +#define WSREP_DEBUG(...) \ + if (wsrep_debug) WSREP_LOG(sql_print_information, ##__VA_ARGS__) +#define WSREP_INFO(...) WSREP_LOG(sql_print_information, ##__VA_ARGS__) +#define WSREP_WARN(...) WSREP_LOG(sql_print_warning, ##__VA_ARGS__) +#define WSREP_ERROR(...) WSREP_LOG(sql_print_error, ##__VA_ARGS__) + +#else +#define IF_WSREP(A,B) B +#define DBUG_ASSERT_IF_WSREP(A) +#define WSREP_DEBUG(...) +#define WSREP_INFO(...) +#define WSREP_WARN(...) +#define WSREP_ERROR(...) +#define WSREP_FORMAT(my_format) my_format +#define WSREP_TO_ISOLATION_BEGIN(db_, table_, table_list_) +#define WSREP_TO_ISOLATION_END +#endif + +#endif /* WSERP_INCLUDED */ diff --git a/mysql-test/extra/binlog_tests/binlog.test b/mysql-test/extra/binlog_tests/binlog.test index ce5dde97894..831c6c886d5 100644 --- a/mysql-test/extra/binlog_tests/binlog.test +++ b/mysql-test/extra/binlog_tests/binlog.test @@ -372,7 +372,8 @@ dfLtTBcBAAAAIgAAAPkAAAAAABcAAAAAAAcAAf/+AQAAAA== SELECT * FROM t1; --echo # Their values should be ON -SHOW SESSION VARIABLES LIKE "%_checks"; +SHOW SESSION VARIABLES LIKE "foreign_key_checks"; +SHOW SESSION VARIABLES LIKE "unique_checks"; --echo SET @@SESSION.foreign_key_checks= OFF; @@ -387,7 +388,8 @@ dfLtTBcBAAAAIgAAAM0BAAAAABcAAAAAAAEAAf/+AgAAAA== SELECT * FROM t1; --echo # Their values should be OFF -SHOW SESSION VARIABLES LIKE "%_checks"; +SHOW SESSION VARIABLES LIKE "foreign_key_checks"; +SHOW SESSION VARIABLES LIKE "unique_checks"; --echo # INSERT INTO t1 VALUES(2) --echo # foreign_key_checks=1 and unique_checks=1 @@ -401,7 +403,8 @@ dfLtTBcBAAAAIgAAAM0BAAAAABcAAAAAAAEAAf/+AgAAAA== SELECT * FROM t1; --echo # Their values should be OFF -SHOW SESSION VARIABLES LIKE "%_checks"; +SHOW SESSION VARIABLES LIKE "foreign_key_checks"; +SHOW SESSION VARIABLES LIKE "unique_checks"; DROP TABLE t1; diff --git a/mysql-test/include/galera_cluster.inc b/mysql-test/include/galera_cluster.inc new file mode 100644 index 00000000000..bc652225722 --- /dev/null +++ b/mysql-test/include/galera_cluster.inc @@ -0,0 +1,10 @@ +# galera_cluster.inc +# ================== +# +# Description +# ----------- +# Configure galera cluster with 2 nodes. +# + +--let $galera_cluster_size = 2 +--source include/galera_init.inc diff --git a/mysql-test/include/galera_connect.inc b/mysql-test/include/galera_connect.inc new file mode 100644 index 00000000000..bfd9b188667 --- /dev/null +++ b/mysql-test/include/galera_connect.inc @@ -0,0 +1,45 @@ +# galera_connect.inc +# ================== +# +# Description +# ----------- +# Open a connection to the specified server number ($galera_server_number). +# The connection itself would be identified by $galera_connection_name. +# +# Parameters +# ---------- +# $galera_connection_name +# Name of the resulting connection. +# +# $galera_server_number +# Sequence number of the node in the galera cluster. +# +# $galera_debug +# Print debug information. +# + +if (!$galera_connection_name) +{ + --die ERROR IN TEST: $galera_connection_name must be set before sourcing include/galera_connect.inc +} + +if (!$galera_server_number) +{ + --die ERROR IN TEST: $galera_server_number must be set before sourcing include/galera_connect.inc +} + +--let $_galera_port= \$NODE_MYPORT_$galera_server_number +if (!$_galera_port) +{ + --echo Bug in test case: '\$NODE_MYPORT_$galera_server_number' not initialized. Check the test's .cfg file. + --die Not all NODE_MYPORT_* environment variables are setup correctly. +} + +if ($galera_debug) +{ + --echo connect($galera_connection_name,127.0.0.1,root,,test,$_galera_port,) +} + +# Open a connection +--connect($galera_connection_name,127.0.0.1,root,,test,$_galera_port,) + diff --git a/mysql-test/include/galera_diff.inc b/mysql-test/include/galera_diff.inc new file mode 100644 index 00000000000..6043b582647 --- /dev/null +++ b/mysql-test/include/galera_diff.inc @@ -0,0 +1,100 @@ +# galera_diff.inc +# =============== +# +# Description +# ----------- +# Compare the output of the given statement on all the nodes of the cluster. +# +# Parameters +# ---------- +# $galera_diff_statement +# Statement for which the output would be compared. +# +# $galera_diff_database +# Database against which the above statement would be executed. +# (Default : test) +# +# $galera_diff_servers +# Comma separated list of servers to executed the diff statement on. If not +# set, a list of servers will be generated based on $galera_cluster_size. +# +# $galerra_debug +# Print debug information. +# + +if (!$galera_diff_statement) +{ + --die ERROR IN TEST: $galera_diff_statement must be set before sourcing include/galera_diff.inc +} + +--let $_galera_diff_database = $galera_diff_database +if (!$_galera_diff_database) +{ + --let $_galera_diff_database = test +} + +--let $_galera_diff_servers= $galera_diff_servers +if (!$_galera_diff_servers) +{ + --let $_i= $galera_cluster_size + --let $_galera_diff_servers= + while ($_i) + { + --let $_galera_diff_servers= $_i,$_galera_diff_servers + --dec $_i + } +} +if ($galera_debug) +{ + --echo \$galera_diff_servers= '$_galera_diff_servers' +} + +if (!$galera_debug) +{ + --disable_query_log +} + +# Generate file containing $galera_diff_statement. We don't pass the +# statement on the command line, because it would be subject to shell +# substitutions. +--let $write_to_file= GENERATE +--let $write_var= $galera_diff_statement +--source include/write_var_to_file.inc +--let $_galera_diff_statement_file= $write_to_file + +if (!$galera_debug) +{ + --enable_query_log +} + +# Compare all servers. +--let $_galera_diff_first= 1 +while ($_galera_diff_servers) +{ + # Set $_galera_diff_server_i to the first number in the list + --let $_galera_diff_server_i= `SELECT SUBSTRING_INDEX('$_galera_diff_servers', ',', 1)` + # Remove $_galera_diff_server_i from the list + --let $_galera_diff_servers= `SELECT SUBSTRING('$_galera_diff_servers', LENGTH('$_galera_diff_server_i') + 2)` + + # Execute statement + --let $_galera_diff_file= $MYSQLTEST_VARDIR/tmp/_galera_diff_server-$_galera_diff_server_i.tmp + --exec $MYSQL --defaults-group-suffix=.$_galera_diff_server_i $_galera_diff_database < $_galera_diff_statement_file > $_galera_diff_file + + # Compare + if (!$_galera_diff_first) + { + if ($galera_debug) + { + --echo diffing $_galera_diff_file and $_galera_diff_prev_file + } + --diff_files $_galera_diff_file $_galera_diff_prev_file + --remove_file $_galera_diff_prev_file + } + --let $_galera_diff_prev_file= $_galera_diff_file + --let $_galera_diff_first= 0 +} + +# Cleanup +--remove_file $_galera_diff_prev_file +--remove_file $_galera_diff_statement_file + diff --git a/mysql-test/include/galera_end.inc b/mysql-test/include/galera_end.inc new file mode 100644 index 00000000000..0fb5479844e --- /dev/null +++ b/mysql-test/include/galera_end.inc @@ -0,0 +1,25 @@ +# galera_end.inc +# ============== +# +# Description +# ----------- +# Closes the connections opened via include/galera_init.inc +# +# Parameters +# ---------- +# $galera_cluster_size +# Number of nodes in the cluster. +# + +--let $_galera_node= $galera_cluster_size + +while ($_galera_node) +{ + if ($galera_debug) + { + --echo Disconnecting node_$_galera_node + } + --disconnect node_$_galera_node + --dec $_galera_node +} + diff --git a/mysql-test/include/galera_init.inc b/mysql-test/include/galera_init.inc new file mode 100644 index 00000000000..79591973862 --- /dev/null +++ b/mysql-test/include/galera_init.inc @@ -0,0 +1,26 @@ +# galera_init.inc +# =============== +# +# Description +# ----------- +# Set up a Galera cluster with $wsrep_cluster_size nodes. +# +# Parameters +# ---------- +# $galera_cluster_size +# Number of nodes in the cluster. +# + +--source include/have_wsrep_enabled.inc + +--let $_galera_node= $galera_cluster_size + +while ($_galera_node) +{ + --let $galera_connection_name= node_$_galera_node + --let $galera_server_number= $_galera_node + --source include/galera_connect.inc + + --dec $_galera_node +} + diff --git a/mysql-test/include/have_innodb_disallow_writes.inc b/mysql-test/include/have_innodb_disallow_writes.inc new file mode 100644 index 00000000000..83b516b7a34 --- /dev/null +++ b/mysql-test/include/have_innodb_disallow_writes.inc @@ -0,0 +1,6 @@ +--source include/have_innodb.inc + +if (`SELECT COUNT(*) = 0 from INFORMATION_SCHEMA.GLOBAL_VARIABLES + WHERE VARIABLE_NAME = 'INNODB_DISALLOW_WRITES'`) { + --skip Test requires 'innodb_disallow_writes' +} diff --git a/mysql-test/include/have_wsrep.inc b/mysql-test/include/have_wsrep.inc new file mode 100644 index 00000000000..52220edf481 --- /dev/null +++ b/mysql-test/include/have_wsrep.inc @@ -0,0 +1,8 @@ +# To be used in a test which requires server to be compiled with wsrep support +# (-DWITH_WSREP=ON) and wsrep plugin is ACTIVE. + +if (`SELECT COUNT(*)=0 FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = 'wsrep' AND PLUGIN_STATUS='ACTIVE'`) +{ + --skip Test requires wsrep plugin. +} + diff --git a/mysql-test/include/have_wsrep_enabled.inc b/mysql-test/include/have_wsrep_enabled.inc new file mode 100644 index 00000000000..edb919fd852 --- /dev/null +++ b/mysql-test/include/have_wsrep_enabled.inc @@ -0,0 +1,9 @@ +# To be used in a test which requires wsrep plugin to be ACTIVE and enabled +# (i.e. wsrep_on=ON). It includes have_wsrep.inc. + +--source include/have_wsrep.inc + +--require r/have_wsrep.require +disable_query_log; +SHOW VARIABLES LIKE 'wsrep_on'; +enable_query_log; diff --git a/mysql-test/include/mtr_check.sql b/mysql-test/include/mtr_check.sql index e34e32ad1a6..edc15850d97 100644 --- a/mysql-test/include/mtr_check.sql +++ b/mysql-test/include/mtr_check.sql @@ -34,6 +34,7 @@ BEGIN AND variable_name != 'INNODB_USE_NATIVE_AIO' AND variable_name not like 'GTID%POS' AND variable_name != 'GTID_BINLOG_STATE' + AND variable_name != 'WSREP_DATA_HOME_DIR' ORDER BY variable_name; -- Dump all databases, there should be none diff --git a/mysql-test/include/mtr_warnings.sql b/mysql-test/include/mtr_warnings.sql index 0ad1079cd92..06a7b49e979 100644 --- a/mysql-test/include/mtr_warnings.sql +++ b/mysql-test/include/mtr_warnings.sql @@ -226,6 +226,14 @@ INSERT INTO global_suppressions VALUES ("Slave I/O: Notifying master by SET @master_binlog_checksum= @@global.binlog_checksum failed with error.*"), ("Slave I/O: Setting master-side filtering of @@skip_replication failed with error:.*"), ("Slave I/O: Setting @mariadb_slave_capability failed with error:.*"), + + /* + Galera-related warnings. + */ + ("WSREP: Could not open saved state file for reading: .*"), + ("WSREP: last inactive check more than .* skipping check"), + ("WSREP: Gap in state sequence. Need state transfer."), + ("WSREP: Failed to prepare for incremental state transfer: .*"), ("THE_LAST_SUPPRESSION")|| diff --git a/mysql-test/include/not_wsrep.inc b/mysql-test/include/not_wsrep.inc new file mode 100644 index 00000000000..3314b5c8717 --- /dev/null +++ b/mysql-test/include/not_wsrep.inc @@ -0,0 +1,7 @@ +# To be used in a test which should be skipped if server is compiled with wsrep +# support (-DWITH_WSREP=ON) and wsrep plugin is ACTIVE. + +-- require r/not_wsrep.require +disable_query_log; +SELECT VERSION() LIKE '%wsrep%' AS 'HAVE_WSREP'; +enable_query_log; diff --git a/mysql-test/include/write_result_to_file.inc b/mysql-test/include/write_result_to_file.inc index 3e2ddf48957..db5d546750c 100644 --- a/mysql-test/include/write_result_to_file.inc +++ b/mysql-test/include/write_result_to_file.inc @@ -33,7 +33,8 @@ --let _WRTF_SERVER_NUMBER= $server_number if (!$server_number) { - --let _WRTF_SERVER_NUMBER= `SELECT 1 + @@PORT - $MASTER_MYPORT` + # Note: 2 extra ports are reserved per server for galera use. + --let _WRTF_SERVER_NUMBER= `SELECT 1 + FLOOR((@@PORT - $MASTER_MYPORT) / 3)` } --let $_write_result_msg= [server=$_WRTF_SERVER_NUMBER] diff --git a/mysql-test/lib/My/ConfigFactory.pm b/mysql-test/lib/My/ConfigFactory.pm index 4e8507a5c4a..488b0823763 100644 --- a/mysql-test/lib/My/ConfigFactory.pm +++ b/mysql-test/lib/My/ConfigFactory.pm @@ -238,6 +238,9 @@ my @mysqld_rules= { 'pid-file' => \&fix_pidfile }, { '#host' => \&fix_host }, { 'port' => \&fix_port }, + # galera base_port and port used during SST + { '#galera_port' => \&fix_port }, + { '#sst_port' => \&fix_port }, { 'socket' => \&fix_socket }, { '#log-error' => \&fix_log_error }, { 'general-log' => 1 }, diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm index 441fd6e6559..7415b229862 100644 --- a/mysql-test/lib/mtr_cases.pm +++ b/mysql-test/lib/mtr_cases.pm @@ -861,6 +861,8 @@ sub collect_one_test_case { # Suite has no config, autodetect which one to use if ($tinfo->{rpl_test}) { $config= "suite/rpl/my.cnf"; + } elsif ($tinfo->{galera_test}) { + $config= "suite/galera/my.cnf"; } else { $config= "include/default_my.cnf"; } @@ -981,6 +983,7 @@ my $tags_map= {'big_test' => ['big_test', 1], 'master-slave' => ['rpl_test', 1], 'ndb_master-slave' => ['rpl_test', 1, 'ndb_test', 1], 'long_test' => ['long_test', 1], + 'galera_init' => ['galera_test', 1], }; my $tags_regex_string= join('|', keys %$tags_map); my $tags_regex= qr:include/($tags_regex_string)\.inc:o; diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index c2d44bf4db1..61f9538c1b4 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -135,6 +135,7 @@ my $opt_start; my $opt_start_dirty; my $opt_start_exit; my $start_only; +my $file_wsrep_provider; END { if ( defined $opt_tmpdir_pid and $opt_tmpdir_pid == $$ ) @@ -412,6 +413,7 @@ sub main { check_ndbcluster_support(); check_ssl_support(); check_debug_support(); + check_wsrep_support(); if (!$opt_suites) { $opt_suites= join ',', collect_default_suites(@DEFAULT_SUITES); @@ -2397,6 +2399,24 @@ sub environment_setup { $ENV{'NDB_EXAMPLES_OUTPUT'}= $path_ndb_testrun_log; } + # ---------------------------------------------------- + # Setup env for wsrep + # ---------------------------------------------------- + if (have_wsrep()) { + if (defined $ENV{'WSREP_PROVIDER'} ) { + # Nothing needs to be done! WSREP_PROVIDER env is already set & checked; + # will be used. + } else { + $ENV{'WSREP_PROVIDER'}= $file_wsrep_provider; + } + + if ($ENV{'WSREP_PROVIDER'} ne "") { + mtr_verbose("WSREP_PROVIDER set to $ENV{'WSREP_PROVIDER'}"); + } else { + mtr_verbose("WSREP_PROVIDER isn't available"); + } + } + # ---------------------------------------------------- # mysql clients # ---------------------------------------------------- @@ -3174,6 +3194,40 @@ sub ndbcluster_start ($) { return 0; } +sub have_wsrep() { + my $wsrep_on= $mysqld_variables{'wsrep-on'}; + return defined $wsrep_on +} + +sub check_wsrep_provider_env { + if (defined $ENV{'WSREP_PROVIDER'}) { + if (mtr_file_exists($ENV{'WSREP_PROVIDER'}) eq "") { + mtr_error("WSREP_PROVIDER env set to an invalid path"); + return 0; # error + } + # Ok, WSREP_PROVIDER set to a valid path. + return 1; + } + # Ok, WSREP_PROVIDER not defined. + return 2; +} + +sub check_wsrep_support() { + if (have_wsrep()) + { + mtr_report(" - binaries built with wsrep patch"); + + $file_wsrep_provider= + mtr_file_exists("/usr/lib/galera/libgalera_smm.so", + "/usr/lib64/galera/libgalera_smm.so"); + + if ((check_wsrep_provider_env() == 1) || ($file_wsrep_provider ne "")) { + # Add galera test suites + mtr_report(" - adding wsrep, galera to default test suites"); + push @DEFAULT_SUITES, qw(wsrep galera); + } + } +} sub mysql_server_start($) { my ($mysqld, $tinfo) = @_; @@ -4837,6 +4891,10 @@ sub extract_warning_lines ($$) { qr|Plugin 'FEEDBACK' registration as a INFORMATION SCHEMA failed|, qr|'log-bin-use-v1-row-events' is MySQL 5.6 compatible option|, qr|InnoDB: Setting thread \d+ nice to \d+ failed, current nice \d+, errno 13|, # setpriority() fails under valgrind + # Galera-related warnings. + qr|WSREP:.*down context.*|, + qr|WSREP: Failed to send state UUID:.*|, + qr|WSREP: wsrep_sst_receive_address.*|, ); my $matched_lines= []; diff --git a/mysql-test/r/have_wsrep.require b/mysql-test/r/have_wsrep.require new file mode 100644 index 00000000000..af32ac7dca7 --- /dev/null +++ b/mysql-test/r/have_wsrep.require @@ -0,0 +1,2 @@ +Variable_name Value +wsrep_on ON diff --git a/mysql-test/r/mysql_tzinfo_to_sql_symlink.result b/mysql-test/r/mysql_tzinfo_to_sql_symlink.result index dda732937ee..484f71a4c2e 100644 --- a/mysql-test/r/mysql_tzinfo_to_sql_symlink.result +++ b/mysql-test/r/mysql_tzinfo_to_sql_symlink.result @@ -1,6 +1,7 @@ # # MDEV-5226 mysql_tzinfo_to_sql errors with tzdata 2013f and above # +SET SESSION wsrep_replicate_myisam=ON; # Verbose run TRUNCATE TABLE time_zone; TRUNCATE TABLE time_zone_name; diff --git a/mysql-test/r/mysqld--help.result b/mysql-test/r/mysqld--help.result index 5a2142c402c..6953a05fd5c 100644 --- a/mysql-test/r/mysqld--help.result +++ b/mysql-test/r/mysqld--help.result @@ -1065,6 +1065,93 @@ The following options may be given as the first argument: -V, --version Output version information and exit. --wait-timeout=# The number of seconds the server waits for activity on a connection before closing it + --wsrep-OSU-method[=name] + Method for Online Schema Upgrade + --wsrep-auto-increment-control + To automatically control the assignment of autoincrement + variables + (Defaults to on; use --skip-wsrep-auto-increment-control to disable.) + --wsrep-causal-reads + (DEPRECATED) Setting this variable is equivalent to + setting wsrep_sync_wait READ flag + --wsrep-certify-nonPK + Certify tables with no primary key + (Defaults to on; use --skip-wsrep-certify-nonPK to disable.) + --wsrep-cluster-address=name + Address to initially connect to cluster + --wsrep-cluster-name=name + Name for the cluster + --wsrep-convert-LOCK-to-trx + To convert locking sessions into transactions + --wsrep-data-home-dir=name + home directory for wsrep provider + --wsrep-dbug-option=name + DBUG options to provider library + --wsrep-debug To enable debug level logging + --wsrep-desync To desynchronize the node from the cluster + --wsrep-drupal-282555-workaround + To use a workaround forbad autoincrement value + --wsrep-forced-binlog-format=name + binlog format to take effect over user's choice + --wsrep-load-data-splitting + To commit LOAD DATA transaction after every 10K rows + inserted + (Defaults to on; use --skip-wsrep-load-data-splitting to disable.) + --wsrep-log-conflicts + To log multi-master conflicts + --wsrep-max-ws-rows=# + Max number of rows in write set + --wsrep-max-ws-size=# + Max write set size (bytes) + --wsrep-mysql-replication-bundle=# + mysql replication group commit + --wsrep-node-address=name + Node address + --wsrep-node-incoming-address=name + Client connection address + --wsrep-node-name=name + Node name + --wsrep-notify-cmd=name + --wsrep-on To enable wsrep replication + (Defaults to on; use --skip-wsrep-on to disable.) + --wsrep-provider=name + Path to replication provider library + --wsrep-provider-options=name + provider specific options + --wsrep-recover Recover database state after crash and exit + --wsrep-replicate-myisam + To enable myisam replication + --wsrep-restart-slave + Should MySQL slave be restarted automatically, when node + joins back to cluster + --wsrep-retry-autocommit=# + Max number of times to retry a failed autocommit + statement + --wsrep-slave-FK-checks + Should slave thread do foreign key constraint checks + (Defaults to on; use --skip-wsrep-slave-FK-checks to disable.) + --wsrep-slave-UK-checks + Should slave thread do secondary index uniqueness checks + --wsrep-slave-threads=# + Number of slave appliers to launch + --wsrep-sst-auth=name + Authentication for SST connection + --wsrep-sst-donor=name + preferred donor node for the SST + --wsrep-sst-donor-rejects-queries + Reject client queries when donating state snapshot + transfer + --wsrep-sst-method=name + State snapshot transfer method + --wsrep-sst-receive-address=name + Address where node is waiting for SST contact + --wsrep-start-position=name + global transaction position to start from + --wsrep-sync-wait[=#] + Ensure "synchronous" read view before executing an + operation of the type specified by bitmask: 1 - + READ(includes SELECT, SHOW and BEGIN/START TRANSACTION); + 2 - UPDATE and DELETE; 4 - INSERT and REPLACE Variables (--variable-name=value) allow-suspicious-udfs FALSE @@ -1364,6 +1451,44 @@ use-stat-tables NEVER userstat FALSE verbose TRUE wait-timeout 28800 +wsrep-OSU-method TOI +wsrep-auto-increment-control TRUE +wsrep-causal-reads FALSE +wsrep-certify-nonPK TRUE +wsrep-cluster-address +wsrep-cluster-name my_wsrep_cluster +wsrep-convert-LOCK-to-trx FALSE +wsrep-data-home-dir +wsrep-dbug-option +wsrep-debug FALSE +wsrep-desync FALSE +wsrep-drupal-282555-workaround FALSE +wsrep-forced-binlog-format NONE +wsrep-load-data-splitting TRUE +wsrep-log-conflicts FALSE +wsrep-max-ws-rows 131072 +wsrep-max-ws-size 1073741824 +wsrep-mysql-replication-bundle 0 +wsrep-node-address +wsrep-node-incoming-address AUTO +wsrep-notify-cmd +wsrep-on FALSE +wsrep-provider none +wsrep-provider-options +wsrep-recover FALSE +wsrep-replicate-myisam FALSE +wsrep-restart-slave FALSE +wsrep-retry-autocommit 1 +wsrep-slave-FK-checks TRUE +wsrep-slave-UK-checks FALSE +wsrep-slave-threads 1 +wsrep-sst-auth (No default value) +wsrep-sst-donor +wsrep-sst-donor-rejects-queries FALSE +wsrep-sst-method rsync +wsrep-sst-receive-address AUTO +wsrep-start-position 00000000-0000-0000-0000-000000000000:-1 +wsrep-sync-wait 0 To see what values a running MySQL server is using, type 'mysqladmin variables' instead of 'mysqld --verbose --help'. diff --git a/mysql-test/r/not_wsrep.require b/mysql-test/r/not_wsrep.require new file mode 100644 index 00000000000..7c8e74af144 --- /dev/null +++ b/mysql-test/r/not_wsrep.require @@ -0,0 +1,2 @@ +HAVE_WSREP +0 diff --git a/mysql-test/suite/binlog/r/binlog_row_binlog.result b/mysql-test/suite/binlog/r/binlog_row_binlog.result index 20a4b52f1a7..05009c5a570 100644 --- a/mysql-test/suite/binlog/r/binlog_row_binlog.result +++ b/mysql-test/suite/binlog/r/binlog_row_binlog.result @@ -806,9 +806,11 @@ SELECT * FROM t1; c1 1 # Their values should be ON -SHOW SESSION VARIABLES LIKE "%_checks"; +SHOW SESSION VARIABLES LIKE "foreign_key_checks"; Variable_name Value foreign_key_checks ON +SHOW SESSION VARIABLES LIKE "unique_checks"; +Variable_name Value unique_checks ON SET @@SESSION.foreign_key_checks= OFF; @@ -824,9 +826,11 @@ c1 1 2 # Their values should be OFF -SHOW SESSION VARIABLES LIKE "%_checks"; +SHOW SESSION VARIABLES LIKE "foreign_key_checks"; Variable_name Value foreign_key_checks OFF +SHOW SESSION VARIABLES LIKE "unique_checks"; +Variable_name Value unique_checks OFF # INSERT INTO t1 VALUES(2) # foreign_key_checks=1 and unique_checks=1 @@ -842,8 +846,10 @@ c1 1 2 # Their values should be OFF -SHOW SESSION VARIABLES LIKE "%_checks"; +SHOW SESSION VARIABLES LIKE "foreign_key_checks"; Variable_name Value foreign_key_checks OFF +SHOW SESSION VARIABLES LIKE "unique_checks"; +Variable_name Value unique_checks OFF DROP TABLE t1; diff --git a/mysql-test/suite/binlog/r/binlog_stm_binlog.result b/mysql-test/suite/binlog/r/binlog_stm_binlog.result index 824bf3ed2a0..3a6af15e88a 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_binlog.result +++ b/mysql-test/suite/binlog/r/binlog_stm_binlog.result @@ -618,9 +618,11 @@ SELECT * FROM t1; c1 1 # Their values should be ON -SHOW SESSION VARIABLES LIKE "%_checks"; +SHOW SESSION VARIABLES LIKE "foreign_key_checks"; Variable_name Value foreign_key_checks ON +SHOW SESSION VARIABLES LIKE "unique_checks"; +Variable_name Value unique_checks ON SET @@SESSION.foreign_key_checks= OFF; @@ -636,9 +638,11 @@ c1 1 2 # Their values should be OFF -SHOW SESSION VARIABLES LIKE "%_checks"; +SHOW SESSION VARIABLES LIKE "foreign_key_checks"; Variable_name Value foreign_key_checks OFF +SHOW SESSION VARIABLES LIKE "unique_checks"; +Variable_name Value unique_checks OFF # INSERT INTO t1 VALUES(2) # foreign_key_checks=1 and unique_checks=1 @@ -654,8 +658,10 @@ c1 1 2 # Their values should be OFF -SHOW SESSION VARIABLES LIKE "%_checks"; +SHOW SESSION VARIABLES LIKE "foreign_key_checks"; Variable_name Value foreign_key_checks OFF +SHOW SESSION VARIABLES LIKE "unique_checks"; +Variable_name Value unique_checks OFF DROP TABLE t1; diff --git a/mysql-test/suite/galera/galera_2nodes.cnf b/mysql-test/suite/galera/galera_2nodes.cnf new file mode 100644 index 00000000000..5a08125089a --- /dev/null +++ b/mysql-test/suite/galera/galera_2nodes.cnf @@ -0,0 +1,24 @@ +# Use default setting for mysqld processes +!include include/default_mysqld.cnf + +[mysqld.1] +binlog-format=row +wsrep_provider=@ENV.WSREP_PROVIDER +wsrep_cluster_address='gcomm://' +wsrep_provider_options='base_port=@mysqld.1.#galera_port' +wsrep_sst_receive_address='127.0.0.1:@mysqld.1.#sst_port' + +[mysqld.2] +binlog-format=row +wsrep_provider=@ENV.WSREP_PROVIDER +wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port' +wsrep_provider_options='base_port=@mysqld.2.#galera_port' +wsrep_sst_receive_address='127.0.0.1:@mysqld.2.#sst_port' + +[ENV] +NODE_MYPORT_1= @mysqld.1.port +NODE_MYSOCK_1= @mysqld.1.socket + +NODE_MYPORT_2= @mysqld.2.port +NODE_MYSOCK_2= @mysqld.2.socket + diff --git a/mysql-test/suite/galera/my.cnf b/mysql-test/suite/galera/my.cnf new file mode 100644 index 00000000000..ca163a540d9 --- /dev/null +++ b/mysql-test/suite/galera/my.cnf @@ -0,0 +1 @@ +!include galera_2nodes.cnf diff --git a/mysql-test/suite/galera/r/basic.result b/mysql-test/suite/galera/r/basic.result new file mode 100644 index 00000000000..d4efe348b61 --- /dev/null +++ b/mysql-test/suite/galera/r/basic.result @@ -0,0 +1,30 @@ +USE test; +CREATE TABLE t1(c1 INT PRIMARY KEY) ENGINE=INNODB; +INSERT INTO t1 VALUES (1), (2), (3), (4), (5); +SELECT * FROM t1; +c1 +1 +2 +3 +4 +5 + +# On node_1 +SELECT * FROM test.t1; +c1 +1 +2 +3 +4 +5 + +# On node_2 +SELECT * FROM test.t1; +c1 +1 +2 +3 +4 +5 +DROP TABLE t1; +# End of test diff --git a/mysql-test/suite/galera/r/galera_sst_mode.result b/mysql-test/suite/galera/r/galera_sst_mode.result new file mode 100644 index 00000000000..ea25b322449 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_sst_mode.result @@ -0,0 +1,24 @@ +# +# Test for mysqldump's galera-sst-mode option +# +# +# MDEV-6490: mysqldump unknown option --galera-sst-mode +# +CREATE DATABASE bug6490; +USE bug6490; +CREATE TABLE t1(c1 INT); +INSERT INTO t1 values (1); +INSERT INTO t1 values (2); +# Save the current gtid_binlog_state. +# Take a dump of bug6490 database +DROP TABLE t1; +# Load the dump +RESET MASTER; +SELECT * from t1; +c1 +1 +2 +# Compare the two gtid_binlog_state's +# Cleanup +DROP DATABASE bug6490; +# End of test diff --git a/mysql-test/suite/galera/r/grant.result b/mysql-test/suite/galera/r/grant.result new file mode 100644 index 00000000000..8d257e7e8e2 --- /dev/null +++ b/mysql-test/suite/galera/r/grant.result @@ -0,0 +1,17 @@ +# +# MDEV#6266: Changing password fails on galera cluster +# + +# On node_1 +GRANT SELECT ON *.* TO 'user_6266'@'localhost' IDENTIFIED BY 'pass'; + +# Now, try changing password for 'user_6266'. This command should also +# execute successfully on the other node. +SET PASSWORD FOR 'user_6266'@'localhost' = PASSWORD('newpass'); + +# On node_2 +SELECT user FROM mysql.user WHERE user='user_6266'; +user +user_6266 +DROP USER 'user_6266'@'localhost'; +# End of test diff --git a/mysql-test/suite/galera/r/partition.result b/mysql-test/suite/galera/r/partition.result new file mode 100644 index 00000000000..60fb2ed298d --- /dev/null +++ b/mysql-test/suite/galera/r/partition.result @@ -0,0 +1,23 @@ +# +# MDEV#4953 Galera: DELETE from a partitioned table is not replicated +# +USE test; +CREATE TABLE t1 (pk INT PRIMARY KEY, i INT) ENGINE=INNODB PARTITION BY HASH(pk) PARTITIONS 2; +INSERT INTO t1 VALUES (1,100), (2,200); +SELECT * FROM t1; +pk i +2 200 +1 100 +DELETE FROM t1; +SELECT * FROM t1; +pk i + +# On node_1 +SELECT * FROM t1; +pk i + +# On node_2 +SELECT * FROM t1; +pk i +DROP TABLE t1; +# End of test diff --git a/mysql-test/suite/galera/r/unique_key.result b/mysql-test/suite/galera/r/unique_key.result new file mode 100644 index 00000000000..ffb4f01c1f8 --- /dev/null +++ b/mysql-test/suite/galera/r/unique_key.result @@ -0,0 +1,47 @@ +# +# MDEV#5552 Deadlock when inserting NULL column value in column with +# UNIQUE index +# +USE test; + +# On node_1 +CREATE TABLE t1(c1 INT DEFAULT NULL, UNIQUE KEY c1(c1)) ENGINE=INNODB; +INSERT INTO t1 VALUES (NULL); +INSERT INTO t1 VALUES (NULL); +SELECT * FROM test.t1; +c1 +NULL +NULL + +# On node_2 +SELECT * FROM test.t1; +c1 +NULL +NULL + +# On node_1 +INSERT INTO t1 VALUES (1); +UPDATE t1 SET c1=NULL WHERE c1=1; +SELECT * FROM test.t1; +c1 +NULL +NULL +NULL + +# On node_2 +SELECT * FROM test.t1; +c1 +NULL +NULL +NULL + +# On node_1 +DELETE FROM t1 WHERE c1<=>NULL; +SELECT * FROM test.t1; +c1 + +# On node_2 +SELECT * FROM test.t1; +c1 +DROP TABLE t1; +# End of test diff --git a/mysql-test/suite/galera/t/basic.test b/mysql-test/suite/galera/t/basic.test new file mode 100644 index 00000000000..8fc6eee3b3b --- /dev/null +++ b/mysql-test/suite/galera/t/basic.test @@ -0,0 +1,26 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +USE test; +CREATE TABLE t1(c1 INT PRIMARY KEY) ENGINE=INNODB; +INSERT INTO t1 VALUES (1), (2), (3), (4), (5); +SELECT * FROM t1; + +--echo +--echo # On node_1 +--connection node_1 +SELECT * FROM test.t1; + +--echo +--echo # On node_2 +--connection node_2 +SELECT * FROM test.t1; + +--let $galera_diff_statement = SELECT * FROM t1 +--source include/galera_diff.inc + +# Cleanup +DROP TABLE t1; + +--source include/galera_end.inc +--echo # End of test diff --git a/mysql-test/suite/galera/t/galera_sst_mode.test b/mysql-test/suite/galera/t/galera_sst_mode.test new file mode 100644 index 00000000000..dd8f9531c9d --- /dev/null +++ b/mysql-test/suite/galera/t/galera_sst_mode.test @@ -0,0 +1,43 @@ +# Embedded server doesn't support external clients +--source include/not_embedded.inc +# Binlog is required +--source include/have_log_bin.inc + +--echo # +--echo # Test for mysqldump's galera-sst-mode option +--echo # + +--echo # +--echo # MDEV-6490: mysqldump unknown option --galera-sst-mode +--echo # +CREATE DATABASE bug6490; +USE bug6490; +CREATE TABLE t1(c1 INT); +INSERT INTO t1 values (1); +INSERT INTO t1 values (2); + +--echo # Save the current gtid_binlog_state. +--let $before= `SELECT @@global.gtid_binlog_state` + +--echo # Take a dump of bug6490 database +--exec $MYSQL_DUMP --galera-sst-mode bug6490 > $MYSQLTEST_VARDIR/tmp/bug6490.sql +DROP TABLE t1; + +--echo # Load the dump +RESET MASTER; +--exec $MYSQL -uroot bug6490 < $MYSQLTEST_VARDIR/tmp/bug6490.sql + +SELECT * from t1; + +--echo # Compare the two gtid_binlog_state's +--let $after= `SELECT @@global.gtid_binlog_state` +if (`SELECT STRCMP($before, $after)`) +{ + --die ERROR: The two gtid_binlog_state's did not match. +} + +--echo # Cleanup +--remove_file $MYSQLTEST_VARDIR/tmp/bug6490.sql +DROP DATABASE bug6490; + +--echo # End of test diff --git a/mysql-test/suite/galera/t/grant.test b/mysql-test/suite/galera/t/grant.test new file mode 100644 index 00000000000..de1c202cfbb --- /dev/null +++ b/mysql-test/suite/galera/t/grant.test @@ -0,0 +1,25 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +--echo # +--echo # MDEV#6266: Changing password fails on galera cluster +--echo # + +--echo +--echo # On node_1 +--connection node_1 +GRANT SELECT ON *.* TO 'user_6266'@'localhost' IDENTIFIED BY 'pass'; +--echo +--echo # Now, try changing password for 'user_6266'. This command should also +--echo # execute successfully on the other node. +SET PASSWORD FOR 'user_6266'@'localhost' = PASSWORD('newpass'); + +--echo +--echo # On node_2 +--connection node_2 +SELECT user FROM mysql.user WHERE user='user_6266'; +# cleanup +DROP USER 'user_6266'@'localhost'; + +--source include/galera_end.inc +--echo # End of test diff --git a/mysql-test/suite/galera/t/partition.test b/mysql-test/suite/galera/t/partition.test new file mode 100644 index 00000000000..048f35a9282 --- /dev/null +++ b/mysql-test/suite/galera/t/partition.test @@ -0,0 +1,31 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc +--source include/have_partition.inc + +--echo # +--echo # MDEV#4953 Galera: DELETE from a partitioned table is not replicated +--echo # + +USE test; +CREATE TABLE t1 (pk INT PRIMARY KEY, i INT) ENGINE=INNODB PARTITION BY HASH(pk) PARTITIONS 2; +INSERT INTO t1 VALUES (1,100), (2,200); +SELECT * FROM t1; + +DELETE FROM t1; +SELECT * FROM t1; + +--echo +--echo # On node_1 +--connection node_1 +SELECT * FROM t1; + +--echo +--echo # On node_2 +--connection node_2 +SELECT * FROM t1; + +# Cleanup +DROP TABLE t1; + +--source include/galera_end.inc +--echo # End of test diff --git a/mysql-test/suite/galera/t/unique_key.test b/mysql-test/suite/galera/t/unique_key.test new file mode 100644 index 00000000000..00b85d57165 --- /dev/null +++ b/mysql-test/suite/galera/t/unique_key.test @@ -0,0 +1,54 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +--echo # +--echo # MDEV#5552 Deadlock when inserting NULL column value in column with +--echo # UNIQUE index +--echo # + +USE test; +--echo +--echo # On node_1 +--connection node_1 +CREATE TABLE t1(c1 INT DEFAULT NULL, UNIQUE KEY c1(c1)) ENGINE=INNODB; +INSERT INTO t1 VALUES (NULL); +INSERT INTO t1 VALUES (NULL); +SELECT * FROM test.t1; + +--echo +--echo # On node_2 +--connection node_2 +SELECT * FROM test.t1; + + +--echo +--echo # On node_1 +--connection node_1 +INSERT INTO t1 VALUES (1); +UPDATE t1 SET c1=NULL WHERE c1=1; +SELECT * FROM test.t1; + +--echo +--echo # On node_2 +--connection node_2 +SELECT * FROM test.t1; + +--echo +--echo # On node_1 +--connection node_1 +DELETE FROM t1 WHERE c1<=>NULL; +SELECT * FROM test.t1; + +--echo +--echo # On node_2 +--connection node_2 +SELECT * FROM test.t1; + +--let $galera_diff_statement = SELECT * FROM t1 +--source include/galera_diff.inc + +# Cleanup +DROP TABLE t1; + +--source include/galera_end.inc +--echo # End of test diff --git a/mysql-test/suite/innodb/r/innodb-autoinc.result b/mysql-test/suite/innodb/r/innodb-autoinc.result index d5ad06e861f..6ecb6055f26 100644 --- a/mysql-test/suite/innodb/r/innodb-autoinc.result +++ b/mysql-test/suite/innodb/r/innodb-autoinc.result @@ -197,7 +197,7 @@ c1 c2 5 9 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 100 auto_increment_offset 10 @@ -230,7 +230,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -269,7 +269,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -282,7 +282,7 @@ SELECT * FROM t1; c1 -1 SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 100 auto_increment_offset 10 @@ -315,7 +315,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -330,7 +330,7 @@ SELECT * FROM t1; c1 1 SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 100 auto_increment_offset 10 @@ -370,7 +370,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -385,7 +385,7 @@ SELECT * FROM t1; c1 1 SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 100 auto_increment_offset 10 @@ -419,7 +419,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -434,7 +434,7 @@ c1 1 9223372036854775794 SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 2 auto_increment_offset 10 @@ -452,7 +452,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -467,7 +467,7 @@ c1 1 18446744073709551603 SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 2 auto_increment_offset 10 @@ -480,7 +480,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -495,7 +495,7 @@ c1 1 18446744073709551603 SET @@SESSION.AUTO_INCREMENT_INCREMENT=5, @@SESSION.AUTO_INCREMENT_OFFSET=7; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 5 auto_increment_offset 7 @@ -508,7 +508,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -527,7 +527,7 @@ c1 -9223372036854775806 1 SET @@SESSION.AUTO_INCREMENT_INCREMENT=3, @@SESSION.AUTO_INCREMENT_OFFSET=3; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 3 auto_increment_offset 3 @@ -544,7 +544,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -562,7 +562,7 @@ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1152921504606846976, @@SESSION.AUTO_INCRE Warnings: Warning 1292 Truncated incorrect auto_increment_increment value: '1152921504606846976' Warning 1292 Truncated incorrect auto_increment_offset value: '1152921504606846976' -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 65535 auto_increment_offset 65535 @@ -575,7 +575,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -862,7 +862,7 @@ ERROR 22003: Out of range value for column 'c1' at row 1 DROP TABLE t1; DROP TABLE t2; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -1252,7 +1252,7 @@ t1 CREATE TABLE `t1` ( ) ENGINE=InnoDB AUTO_INCREMENT=18446744073709551615 DEFAULT CHARSET=latin1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=256; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 256 @@ -1270,7 +1270,7 @@ c1 c2 1 NULL DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 diff --git a/mysql-test/suite/innodb/t/innodb-autoinc.test b/mysql-test/suite/innodb/t/innodb-autoinc.test index fd40b50ebbc..415ada2939a 100644 --- a/mysql-test/suite/innodb/t/innodb-autoinc.test +++ b/mysql-test/suite/innodb/t/innodb-autoinc.test @@ -161,7 +161,7 @@ DROP TABLE t1; # # Test changes to AUTOINC next value calculation SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; INSERT INTO t1 VALUES (NULL),(5),(NULL); @@ -178,7 +178,7 @@ DROP TABLE t1; # Reset the AUTOINC session variables SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; INSERT INTO t1 VALUES(0); @@ -198,13 +198,13 @@ DROP TABLE t1; # Reset the AUTOINC session variables SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; INSERT INTO t1 VALUES(-1); SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; INSERT INTO t1 VALUES (-2), (NULL),(2),(NULL); INSERT INTO t1 VALUES (250),(NULL); SELECT * FROM t1; @@ -219,13 +219,13 @@ DROP TABLE t1; # Reset the AUTOINC session variables SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 INT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; INSERT INTO t1 VALUES(-1); SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; INSERT INTO t1 VALUES (-2); INSERT INTO t1 VALUES (NULL); INSERT INTO t1 VALUES (2); @@ -245,13 +245,13 @@ DROP TABLE t1; # Reset the AUTOINC session variables SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 INT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; INSERT INTO t1 VALUES(-1); SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; INSERT INTO t1 VALUES (-2),(NULL),(2),(NULL); INSERT INTO t1 VALUES (250),(NULL); SELECT * FROM t1; @@ -267,7 +267,7 @@ DROP TABLE t1; # Check for overflow handling when increment is > 1 SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 BIGINT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; # TODO: Fix the autoinc init code @@ -276,7 +276,7 @@ INSERT INTO t1 VALUES(NULL); INSERT INTO t1 VALUES (9223372036854775794); #-- 2^63 - 14 SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; # This should just fit INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); SELECT * FROM t1; @@ -286,7 +286,7 @@ DROP TABLE t1; # Check for overflow handling when increment and offser are > 1 SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; # TODO: Fix the autoinc init code @@ -295,7 +295,7 @@ INSERT INTO t1 VALUES(NULL); INSERT INTO t1 VALUES (18446744073709551603); #-- 2^64 - 13 SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; --error ER_AUTOINC_READ_FAILED INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL); SELECT * FROM t1; @@ -305,7 +305,7 @@ DROP TABLE t1; # Check for overflow handling when increment and offset are odd numbers SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; # TODO: Fix the autoinc init code @@ -314,7 +314,7 @@ INSERT INTO t1 VALUES(NULL); INSERT INTO t1 VALUES (18446744073709551603); #-- 2^64 - 13 SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=5, @@SESSION.AUTO_INCREMENT_OFFSET=7; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; --error ER_AUTOINC_READ_FAILED INSERT INTO t1 VALUES (NULL),(NULL), (NULL); SELECT * FROM t1; @@ -324,7 +324,7 @@ DROP TABLE t1; # and check for large -ve numbers SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 BIGINT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; # TODO: Fix the autoinc init code @@ -335,7 +335,7 @@ INSERT INTO t1 VALUES(-9223372036854775807); #-- -2^63 + 1 INSERT INTO t1 VALUES(-9223372036854775808); #-- -2^63 SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=3, @@SESSION.AUTO_INCREMENT_OFFSET=3; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; INSERT INTO t1 VALUES (NULL),(NULL), (NULL); SELECT * FROM t1; DROP TABLE t1; @@ -344,7 +344,7 @@ DROP TABLE t1; # large numbers 2^60 SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; # TODO: Fix the autoinc init code @@ -353,7 +353,7 @@ INSERT INTO t1 VALUES(NULL); INSERT INTO t1 VALUES (18446744073709551610); #-- 2^64 - 2 SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1152921504606846976, @@SESSION.AUTO_INCREMENT_OFFSET=1152921504606846976; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; --error 167 INSERT INTO t1 VALUES (NULL),(NULL); SELECT * FROM t1; @@ -364,7 +364,7 @@ DROP TABLE t1; # SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; CREATE TABLE t1 (c1 DOUBLE NOT NULL AUTO_INCREMENT, c2 INT, PRIMARY KEY (c1)) ENGINE=InnoDB; INSERT INTO t1 VALUES(NULL, 1); INSERT INTO t1 VALUES(NULL, 2); @@ -450,7 +450,7 @@ DROP TABLE t2; # If the user has specified negative values for an AUTOINC column then # InnoDB should ignore those values when setting the table's max value. SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; # TINYINT CREATE TABLE t1 (c1 TINYINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; INSERT INTO t1 VALUES (1, NULL); @@ -646,7 +646,7 @@ DROP TABLE t1; # Check if we handle offset > column max value properly SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=256; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; # TINYINT CREATE TABLE t1 (c1 TINYINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; INSERT INTO t1 VALUES (1, NULL); @@ -658,7 +658,7 @@ DROP TABLE t1; # of the column. IMO, this should not be allowed and the assertion that fails # is actually an invariant. SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; # TINYINT CREATE TABLE t1 (c1 INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; INSERT INTO t1 VALUES (2147483648, 'a'); diff --git a/mysql-test/suite/parts/r/partition_exch_qa_10.result b/mysql-test/suite/parts/r/partition_exch_qa_10.result old mode 100755 new mode 100644 index 77b91f19e8f..7193a6c99a1 --- a/mysql-test/suite/parts/r/partition_exch_qa_10.result +++ b/mysql-test/suite/parts/r/partition_exch_qa_10.result @@ -23,7 +23,7 @@ a b DROP PROCEDURE test_p1; SET @save_autocommit= @@autocommit; SET @@autocommit= OFF; -SHOW VARIABLES LIKE '%autocommit%'; +SHOW VARIABLES LIKE 'autocommit%'; Variable_name Value autocommit OFF CREATE TRIGGER test_trg_1 BEFORE UPDATE ON tp FOR EACH ROW diff --git a/mysql-test/suite/parts/t/partition_exch_qa_10.test b/mysql-test/suite/parts/t/partition_exch_qa_10.test index 4f569605f5f..a87d658cfb6 100644 --- a/mysql-test/suite/parts/t/partition_exch_qa_10.test +++ b/mysql-test/suite/parts/t/partition_exch_qa_10.test @@ -37,7 +37,7 @@ DROP PROCEDURE test_p1; SET @save_autocommit= @@autocommit; SET @@autocommit= OFF; -SHOW VARIABLES LIKE '%autocommit%'; +SHOW VARIABLES LIKE 'autocommit%'; DELIMITER |; --error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG CREATE TRIGGER test_trg_1 BEFORE UPDATE ON tp FOR EACH ROW diff --git a/mysql-test/suite/percona/innodb_sys_index.result b/mysql-test/suite/percona/innodb_sys_index.result index 67604236366..1c4cc63c467 100644 --- a/mysql-test/suite/percona/innodb_sys_index.result +++ b/mysql-test/suite/percona/innodb_sys_index.result @@ -3,7 +3,7 @@ Warnings: Note 1051 Unknown table 'test.t1' select @@version_comment limit 1 ; @@version_comment -Source distribution +Source distribution, wsrep_25.10.r3991 SELECT COUNT(*) FROM `information_schema`.`INNODB_SYS_INDEXES` ; CREATE TABLE test.t1 ( `a` SERIAL NOT NULL , `b` VARCHAR( 255 ) NOT NULL , INDEX ( `b` ) ) ENGINE = InnoDB ; SHOW TABLE STATUS FROM `information_schema` LIKE 'INNODB\_SYS\_INDEXES%' ; diff --git a/mysql-test/suite/percona/innodb_sys_index.test b/mysql-test/suite/percona/innodb_sys_index.test index 212baeda663..a5a79611815 100644 --- a/mysql-test/suite/percona/innodb_sys_index.test +++ b/mysql-test/suite/percona/innodb_sys_index.test @@ -5,7 +5,8 @@ drop table if exists t1; # # test for bug LP#875797 "Using 'innodb_sys_indexes' causes core dump" # -select @@version_comment limit 1 ; +# disable version_commit as it could contain wsrep +#select @@version_comment limit 1 ; --disable_result_log SELECT COUNT(*) FROM `information_schema`.`INNODB_SYS_INDEXES` ; CREATE TABLE test.t1 ( `a` SERIAL NOT NULL , `b` VARCHAR( 255 ) NOT NULL , INDEX ( `b` ) ) ENGINE = InnoDB ; diff --git a/mysql-test/suite/perfschema/r/rpl_statements.result b/mysql-test/suite/perfschema/r/rpl_statements.result index e271cd2a7fa..211a7d3398d 100644 --- a/mysql-test/suite/perfschema/r/rpl_statements.result +++ b/mysql-test/suite/perfschema/r/rpl_statements.result @@ -11,9 +11,10 @@ include/master-slave.inc *** Create test tables -show variables like '%binlog_format%'; +show variables like 'binlog_format%'; Variable_name Value binlog_format MIXED +wsrep_forced_binlog_format NONE drop table if exists test.marker; select thread_id into @my_thread_id from performance_schema.threads @@ -55,9 +56,10 @@ Expect 1 *** MASTER *** ************** -show variables like '%binlog_format%'; +show variables like 'binlog_format%'; Variable_name Value binlog_format MIXED +wsrep_forced_binlog_format NONE *** Clear statement events *** Create/drop table, create/drop database diff --git a/mysql-test/suite/perfschema/t/rpl_statements.test b/mysql-test/suite/perfschema/t/rpl_statements.test index fa429cd2aa3..479805edccc 100644 --- a/mysql-test/suite/perfschema/t/rpl_statements.test +++ b/mysql-test/suite/perfschema/t/rpl_statements.test @@ -64,7 +64,7 @@ connection master; --echo *** Create test tables --echo -show variables like '%binlog_format%'; +show variables like 'binlog_format%'; --disable_warnings drop table if exists test.marker; @@ -129,7 +129,7 @@ connection master; --echo *** MASTER *** --echo ************** --echo -show variables like '%binlog_format%'; +show variables like 'binlog_format%'; --echo *** Clear statement events --source ../include/rpl_statements_truncate.inc diff --git a/mysql-test/suite/sys_vars/r/innodb_disallow_writes_basic.result b/mysql-test/suite/sys_vars/r/innodb_disallow_writes_basic.result new file mode 100644 index 00000000000..bfb6b67b5d8 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/innodb_disallow_writes_basic.result @@ -0,0 +1,45 @@ +# +# innodb_disallow_writes +# +# save the initial value +SET @innodb_disallow_writes_global_saved = @@global.innodb_disallow_writes; +# default +SELECT @@global.innodb_disallow_writes; +@@global.innodb_disallow_writes +0 + +# scope +SELECT @@session.innodb_disallow_writes; +ERROR HY000: Variable 'innodb_disallow_writes' is a GLOBAL variable +SET @@global.innodb_disallow_writes=OFF; +SELECT @@global.innodb_disallow_writes; +@@global.innodb_disallow_writes +0 +SET @@global.innodb_disallow_writes=ON; +SELECT @@global.innodb_disallow_writes; +@@global.innodb_disallow_writes +1 + +# valid values +SET @@global.innodb_disallow_writes='OFF'; +SELECT @@global.innodb_disallow_writes; +@@global.innodb_disallow_writes +0 +SET @@global.innodb_disallow_writes=ON; +SELECT @@global.innodb_disallow_writes; +@@global.innodb_disallow_writes +1 +SET @@global.innodb_disallow_writes=default; +SELECT @@global.innodb_disallow_writes; +@@global.innodb_disallow_writes +0 + +# invalid values +SET @@global.innodb_disallow_writes=NULL; +ERROR 42000: Variable 'innodb_disallow_writes' can't be set to the value of 'NULL' +SET @@global.innodb_disallow_writes='junk'; +ERROR 42000: Variable 'innodb_disallow_writes' can't be set to the value of 'junk' + +# restore the initial value +SET @@global.innodb_disallow_writes = @innodb_disallow_writes_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_auto_increment_control_basic.result b/mysql-test/suite/sys_vars/r/wsrep_auto_increment_control_basic.result new file mode 100644 index 00000000000..d5affeaf5e4 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_auto_increment_control_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_auto_increment_control; +set @@global.wsrep_auto_increment_control=ON; +set @@global.wsrep_auto_increment_control=OFF; +set @@global.wsrep_auto_increment_control=1; +set @@global.wsrep_auto_increment_control=0; +SET @@global.wsrep_auto_increment_control = -1; +ERROR 42000: Variable 'wsrep_auto_increment_control' can't be set to the value of '-1' +set @@global.wsrep_auto_increment_control = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_causal_reads_basic.result b/mysql-test/suite/sys_vars/r/wsrep_causal_reads_basic.result new file mode 100644 index 00000000000..3b96654f8c7 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_causal_reads_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_causal_reads; +set @@global.wsrep_causal_reads=ON; +set @@global.wsrep_causal_reads=OFF; +set @@global.wsrep_causal_reads=1; +set @@global.wsrep_causal_reads=0; +SET @@global.wsrep_causal_reads = -1; +ERROR 42000: Variable 'wsrep_causal_reads' can't be set to the value of '-1' +set @@global.wsrep_causal_reads = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_certify_nonpk_basic.result b/mysql-test/suite/sys_vars/r/wsrep_certify_nonpk_basic.result new file mode 100644 index 00000000000..4b02f9fb61e --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_certify_nonpk_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_certify_nonpk; +set @@global.wsrep_certify_nonpk=ON; +set @@global.wsrep_certify_nonpk=OFF; +set @@global.wsrep_certify_nonpk=1; +set @@global.wsrep_certify_nonpk=0; +SET @@global.wsrep_certify_nonpk = -1; +ERROR 42000: Variable 'wsrep_certify_nonPK' can't be set to the value of '-1' +set @@global.wsrep_certify_nonpk = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_cluster_address_basic.result b/mysql-test/suite/sys_vars/r/wsrep_cluster_address_basic.result new file mode 100644 index 00000000000..734908d42e5 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_cluster_address_basic.result @@ -0,0 +1,45 @@ +SELECT COUNT(@@GLOBAL.wsrep_cluster_address); +COUNT(@@GLOBAL.wsrep_cluster_address) +1 +1 Expected +SELECT COUNT(@@GLOBAL.wsrep_cluster_address); +COUNT(@@GLOBAL.wsrep_cluster_address) +1 +1 Expected +SELECT @@GLOBAL.wsrep_cluster_address = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_cluster_address'; +@@GLOBAL.wsrep_cluster_address = VARIABLE_VALUE +1 +1 Expected +SELECT COUNT(@@GLOBAL.wsrep_cluster_address); +COUNT(@@GLOBAL.wsrep_cluster_address) +1 +1 Expected +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_cluster_address'; +COUNT(VARIABLE_VALUE) +1 +1 Expected +SELECT @@wsrep_cluster_address = @@GLOBAL.wsrep_cluster_address; +@@wsrep_cluster_address = @@GLOBAL.wsrep_cluster_address +1 +1 Expected +SELECT COUNT(@@wsrep_cluster_address); +COUNT(@@wsrep_cluster_address) +1 +1 Expected +SELECT COUNT(@@local.wsrep_cluster_address); +ERROR HY000: Variable 'wsrep_cluster_address' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@SESSION.wsrep_cluster_address); +ERROR HY000: Variable 'wsrep_cluster_address' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@GLOBAL.wsrep_cluster_address); +COUNT(@@GLOBAL.wsrep_cluster_address) +1 +1 Expected +SELECT wsrep_cluster_address = @@SESSION.wsrep_cluster_address; +ERROR 42S22: Unknown column 'wsrep_cluster_address' in 'field list' +Expected error 'Readonly variable' diff --git a/mysql-test/suite/sys_vars/r/wsrep_cluster_name_basic.result b/mysql-test/suite/sys_vars/r/wsrep_cluster_name_basic.result new file mode 100644 index 00000000000..59c3b9381d1 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_cluster_name_basic.result @@ -0,0 +1,7 @@ +set @start_value = @@wsrep_cluster_name; +set @@global.wsrep_cluster_name='test'; +set @@global.wsrep_cluster_name=NULL; +ERROR 42000: Variable 'wsrep_cluster_name' can't be set to the value of 'NULL' +SET @@global.wsrep_cluster_name = 1; +ERROR 42000: Incorrect argument type to variable 'wsrep_cluster_name' +set @@global.wsrep_cluster_name = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_convert_lock_to_trx_basic.result b/mysql-test/suite/sys_vars/r/wsrep_convert_lock_to_trx_basic.result new file mode 100644 index 00000000000..10043812289 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_convert_lock_to_trx_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_convert_lock_to_trx; +set @@global.wsrep_convert_lock_to_trx=ON; +set @@global.wsrep_convert_lock_to_trx=OFF; +set @@global.wsrep_convert_lock_to_trx=1; +set @@global.wsrep_convert_lock_to_trx=0; +SET @@global.wsrep_convert_lock_to_trx = -1; +ERROR 42000: Variable 'wsrep_convert_LOCK_to_trx' can't be set to the value of '-1' +set @@global.wsrep_convert_lock_to_trx = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_data_home_dir_basic.result b/mysql-test/suite/sys_vars/r/wsrep_data_home_dir_basic.result new file mode 100644 index 00000000000..668aebe30f1 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_data_home_dir_basic.result @@ -0,0 +1,48 @@ +SELECT COUNT(@@GLOBAL.wsrep_data_home_dir); +COUNT(@@GLOBAL.wsrep_data_home_dir) +1 +1 Expected +SET @@GLOBAL.wsrep_data_home_dir=1; +ERROR HY000: Variable 'wsrep_data_home_dir' is a read only variable +Expected error 'Read only variable' +SELECT COUNT(@@GLOBAL.wsrep_data_home_dir); +COUNT(@@GLOBAL.wsrep_data_home_dir) +1 +1 Expected +SELECT @@GLOBAL.wsrep_data_home_dir = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_data_home_dir'; +@@GLOBAL.wsrep_data_home_dir = VARIABLE_VALUE +1 +1 Expected +SELECT COUNT(@@GLOBAL.wsrep_data_home_dir); +COUNT(@@GLOBAL.wsrep_data_home_dir) +1 +1 Expected +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_data_home_dir'; +COUNT(VARIABLE_VALUE) +1 +1 Expected +SELECT @@wsrep_data_home_dir = @@GLOBAL.wsrep_data_home_dir; +@@wsrep_data_home_dir = @@GLOBAL.wsrep_data_home_dir +1 +1 Expected +SELECT COUNT(@@wsrep_data_home_dir); +COUNT(@@wsrep_data_home_dir) +1 +1 Expected +SELECT COUNT(@@local.wsrep_data_home_dir); +ERROR HY000: Variable 'wsrep_data_home_dir' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@SESSION.wsrep_data_home_dir); +ERROR HY000: Variable 'wsrep_data_home_dir' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@GLOBAL.wsrep_data_home_dir); +COUNT(@@GLOBAL.wsrep_data_home_dir) +1 +1 Expected +SELECT wsrep_data_home_dir = @@SESSION.wsrep_data_home_dir; +ERROR 42S22: Unknown column 'wsrep_data_home_dir' in 'field list' +Expected error 'Readonly variable' diff --git a/mysql-test/suite/sys_vars/r/wsrep_dbug_option_basic.result b/mysql-test/suite/sys_vars/r/wsrep_dbug_option_basic.result new file mode 100644 index 00000000000..36ebcb17002 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_dbug_option_basic.result @@ -0,0 +1,6 @@ +set @start_value = @@wsrep_dbug_option; +set @@global.wsrep_dbug_option='foo:bar'; +set @@global.wsrep_dbug_option=NULL; +SET @@global.wsrep_dbug_option = -1; +ERROR 42000: Incorrect argument type to variable 'wsrep_dbug_option' +set @@global.wsrep_dbug_option = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_debug_basic.result b/mysql-test/suite/sys_vars/r/wsrep_debug_basic.result new file mode 100644 index 00000000000..6bbe780316b --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_debug_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_debug; +set @@global.wsrep_debug=ON; +set @@global.wsrep_debug=OFF; +set @@global.wsrep_debug=1; +set @@global.wsrep_debug=0; +SET @@global.wsrep_debug = -1; +ERROR 42000: Variable 'wsrep_debug' can't be set to the value of '-1' +set @@global.wsrep_debug = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_desync_basic.result b/mysql-test/suite/sys_vars/r/wsrep_desync_basic.result new file mode 100644 index 00000000000..a61367ca200 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_desync_basic.result @@ -0,0 +1,3 @@ +select @@global.wsrep_desync; +@@global.wsrep_desync +0 diff --git a/mysql-test/suite/sys_vars/r/wsrep_drupal_282555_workaround_basic.result b/mysql-test/suite/sys_vars/r/wsrep_drupal_282555_workaround_basic.result new file mode 100644 index 00000000000..5a8d5a8abee --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_drupal_282555_workaround_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_drupal_282555_workaround; +set @@global.wsrep_drupal_282555_workaround=ON; +set @@global.wsrep_drupal_282555_workaround=OFF; +set @@global.wsrep_drupal_282555_workaround=1; +set @@global.wsrep_drupal_282555_workaround=0; +SET @@global.wsrep_drupal_282555_workaround = -1; +ERROR 42000: Variable 'wsrep_drupal_282555_workaround' can't be set to the value of '-1' +set @@global.wsrep_drupal_282555_workaround = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_forced_binlog_format_basic.result b/mysql-test/suite/sys_vars/r/wsrep_forced_binlog_format_basic.result new file mode 100644 index 00000000000..58bdb45c8de --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_forced_binlog_format_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_forced_binlog_format; +set @@global.wsrep_forced_binlog_format = ROW; +set @@global.wsrep_forced_binlog_format = MIXED; +set @@global.wsrep_forced_binlog_format = STATEMENT; +set @@global.wsrep_forced_binlog_format = NONE; +set @@global.wsrep_forced_binlog_format = FOO; +ERROR 42000: Variable 'wsrep_forced_binlog_format' can't be set to the value of 'FOO' +set @@global.wsrep_forced_binlog_format = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_load_data_splitting_basic.result b/mysql-test/suite/sys_vars/r/wsrep_load_data_splitting_basic.result new file mode 100644 index 00000000000..be73397f35e --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_load_data_splitting_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_load_data_splitting; +set @@global.wsrep_load_data_splitting=ON; +set @@global.wsrep_load_data_splitting=OFF; +set @@global.wsrep_load_data_splitting=1; +set @@global.wsrep_load_data_splitting=0; +SET @@global.wsrep_load_data_splitting = -1; +ERROR 42000: Variable 'wsrep_load_data_splitting' can't be set to the value of '-1' +set @@global.wsrep_load_data_splitting = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_log_conflicts_basic.result b/mysql-test/suite/sys_vars/r/wsrep_log_conflicts_basic.result new file mode 100644 index 00000000000..22d8cbb568a --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_log_conflicts_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_log_conflicts; +set @@global.wsrep_log_conflicts=ON; +set @@global.wsrep_log_conflicts=OFF; +set @@global.wsrep_log_conflicts=1; +set @@global.wsrep_log_conflicts=0; +SET @@global.wsrep_log_conflicts = -1; +ERROR 42000: Variable 'wsrep_log_conflicts' can't be set to the value of '-1' +set @@global.wsrep_log_conflicts = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_max_ws_rows_basic.result b/mysql-test/suite/sys_vars/r/wsrep_max_ws_rows_basic.result new file mode 100644 index 00000000000..fc4dd38ade3 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_max_ws_rows_basic.result @@ -0,0 +1,17 @@ +set @start_value = @@wsrep_max_ws_rows; +set @@global.wsrep_max_ws_rows=256000; +set @@global.wsrep_max_ws_rows=0; +Warnings: +Warning 1292 Truncated incorrect wsrep_max_ws_rows value: '0' +show warnings; +Level Code Message +Warning 1292 Truncated incorrect wsrep_max_ws_rows value: '0' +set @@global.wsrep_max_ws_rows=-1; +Warnings: +Warning 1292 Truncated incorrect wsrep_max_ws_rows value: '-1' +show warnings; +Level Code Message +Warning 1292 Truncated incorrect wsrep_max_ws_rows value: '-1' +SET @@global.wsrep_max_ws_rows = r; +ERROR 42000: Incorrect argument type to variable 'wsrep_max_ws_rows' +set @@global.wsrep_max_ws_rows = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_max_ws_size_basic.result b/mysql-test/suite/sys_vars/r/wsrep_max_ws_size_basic.result new file mode 100644 index 00000000000..292fd4e02d8 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_max_ws_size_basic.result @@ -0,0 +1,17 @@ +set @start_value = @@wsrep_max_ws_size; +set @@global.wsrep_max_ws_size=256000; +set @@global.wsrep_max_ws_size=0; +Warnings: +Warning 1292 Truncated incorrect wsrep_max_ws_size value: '0' +show warnings; +Level Code Message +Warning 1292 Truncated incorrect wsrep_max_ws_size value: '0' +set @@global.wsrep_max_ws_size=-1; +Warnings: +Warning 1292 Truncated incorrect wsrep_max_ws_size value: '-1' +show warnings; +Level Code Message +Warning 1292 Truncated incorrect wsrep_max_ws_size value: '-1' +SET @@global.wsrep_max_ws_size = r; +ERROR 42000: Incorrect argument type to variable 'wsrep_max_ws_size' +set @@global.wsrep_max_ws_size = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_mysql_replication_bundle_basic.result b/mysql-test/suite/sys_vars/r/wsrep_mysql_replication_bundle_basic.result new file mode 100644 index 00000000000..ad435a2c05f --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_mysql_replication_bundle_basic.result @@ -0,0 +1,18 @@ +set @start_value = @@wsrep_mysql_replication_bundle; +set @@global.wsrep_mysql_replication_bundle=0; +set @@global.wsrep_mysql_replication_bundle=1000; +set @@global.wsrep_mysql_replication_bundle=-1; +Warnings: +Warning 1292 Truncated incorrect wsrep_mysql_replication_bundle value: '-1' +show warnings; +Level Code Message +Warning 1292 Truncated incorrect wsrep_mysql_replication_bundle value: '-1' +set @@global.wsrep_mysql_replication_bundle=1001; +Warnings: +Warning 1292 Truncated incorrect wsrep_mysql_replication_bundle value: '1001' +show warnings; +Level Code Message +Warning 1292 Truncated incorrect wsrep_mysql_replication_bundle value: '1001' +SET @@global.wsrep_mysql_replication_bundle = r; +ERROR 42000: Incorrect argument type to variable 'wsrep_mysql_replication_bundle' +set @@global.wsrep_mysql_replication_bundle = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_node_address_basic.result b/mysql-test/suite/sys_vars/r/wsrep_node_address_basic.result new file mode 100644 index 00000000000..96ae51cc70f --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_node_address_basic.result @@ -0,0 +1,45 @@ +SELECT COUNT(@@GLOBAL.wsrep_node_address); +COUNT(@@GLOBAL.wsrep_node_address) +1 +1 Expected +SET @@GLOBAL.wsrep_node_address=1; +ERROR 42000: Incorrect argument type to variable 'wsrep_node_address' +Expected error 'Read only variable' +SELECT COUNT(@@GLOBAL.wsrep_node_address); +COUNT(@@GLOBAL.wsrep_node_address) +1 +1 Expected +SELECT @@GLOBAL.wsrep_node_address = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_node_address'; +@@GLOBAL.wsrep_node_address = VARIABLE_VALUE +1 +1 Expected +SELECT COUNT(@@GLOBAL.wsrep_node_address); +COUNT(@@GLOBAL.wsrep_node_address) +1 +1 Expected +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_node_address'; +COUNT(VARIABLE_VALUE) +1 +1 Expected +SELECT @@wsrep_node_address = @@GLOBAL.wsrep_node_address; +@@wsrep_node_address = @@GLOBAL.wsrep_node_address +1 +1 Expected +SELECT COUNT(@@wsrep_node_address); +COUNT(@@wsrep_node_address) +1 +1 Expected +SELECT COUNT(@@local.wsrep_node_address); +ERROR HY000: Variable 'wsrep_node_address' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@SESSION.wsrep_node_address); +ERROR HY000: Variable 'wsrep_node_address' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@GLOBAL.wsrep_node_address); +COUNT(@@GLOBAL.wsrep_node_address) +1 +1 Expected diff --git a/mysql-test/suite/sys_vars/r/wsrep_node_incoming_address_basic.result b/mysql-test/suite/sys_vars/r/wsrep_node_incoming_address_basic.result new file mode 100644 index 00000000000..9ccf9706484 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_node_incoming_address_basic.result @@ -0,0 +1,45 @@ +SELECT COUNT(@@GLOBAL.wsrep_node_incoming_address); +COUNT(@@GLOBAL.wsrep_node_incoming_address) +1 +1 Expected +SET @@GLOBAL.wsrep_node_incoming_address=1; +ERROR 42000: Incorrect argument type to variable 'wsrep_node_incoming_address' +Expected error 'Read only variable' +SELECT COUNT(@@GLOBAL.wsrep_node_incoming_address); +COUNT(@@GLOBAL.wsrep_node_incoming_address) +1 +1 Expected +SELECT @@GLOBAL.wsrep_node_incoming_address = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_node_incoming_address'; +@@GLOBAL.wsrep_node_incoming_address = VARIABLE_VALUE +1 +1 Expected +SELECT COUNT(@@GLOBAL.wsrep_node_incoming_address); +COUNT(@@GLOBAL.wsrep_node_incoming_address) +1 +1 Expected +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_node_incoming_address'; +COUNT(VARIABLE_VALUE) +1 +1 Expected +SELECT @@wsrep_node_incoming_address = @@GLOBAL.wsrep_node_incoming_address; +@@wsrep_node_incoming_address = @@GLOBAL.wsrep_node_incoming_address +1 +1 Expected +SELECT COUNT(@@wsrep_node_incoming_address); +COUNT(@@wsrep_node_incoming_address) +1 +1 Expected +SELECT COUNT(@@local.wsrep_node_incoming_address); +ERROR HY000: Variable 'wsrep_node_incoming_address' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@SESSION.wsrep_node_incoming_address); +ERROR HY000: Variable 'wsrep_node_incoming_address' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@GLOBAL.wsrep_node_incoming_address); +COUNT(@@GLOBAL.wsrep_node_incoming_address) +1 +1 Expected diff --git a/mysql-test/suite/sys_vars/r/wsrep_node_name_basic.result b/mysql-test/suite/sys_vars/r/wsrep_node_name_basic.result new file mode 100644 index 00000000000..f3c03570b7b --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_node_name_basic.result @@ -0,0 +1,6 @@ +set @start_value = @@wsrep_node_name; +set @@global.wsrep_node_name='test'; +set @@global.wsrep_node_name=NULL; +SET @@global.wsrep_node_name = 1; +ERROR 42000: Incorrect argument type to variable 'wsrep_node_name' +set @@global.wsrep_node_name = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_notify_cmd_basic.result b/mysql-test/suite/sys_vars/r/wsrep_notify_cmd_basic.result new file mode 100644 index 00000000000..d1d68ea036b --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_notify_cmd_basic.result @@ -0,0 +1,6 @@ +set @start_value = @@wsrep_notify_cmd; +set @@global.wsrep_notify_cmd='test'; +set @@global.wsrep_notify_cmd=NULL; +SET @@global.wsrep_notify_cmd = 1; +ERROR 42000: Incorrect argument type to variable 'wsrep_notify_cmd' +set @@global.wsrep_notify_cmd = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_on_basic.result b/mysql-test/suite/sys_vars/r/wsrep_on_basic.result new file mode 100644 index 00000000000..629c0e866cb --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_on_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_on; +set @@global.wsrep_on=ON; +set @@global.wsrep_on=OFF; +set @@global.wsrep_on=1; +set @@global.wsrep_on=0; +SET @@global.wsrep_on = -1; +ERROR 42000: Variable 'wsrep_on' can't be set to the value of '-1' +set @@global.wsrep_on = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_osu_method_basic.result b/mysql-test/suite/sys_vars/r/wsrep_osu_method_basic.result new file mode 100644 index 00000000000..84c828e5965 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_osu_method_basic.result @@ -0,0 +1,12 @@ +set @start_value = @@wsrep_osu_method; +set @@global.wsrep_osu_method='TOI'; +set @@global.wsrep_osu_method='RSU'; +set @@global.wsrep_osu_method=TOI; +set @@global.wsrep_osu_method=RSU; +set @@global.wsrep_osu_method=TSU; +ERROR 42000: Variable 'wsrep_OSU_method' can't be set to the value of 'TSU' +set @@global.wsrep_osu_method='TSU'; +ERROR 42000: Variable 'wsrep_OSU_method' can't be set to the value of 'TSU' +SET @@global.wsrep_on = -1; +ERROR 42000: Variable 'wsrep_on' can't be set to the value of '-1' +set @@global.wsrep_osu_method = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_provider_basic.result b/mysql-test/suite/sys_vars/r/wsrep_provider_basic.result new file mode 100644 index 00000000000..2de1e84e6c0 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_provider_basic.result @@ -0,0 +1,4 @@ +SELECT COUNT(@@GLOBAL.wsrep_provider); +COUNT(@@GLOBAL.wsrep_provider) +1 +1 Expected diff --git a/mysql-test/suite/sys_vars/r/wsrep_provider_options_basic.result b/mysql-test/suite/sys_vars/r/wsrep_provider_options_basic.result new file mode 100644 index 00000000000..28b55e782bc --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_provider_options_basic.result @@ -0,0 +1,4 @@ +SELECT COUNT(@@GLOBAL.wsrep_provider_options); +COUNT(@@GLOBAL.wsrep_provider_options) +1 +1 Expected diff --git a/mysql-test/suite/sys_vars/r/wsrep_recover_basic.result b/mysql-test/suite/sys_vars/r/wsrep_recover_basic.result new file mode 100644 index 00000000000..b9f7e41047e --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_recover_basic.result @@ -0,0 +1,49 @@ +SELECT COUNT(@@GLOBAL.wsrep_recover); +COUNT(@@GLOBAL.wsrep_recover) +1 +1 Expected +set @@global.wsrep_recover=ON; +ERROR HY000: Variable 'wsrep_recover' is a read only variable +Expected error 'Readonly variable' +set @@global.wsrep_recover=OFF; +ERROR HY000: Variable 'wsrep_recover' is a read only variable +Expected error 'Readonly variable' +SELECT @@GLOBAL.wsrep_recover = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_recover'; +@@GLOBAL.wsrep_recover = VARIABLE_VALUE +1 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'OFF' +1 Expected +SELECT COUNT(@@GLOBAL.wsrep_recover); +COUNT(@@GLOBAL.wsrep_recover) +1 +1 Expected +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_recover'; +COUNT(VARIABLE_VALUE) +1 +1 Expected +SELECT @@wsrep_recover = @@GLOBAL.wsrep_recover; +@@wsrep_recover = @@GLOBAL.wsrep_recover +1 +1 Expected +SELECT COUNT(@@wsrep_recover); +COUNT(@@wsrep_recover) +1 +1 Expected +SELECT COUNT(@@local.wsrep_recover); +ERROR HY000: Variable 'wsrep_recover' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@SESSION.wsrep_recover); +ERROR HY000: Variable 'wsrep_recover' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@GLOBAL.wsrep_recover); +COUNT(@@GLOBAL.wsrep_recover) +1 +1 Expected +SELECT wsrep_recover = @@SESSION.wsrep_recover; +ERROR 42S22: Unknown column 'wsrep_recover' in 'field list' +Expected error 'Readonly variable' diff --git a/mysql-test/suite/sys_vars/r/wsrep_replicate_myisam_basic.result b/mysql-test/suite/sys_vars/r/wsrep_replicate_myisam_basic.result new file mode 100644 index 00000000000..644258206a5 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_replicate_myisam_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_replicate_myisam; +set @@global.wsrep_replicate_myisam=ON; +set @@global.wsrep_replicate_myisam=OFF; +set @@global.wsrep_replicate_myisam=1; +set @@global.wsrep_replicate_myisam=0; +SET @@global.wsrep_replicate_myisam = -1; +ERROR 42000: Variable 'wsrep_replicate_myisam' can't be set to the value of '-1' +set @@global.wsrep_replicate_myisam = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_restart_slave_basic.result b/mysql-test/suite/sys_vars/r/wsrep_restart_slave_basic.result new file mode 100644 index 00000000000..811981b6a37 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_restart_slave_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_restart_slave; +set @@global.wsrep_restart_slave=ON; +set @@global.wsrep_restart_slave=OFF; +set @@global.wsrep_restart_slave=1; +set @@global.wsrep_restart_slave=0; +SET @@global.wsrep_restart_slave = -1; +ERROR 42000: Variable 'wsrep_restart_slave' can't be set to the value of '-1' +set @@global.wsrep_restart_slave = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_retry_autocommit_basic.result b/mysql-test/suite/sys_vars/r/wsrep_retry_autocommit_basic.result new file mode 100644 index 00000000000..811981b6a37 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_retry_autocommit_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_restart_slave; +set @@global.wsrep_restart_slave=ON; +set @@global.wsrep_restart_slave=OFF; +set @@global.wsrep_restart_slave=1; +set @@global.wsrep_restart_slave=0; +SET @@global.wsrep_restart_slave = -1; +ERROR 42000: Variable 'wsrep_restart_slave' can't be set to the value of '-1' +set @@global.wsrep_restart_slave = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_slave_fk_checks_basic.result b/mysql-test/suite/sys_vars/r/wsrep_slave_fk_checks_basic.result new file mode 100644 index 00000000000..40b3270e221 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_slave_fk_checks_basic.result @@ -0,0 +1,45 @@ +# +# wsrep_slave_fk_checks +# +# save the initial value +SET @wsrep_slave_fk_checks_global_saved = @@global.wsrep_slave_fk_checks; +# default +SELECT @@global.wsrep_slave_fk_checks; +@@global.wsrep_slave_fk_checks +1 + +# scope +SELECT @@session.wsrep_slave_fk_checks; +ERROR HY000: Variable 'wsrep_slave_FK_checks' is a GLOBAL variable +SET @@global.wsrep_slave_fk_checks=OFF; +SELECT @@global.wsrep_slave_fk_checks; +@@global.wsrep_slave_fk_checks +0 +SET @@global.wsrep_slave_fk_checks=ON; +SELECT @@global.wsrep_slave_fk_checks; +@@global.wsrep_slave_fk_checks +1 + +# valid values +SET @@global.wsrep_slave_fk_checks='OFF'; +SELECT @@global.wsrep_slave_fk_checks; +@@global.wsrep_slave_fk_checks +0 +SET @@global.wsrep_slave_fk_checks=ON; +SELECT @@global.wsrep_slave_fk_checks; +@@global.wsrep_slave_fk_checks +1 +SET @@global.wsrep_slave_fk_checks=default; +SELECT @@global.wsrep_slave_fk_checks; +@@global.wsrep_slave_fk_checks +1 + +# invalid values +SET @@global.wsrep_slave_fk_checks=NULL; +ERROR 42000: Variable 'wsrep_slave_FK_checks' can't be set to the value of 'NULL' +SET @@global.wsrep_slave_fk_checks='junk'; +ERROR 42000: Variable 'wsrep_slave_FK_checks' can't be set to the value of 'junk' + +# restore the initial value +SET @@global.wsrep_slave_fk_checks = @wsrep_slave_fk_checks_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_slave_threads_basic.result b/mysql-test/suite/sys_vars/r/wsrep_slave_threads_basic.result new file mode 100644 index 00000000000..f8105660c6e --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_slave_threads_basic.result @@ -0,0 +1,20 @@ +set @start_value = @@wsrep_slave_threads; +set @@global.wsrep_slave_threads=1; +set @@global.wsrep_slave_threads=4; +show warnings; +Level Code Message +set @@global.wsrep_slave_threads=0; +Warnings: +Warning 1292 Truncated incorrect wsrep_slave_threads value: '0' +show warnings; +Level Code Message +Warning 1292 Truncated incorrect wsrep_slave_threads value: '0' +set @@global.wsrep_slave_threads=-1; +Warnings: +Warning 1292 Truncated incorrect wsrep_slave_threads value: '-1' +show warnings; +Level Code Message +Warning 1292 Truncated incorrect wsrep_slave_threads value: '-1' +SET @@global.wsrep_slave_threads = r; +ERROR 42000: Incorrect argument type to variable 'wsrep_slave_threads' +set @@global.wsrep_slave_threads = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_slave_uk_checks_basic.result b/mysql-test/suite/sys_vars/r/wsrep_slave_uk_checks_basic.result new file mode 100644 index 00000000000..b78a83b547d --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_slave_uk_checks_basic.result @@ -0,0 +1,45 @@ +# +# wsrep_slave_uk_checks +# +# save the initial value +SET @wsrep_slave_uk_checks_global_saved = @@global.wsrep_slave_uk_checks; +# default +SELECT @@global.wsrep_slave_uk_checks; +@@global.wsrep_slave_uk_checks +0 + +# scope +SELECT @@session.wsrep_slave_uk_checks; +ERROR HY000: Variable 'wsrep_slave_UK_checks' is a GLOBAL variable +SET @@global.wsrep_slave_uk_checks=OFF; +SELECT @@global.wsrep_slave_uk_checks; +@@global.wsrep_slave_uk_checks +0 +SET @@global.wsrep_slave_uk_checks=ON; +SELECT @@global.wsrep_slave_uk_checks; +@@global.wsrep_slave_uk_checks +1 + +# valid values +SET @@global.wsrep_slave_uk_checks='OFF'; +SELECT @@global.wsrep_slave_uk_checks; +@@global.wsrep_slave_uk_checks +0 +SET @@global.wsrep_slave_uk_checks=ON; +SELECT @@global.wsrep_slave_uk_checks; +@@global.wsrep_slave_uk_checks +1 +SET @@global.wsrep_slave_uk_checks=default; +SELECT @@global.wsrep_slave_uk_checks; +@@global.wsrep_slave_uk_checks +0 + +# invalid values +SET @@global.wsrep_slave_uk_checks=NULL; +ERROR 42000: Variable 'wsrep_slave_UK_checks' can't be set to the value of 'NULL' +SET @@global.wsrep_slave_uk_checks='junk'; +ERROR 42000: Variable 'wsrep_slave_UK_checks' can't be set to the value of 'junk' + +# restore the initial value +SET @@global.wsrep_slave_uk_checks = @wsrep_slave_uk_checks_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_sst_auth_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sst_auth_basic.result new file mode 100644 index 00000000000..a8a31dbea61 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_sst_auth_basic.result @@ -0,0 +1,3 @@ +SELECT COUNT(@@wsrep_sst_auth); +COUNT(@@wsrep_sst_auth) +0 diff --git a/mysql-test/suite/sys_vars/r/wsrep_sst_donor_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sst_donor_basic.result new file mode 100644 index 00000000000..fc359690275 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_sst_donor_basic.result @@ -0,0 +1,10 @@ +SELECT COUNT(@@wsrep_sst_donor); +COUNT(@@wsrep_sst_donor) +1 +set @start_value = @@wsrep_sst_donor; +set @@global.wsrep_sst_donor='foo'; +set @@global.wsrep_sst_donor=NULL; +set @@global.wsrep_sst_donor=r; +set @@global.wsrep_sst_donor=1; +ERROR 42000: Incorrect argument type to variable 'wsrep_sst_donor' +set @@global.wsrep_sst_donor = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_sst_donor_rejects_queries_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sst_donor_rejects_queries_basic.result new file mode 100644 index 00000000000..55aa56f27ed --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_sst_donor_rejects_queries_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_sst_donor_rejects_queries; +set @@global.wsrep_sst_donor_rejects_queries=ON; +set @@global.wsrep_sst_donor_rejects_queries=OFF; +set @@global.wsrep_sst_donor_rejects_queries=1; +set @@global.wsrep_sst_donor_rejects_queries=0; +SET @@global.wsrep_sst_donor_rejects_queries = -1; +ERROR 42000: Variable 'wsrep_sst_donor_rejects_queries' can't be set to the value of '-1' +set @@global.wsrep_sst_donor_rejects_queries = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_sst_method_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sst_method_basic.result new file mode 100644 index 00000000000..682a5683026 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_sst_method_basic.result @@ -0,0 +1,12 @@ +set @start_value = @@wsrep_sst_method; +set @@global.wsrep_sst_method='xtrabackup'; +set @@global.wsrep_sst_method='xtrabackup-v2'; +set @@global.wsrep_sst_method='rsync'; +set @@global.wsrep_sst_method='mysqldump'; +set @@global.wsrep_sst_method='myscript'; +set @@global.wsrep_sst_method='skip'; +set @@global.wsrep_sst_method=NULL; +ERROR 42000: Variable 'wsrep_sst_method' can't be set to the value of 'NULL' +SET @@global.wsrep_sst_method = -1; +ERROR 42000: Incorrect argument type to variable 'wsrep_sst_method' +set @@global.wsrep_sst_method = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_sst_receive_address_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sst_receive_address_basic.result new file mode 100644 index 00000000000..a23b7efafa8 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_sst_receive_address_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_sst_receive_address; +set @@global.wsrep_sst_receive_address='128.0.2.1'; +set @@global.wsrep_sst_receive_address=AUTO; +set @@global.wsrep_sst_receive_address='AUTO'; +set @@global.wsrep_sst_receive_address=NULL; +SET @@global.wsrep_sst_receive_address = -1; +ERROR 42000: Incorrect argument type to variable 'wsrep_sst_receive_address' +set @@global.wsrep_sst_receive_address = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_start_position_basic.result b/mysql-test/suite/sys_vars/r/wsrep_start_position_basic.result new file mode 100644 index 00000000000..ad3606d6d55 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_start_position_basic.result @@ -0,0 +1,8 @@ +set @start_value = @@wsrep_start_position; +set @@global.wsrep_start_position='foo:bar'; +ERROR 42000: Variable 'wsrep_start_position' can't be set to the value of 'foo:bar' +set @@global.wsrep_start_position=NULL; +ERROR 42000: Variable 'wsrep_start_position' can't be set to the value of 'NULL' +SET @@global.wsrep_start_position = -1; +ERROR 42000: Incorrect argument type to variable 'wsrep_start_position' +set @@global.wsrep_start_position = @start_value; diff --git a/mysql-test/suite/sys_vars/r/wsrep_sync_wait_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sync_wait_basic.result new file mode 100644 index 00000000000..1e7b9364570 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_sync_wait_basic.result @@ -0,0 +1,56 @@ +# +# wsrep_sync_wait +# +# save the initial values +SET @wsrep_sync_wait_global_saved = @@global.wsrep_sync_wait; +SET @wsrep_sync_wait_session_saved = @@session.wsrep_sync_wait; +# default +SELECT @@global.wsrep_sync_wait; +@@global.wsrep_sync_wait +0 +SELECT @@session.wsrep_sync_wait; +@@session.wsrep_sync_wait +0 + +# scope and valid values +SET @@global.wsrep_sync_wait=0; +SELECT @@global.wsrep_sync_wait; +@@global.wsrep_sync_wait +0 +SET @@global.wsrep_sync_wait=7; +SELECT @@global.wsrep_sync_wait; +@@global.wsrep_sync_wait +7 +SET @@session.wsrep_sync_wait=0; +SELECT @@session.wsrep_sync_wait; +@@session.wsrep_sync_wait +0 +SET @@session.wsrep_sync_wait=7; +SELECT @@session.wsrep_sync_wait; +@@session.wsrep_sync_wait +7 +SET @@session.wsrep_sync_wait=default; +SELECT @@session.wsrep_sync_wait; +@@session.wsrep_sync_wait +7 +SET @@session.wsrep_sync_wait=8; +Warnings: +Warning 1292 Truncated incorrect wsrep_sync_wait value: '8' +SELECT @@session.wsrep_sync_wait; +@@session.wsrep_sync_wait +7 + +# invalid values +SET @@global.wsrep_sync_wait=NULL; +ERROR 42000: Incorrect argument type to variable 'wsrep_sync_wait' +SET @@global.wsrep_sync_wait='junk'; +ERROR 42000: Incorrect argument type to variable 'wsrep_sync_wait' +SET @@session.wsrep_sync_wait=NULL; +ERROR 42000: Incorrect argument type to variable 'wsrep_sync_wait' +SET @@session.wsrep_sync_wait='junk'; +ERROR 42000: Incorrect argument type to variable 'wsrep_sync_wait' + +# restore the initial values +SET @@global.wsrep_sync_wait = @wsrep_sync_wait_global_saved; +SET @@session.wsrep_sync_wait = @wsrep_sync_wait_session_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/t/innodb_disallow_writes_basic.test b/mysql-test/suite/sys_vars/t/innodb_disallow_writes_basic.test new file mode 100644 index 00000000000..b8e5c127377 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_disallow_writes_basic.test @@ -0,0 +1,42 @@ +--source include/have_innodb_disallow_writes.inc + +--echo # +--echo # innodb_disallow_writes +--echo # + +--echo # save the initial value +SET @innodb_disallow_writes_global_saved = @@global.innodb_disallow_writes; + +--echo # default +SELECT @@global.innodb_disallow_writes; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.innodb_disallow_writes; +SET @@global.innodb_disallow_writes=OFF; +SELECT @@global.innodb_disallow_writes; +SET @@global.innodb_disallow_writes=ON; +SELECT @@global.innodb_disallow_writes; + +--echo +--echo # valid values +SET @@global.innodb_disallow_writes='OFF'; +SELECT @@global.innodb_disallow_writes; +SET @@global.innodb_disallow_writes=ON; +SELECT @@global.innodb_disallow_writes; +SET @@global.innodb_disallow_writes=default; +SELECT @@global.innodb_disallow_writes; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.innodb_disallow_writes=NULL; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.innodb_disallow_writes='junk'; + +--echo +--echo # restore the initial value +SET @@global.innodb_disallow_writes = @innodb_disallow_writes_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_auto_increment_control_basic.test b/mysql-test/suite/sys_vars/t/wsrep_auto_increment_control_basic.test new file mode 100644 index 00000000000..91d3c578a2c --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_auto_increment_control_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_auto_increment_control; + +set @@global.wsrep_auto_increment_control=ON; +set @@global.wsrep_auto_increment_control=OFF; +set @@global.wsrep_auto_increment_control=1; +set @@global.wsrep_auto_increment_control=0; +--Error 1231 +SET @@global.wsrep_auto_increment_control = -1; + +set @@global.wsrep_auto_increment_control = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_causal_reads_basic.test b/mysql-test/suite/sys_vars/t/wsrep_causal_reads_basic.test new file mode 100644 index 00000000000..2fb597e842e --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_causal_reads_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_causal_reads; + +set @@global.wsrep_causal_reads=ON; +set @@global.wsrep_causal_reads=OFF; +set @@global.wsrep_causal_reads=1; +set @@global.wsrep_causal_reads=0; +--Error 1231 +SET @@global.wsrep_causal_reads = -1; + +set @@global.wsrep_causal_reads = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_certify_nonpk b/mysql-test/suite/sys_vars/t/wsrep_certify_nonpk new file mode 100644 index 00000000000..f4512aeb5da --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_certify_nonpk @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_certify_nonpk; + +set @@global.wsrep_certify_nonpk=ON; +set @@global.wsrep_certify_nonpk=OFF; +set @@global.wsrep_certify_nonpk=1; +set @@global.wsrep_certify_nonpk=0; +--Error ER_WRONG_TYPE_FOR_VAR +SET @@global.wsrep_certify_nonpk = -1; + +set @@global.wsrep_certify_nonpk = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_certify_nonpk_basic.test b/mysql-test/suite/sys_vars/t/wsrep_certify_nonpk_basic.test new file mode 100644 index 00000000000..b623d8eb073 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_certify_nonpk_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_certify_nonpk; + +set @@global.wsrep_certify_nonpk=ON; +set @@global.wsrep_certify_nonpk=OFF; +set @@global.wsrep_certify_nonpk=1; +set @@global.wsrep_certify_nonpk=0; +--Error 1231 +SET @@global.wsrep_certify_nonpk = -1; + +set @@global.wsrep_certify_nonpk = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_cluster_address_basic.test b/mysql-test/suite/sys_vars/t/wsrep_cluster_address_basic.test new file mode 100644 index 00000000000..b61d5ea60c3 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_cluster_address_basic.test @@ -0,0 +1,44 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +SELECT COUNT(@@GLOBAL.wsrep_cluster_address); +--echo 1 Expected + +SELECT COUNT(@@GLOBAL.wsrep_cluster_address); +--echo 1 Expected + +SELECT @@GLOBAL.wsrep_cluster_address = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_cluster_address'; +--echo 1 Expected + +SELECT COUNT(@@GLOBAL.wsrep_cluster_address); +--echo 1 Expected + +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_cluster_address'; +--echo 1 Expected + +SELECT @@wsrep_cluster_address = @@GLOBAL.wsrep_cluster_address; +--echo 1 Expected + +SELECT COUNT(@@wsrep_cluster_address); +--echo 1 Expected + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@local.wsrep_cluster_address); +--echo Expected error 'Variable is a GLOBAL variable' + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@SESSION.wsrep_cluster_address); +--echo Expected error 'Variable is a GLOBAL variable' + +SELECT COUNT(@@GLOBAL.wsrep_cluster_address); +--echo 1 Expected + +--Error ER_BAD_FIELD_ERROR +SELECT wsrep_cluster_address = @@SESSION.wsrep_cluster_address; +--echo Expected error 'Readonly variable' + + diff --git a/mysql-test/suite/sys_vars/t/wsrep_cluster_name_basic.test b/mysql-test/suite/sys_vars/t/wsrep_cluster_name_basic.test new file mode 100644 index 00000000000..104c342bfe4 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_cluster_name_basic.test @@ -0,0 +1,12 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_cluster_name; + +set @@global.wsrep_cluster_name='test'; +--Error 1231 +set @@global.wsrep_cluster_name=NULL; +--Error 1232 +SET @@global.wsrep_cluster_name = 1; + +set @@global.wsrep_cluster_name = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_convert_lock_to_trx_basic.test b/mysql-test/suite/sys_vars/t/wsrep_convert_lock_to_trx_basic.test new file mode 100644 index 00000000000..84b92085238 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_convert_lock_to_trx_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_convert_lock_to_trx; + +set @@global.wsrep_convert_lock_to_trx=ON; +set @@global.wsrep_convert_lock_to_trx=OFF; +set @@global.wsrep_convert_lock_to_trx=1; +set @@global.wsrep_convert_lock_to_trx=0; +--Error 1231 +SET @@global.wsrep_convert_lock_to_trx = -1; + +set @@global.wsrep_convert_lock_to_trx = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_data_home_dir_basic.test b/mysql-test/suite/sys_vars/t/wsrep_data_home_dir_basic.test new file mode 100644 index 00000000000..fccf685193e --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_data_home_dir_basic.test @@ -0,0 +1,48 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +SELECT COUNT(@@GLOBAL.wsrep_data_home_dir); +--echo 1 Expected + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@GLOBAL.wsrep_data_home_dir=1; +--echo Expected error 'Read only variable' + +SELECT COUNT(@@GLOBAL.wsrep_data_home_dir); +--echo 1 Expected + +SELECT @@GLOBAL.wsrep_data_home_dir = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_data_home_dir'; +--echo 1 Expected + +SELECT COUNT(@@GLOBAL.wsrep_data_home_dir); +--echo 1 Expected + +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_data_home_dir'; +--echo 1 Expected + +SELECT @@wsrep_data_home_dir = @@GLOBAL.wsrep_data_home_dir; +--echo 1 Expected + +SELECT COUNT(@@wsrep_data_home_dir); +--echo 1 Expected + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@local.wsrep_data_home_dir); +--echo Expected error 'Variable is a GLOBAL variable' + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@SESSION.wsrep_data_home_dir); +--echo Expected error 'Variable is a GLOBAL variable' + +SELECT COUNT(@@GLOBAL.wsrep_data_home_dir); +--echo 1 Expected + +--Error ER_BAD_FIELD_ERROR +SELECT wsrep_data_home_dir = @@SESSION.wsrep_data_home_dir; +--echo Expected error 'Readonly variable' + + diff --git a/mysql-test/suite/sys_vars/t/wsrep_dbug_option_basic.test b/mysql-test/suite/sys_vars/t/wsrep_dbug_option_basic.test new file mode 100644 index 00000000000..0a559fe8d27 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_dbug_option_basic.test @@ -0,0 +1,11 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_dbug_option; + +set @@global.wsrep_dbug_option='foo:bar'; +set @@global.wsrep_dbug_option=NULL; +--Error 1232 +SET @@global.wsrep_dbug_option = -1; + +set @@global.wsrep_dbug_option = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_debug_basic.test b/mysql-test/suite/sys_vars/t/wsrep_debug_basic.test new file mode 100644 index 00000000000..194c163baa6 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_debug_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_debug; + +set @@global.wsrep_debug=ON; +set @@global.wsrep_debug=OFF; +set @@global.wsrep_debug=1; +set @@global.wsrep_debug=0; +--Error 1231 +SET @@global.wsrep_debug = -1; + +set @@global.wsrep_debug = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_debug_option_basic.test b/mysql-test/suite/sys_vars/t/wsrep_debug_option_basic.test new file mode 100644 index 00000000000..060e721b676 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_debug_option_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_debug_option; + +--error 1231 +set @@global.wsrep_debug_option='foo:bar'; +--error 1231 +set @@global.wsrep_debug_option=NULL; +--Error 1232 +SET @@global.wsrep_debug_option = -1; + +set @@global.wsrep_debug_option = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_desync_basic.test b/mysql-test/suite/sys_vars/t/wsrep_desync_basic.test new file mode 100644 index 00000000000..3c64d8cb30f --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_desync_basic.test @@ -0,0 +1,4 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +select @@global.wsrep_desync; diff --git a/mysql-test/suite/sys_vars/t/wsrep_drupal_282555_workaround_basic.test b/mysql-test/suite/sys_vars/t/wsrep_drupal_282555_workaround_basic.test new file mode 100644 index 00000000000..ada08bb125d --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_drupal_282555_workaround_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_drupal_282555_workaround; + +set @@global.wsrep_drupal_282555_workaround=ON; +set @@global.wsrep_drupal_282555_workaround=OFF; +set @@global.wsrep_drupal_282555_workaround=1; +set @@global.wsrep_drupal_282555_workaround=0; +--Error 1231 +SET @@global.wsrep_drupal_282555_workaround = -1; + +set @@global.wsrep_drupal_282555_workaround = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_forced_binlog_format_basic.test b/mysql-test/suite/sys_vars/t/wsrep_forced_binlog_format_basic.test new file mode 100644 index 00000000000..5e5530a8f64 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_forced_binlog_format_basic.test @@ -0,0 +1,14 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_forced_binlog_format; + +set @@global.wsrep_forced_binlog_format = ROW; +set @@global.wsrep_forced_binlog_format = MIXED; +set @@global.wsrep_forced_binlog_format = STATEMENT; +set @@global.wsrep_forced_binlog_format = NONE; + +--error 1231 +set @@global.wsrep_forced_binlog_format = FOO; + +set @@global.wsrep_forced_binlog_format = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_load_data_splitting_basic.test b/mysql-test/suite/sys_vars/t/wsrep_load_data_splitting_basic.test new file mode 100644 index 00000000000..61ff27d6894 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_load_data_splitting_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_load_data_splitting; + +set @@global.wsrep_load_data_splitting=ON; +set @@global.wsrep_load_data_splitting=OFF; +set @@global.wsrep_load_data_splitting=1; +set @@global.wsrep_load_data_splitting=0; +--Error 1231 +SET @@global.wsrep_load_data_splitting = -1; + +set @@global.wsrep_load_data_splitting = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_log_conflicts_basic.test b/mysql-test/suite/sys_vars/t/wsrep_log_conflicts_basic.test new file mode 100644 index 00000000000..dbd696c45a2 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_log_conflicts_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_log_conflicts; + +set @@global.wsrep_log_conflicts=ON; +set @@global.wsrep_log_conflicts=OFF; +set @@global.wsrep_log_conflicts=1; +set @@global.wsrep_log_conflicts=0; +--Error 1231 +SET @@global.wsrep_log_conflicts = -1; + +set @@global.wsrep_log_conflicts = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_max_ws_rows_basic.test b/mysql-test/suite/sys_vars/t/wsrep_max_ws_rows_basic.test new file mode 100644 index 00000000000..f607a567d80 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_max_ws_rows_basic.test @@ -0,0 +1,14 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_max_ws_rows; + +set @@global.wsrep_max_ws_rows=256000; +set @@global.wsrep_max_ws_rows=0; +show warnings; +set @@global.wsrep_max_ws_rows=-1; +show warnings; +--Error 1232 +SET @@global.wsrep_max_ws_rows = r; + +set @@global.wsrep_max_ws_rows = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_max_ws_size_basic.test b/mysql-test/suite/sys_vars/t/wsrep_max_ws_size_basic.test new file mode 100644 index 00000000000..6b1d1f71090 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_max_ws_size_basic.test @@ -0,0 +1,14 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_max_ws_size; + +set @@global.wsrep_max_ws_size=256000; +set @@global.wsrep_max_ws_size=0; +show warnings; +set @@global.wsrep_max_ws_size=-1; +show warnings; +--Error 1232 +SET @@global.wsrep_max_ws_size = r; + +set @@global.wsrep_max_ws_size = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_mysql_replication_bundle_basic.test b/mysql-test/suite/sys_vars/t/wsrep_mysql_replication_bundle_basic.test new file mode 100644 index 00000000000..20a0dc9bf9f --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_mysql_replication_bundle_basic.test @@ -0,0 +1,16 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_mysql_replication_bundle; + +set @@global.wsrep_mysql_replication_bundle=0; +set @@global.wsrep_mysql_replication_bundle=1000; + +set @@global.wsrep_mysql_replication_bundle=-1; +show warnings; +set @@global.wsrep_mysql_replication_bundle=1001; +show warnings; +--Error 1232 +SET @@global.wsrep_mysql_replication_bundle = r; + +set @@global.wsrep_mysql_replication_bundle = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_node_address_basic.test b/mysql-test/suite/sys_vars/t/wsrep_node_address_basic.test new file mode 100644 index 00000000000..feace325044 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_node_address_basic.test @@ -0,0 +1,42 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +SELECT COUNT(@@GLOBAL.wsrep_node_address); +--echo 1 Expected + +--error 1232 +SET @@GLOBAL.wsrep_node_address=1; +--echo Expected error 'Read only variable' + +SELECT COUNT(@@GLOBAL.wsrep_node_address); +--echo 1 Expected + +SELECT @@GLOBAL.wsrep_node_address = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_node_address'; +--echo 1 Expected + +SELECT COUNT(@@GLOBAL.wsrep_node_address); +--echo 1 Expected + +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_node_address'; +--echo 1 Expected + +SELECT @@wsrep_node_address = @@GLOBAL.wsrep_node_address; +--echo 1 Expected + +SELECT COUNT(@@wsrep_node_address); +--echo 1 Expected + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@local.wsrep_node_address); +--echo Expected error 'Variable is a GLOBAL variable' + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@SESSION.wsrep_node_address); +--echo Expected error 'Variable is a GLOBAL variable' + +SELECT COUNT(@@GLOBAL.wsrep_node_address); +--echo 1 Expected diff --git a/mysql-test/suite/sys_vars/t/wsrep_node_incoming_address_basic.test b/mysql-test/suite/sys_vars/t/wsrep_node_incoming_address_basic.test new file mode 100644 index 00000000000..188a5960eb9 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_node_incoming_address_basic.test @@ -0,0 +1,42 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +SELECT COUNT(@@GLOBAL.wsrep_node_incoming_address); +--echo 1 Expected + +--error 1232 +SET @@GLOBAL.wsrep_node_incoming_address=1; +--echo Expected error 'Read only variable' + +SELECT COUNT(@@GLOBAL.wsrep_node_incoming_address); +--echo 1 Expected + +SELECT @@GLOBAL.wsrep_node_incoming_address = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_node_incoming_address'; +--echo 1 Expected + +SELECT COUNT(@@GLOBAL.wsrep_node_incoming_address); +--echo 1 Expected + +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_node_incoming_address'; +--echo 1 Expected + +SELECT @@wsrep_node_incoming_address = @@GLOBAL.wsrep_node_incoming_address; +--echo 1 Expected + +SELECT COUNT(@@wsrep_node_incoming_address); +--echo 1 Expected + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@local.wsrep_node_incoming_address); +--echo Expected error 'Variable is a GLOBAL variable' + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@SESSION.wsrep_node_incoming_address); +--echo Expected error 'Variable is a GLOBAL variable' + +SELECT COUNT(@@GLOBAL.wsrep_node_incoming_address); +--echo 1 Expected diff --git a/mysql-test/suite/sys_vars/t/wsrep_node_name_basic.test b/mysql-test/suite/sys_vars/t/wsrep_node_name_basic.test new file mode 100644 index 00000000000..3220ae373e2 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_node_name_basic.test @@ -0,0 +1,11 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_node_name; + +set @@global.wsrep_node_name='test'; +set @@global.wsrep_node_name=NULL; +--Error 1232 +SET @@global.wsrep_node_name = 1; + +set @@global.wsrep_node_name = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_notify_cmd_basic.test b/mysql-test/suite/sys_vars/t/wsrep_notify_cmd_basic.test new file mode 100644 index 00000000000..d816453f8a3 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_notify_cmd_basic.test @@ -0,0 +1,11 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_notify_cmd; + +set @@global.wsrep_notify_cmd='test'; +set @@global.wsrep_notify_cmd=NULL; +--Error 1232 +SET @@global.wsrep_notify_cmd = 1; + +set @@global.wsrep_notify_cmd = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_on_basic.test b/mysql-test/suite/sys_vars/t/wsrep_on_basic.test new file mode 100644 index 00000000000..5afe5c4451f --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_on_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_on; + +set @@global.wsrep_on=ON; +set @@global.wsrep_on=OFF; +set @@global.wsrep_on=1; +set @@global.wsrep_on=0; +--Error 1231 +SET @@global.wsrep_on = -1; + +set @@global.wsrep_on = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_osu_method_basic.test b/mysql-test/suite/sys_vars/t/wsrep_osu_method_basic.test new file mode 100644 index 00000000000..9e1adde76a3 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_osu_method_basic.test @@ -0,0 +1,18 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_osu_method; + +set @@global.wsrep_osu_method='TOI'; +set @@global.wsrep_osu_method='RSU'; +set @@global.wsrep_osu_method=TOI; +set @@global.wsrep_osu_method=RSU; + +--Error 1231 +set @@global.wsrep_osu_method=TSU; +--Error 1231 +set @@global.wsrep_osu_method='TSU'; +--Error 1231 +SET @@global.wsrep_on = -1; + +set @@global.wsrep_osu_method = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_provider_basic.test b/mysql-test/suite/sys_vars/t/wsrep_provider_basic.test new file mode 100644 index 00000000000..aae122c42fe --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_provider_basic.test @@ -0,0 +1,5 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +SELECT COUNT(@@GLOBAL.wsrep_provider); +--echo 1 Expected diff --git a/mysql-test/suite/sys_vars/t/wsrep_provider_options_basic.test b/mysql-test/suite/sys_vars/t/wsrep_provider_options_basic.test new file mode 100644 index 00000000000..e2d8b63b2fd --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_provider_options_basic.test @@ -0,0 +1,5 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +SELECT COUNT(@@GLOBAL.wsrep_provider_options); +--echo 1 Expected diff --git a/mysql-test/suite/sys_vars/t/wsrep_recover_basic.test b/mysql-test/suite/sys_vars/t/wsrep_recover_basic.test new file mode 100644 index 00000000000..f4e1707a434 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_recover_basic.test @@ -0,0 +1,47 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +SELECT COUNT(@@GLOBAL.wsrep_recover); +--echo 1 Expected + +--Error 1238 +set @@global.wsrep_recover=ON; +--echo Expected error 'Readonly variable' +--Error 1238 +set @@global.wsrep_recover=OFF; +--echo Expected error 'Readonly variable' + +SELECT @@GLOBAL.wsrep_recover = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_recover'; +--echo 1 Expected + +SELECT COUNT(@@GLOBAL.wsrep_recover); +--echo 1 Expected + +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='wsrep_recover'; +--echo 1 Expected + +SELECT @@wsrep_recover = @@GLOBAL.wsrep_recover; +--echo 1 Expected + +SELECT COUNT(@@wsrep_recover); +--echo 1 Expected + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@local.wsrep_recover); +--echo Expected error 'Variable is a GLOBAL variable' + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@SESSION.wsrep_recover); +--echo Expected error 'Variable is a GLOBAL variable' + +SELECT COUNT(@@GLOBAL.wsrep_recover); +--echo 1 Expected + +--Error ER_BAD_FIELD_ERROR +SELECT wsrep_recover = @@SESSION.wsrep_recover; +--echo Expected error 'Readonly variable' + diff --git a/mysql-test/suite/sys_vars/t/wsrep_replicate_myisam_basic.test b/mysql-test/suite/sys_vars/t/wsrep_replicate_myisam_basic.test new file mode 100644 index 00000000000..c03d76b5123 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_replicate_myisam_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_replicate_myisam; + +set @@global.wsrep_replicate_myisam=ON; +set @@global.wsrep_replicate_myisam=OFF; +set @@global.wsrep_replicate_myisam=1; +set @@global.wsrep_replicate_myisam=0; +--Error 1231 +SET @@global.wsrep_replicate_myisam = -1; + +set @@global.wsrep_replicate_myisam = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_restart_slave_basic.test b/mysql-test/suite/sys_vars/t/wsrep_restart_slave_basic.test new file mode 100644 index 00000000000..82f5a97327d --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_restart_slave_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_restart_slave; + +set @@global.wsrep_restart_slave=ON; +set @@global.wsrep_restart_slave=OFF; +set @@global.wsrep_restart_slave=1; +set @@global.wsrep_restart_slave=0; +--Error 1231 +SET @@global.wsrep_restart_slave = -1; + +set @@global.wsrep_restart_slave = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_retry_autocommit_basic.test b/mysql-test/suite/sys_vars/t/wsrep_retry_autocommit_basic.test new file mode 100644 index 00000000000..82f5a97327d --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_retry_autocommit_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_restart_slave; + +set @@global.wsrep_restart_slave=ON; +set @@global.wsrep_restart_slave=OFF; +set @@global.wsrep_restart_slave=1; +set @@global.wsrep_restart_slave=0; +--Error 1231 +SET @@global.wsrep_restart_slave = -1; + +set @@global.wsrep_restart_slave = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_slave_fk_checks_basic.test b/mysql-test/suite/sys_vars/t/wsrep_slave_fk_checks_basic.test new file mode 100644 index 00000000000..dd60eb8694b --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_slave_fk_checks_basic.test @@ -0,0 +1,42 @@ +--source include/have_wsrep.inc + +--echo # +--echo # wsrep_slave_fk_checks +--echo # + +--echo # save the initial value +SET @wsrep_slave_fk_checks_global_saved = @@global.wsrep_slave_fk_checks; + +--echo # default +SELECT @@global.wsrep_slave_fk_checks; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_slave_fk_checks; +SET @@global.wsrep_slave_fk_checks=OFF; +SELECT @@global.wsrep_slave_fk_checks; +SET @@global.wsrep_slave_fk_checks=ON; +SELECT @@global.wsrep_slave_fk_checks; + +--echo +--echo # valid values +SET @@global.wsrep_slave_fk_checks='OFF'; +SELECT @@global.wsrep_slave_fk_checks; +SET @@global.wsrep_slave_fk_checks=ON; +SELECT @@global.wsrep_slave_fk_checks; +SET @@global.wsrep_slave_fk_checks=default; +SELECT @@global.wsrep_slave_fk_checks; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_slave_fk_checks=NULL; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_slave_fk_checks='junk'; + +--echo +--echo # restore the initial value +SET @@global.wsrep_slave_fk_checks = @wsrep_slave_fk_checks_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_slave_threads_basic.test b/mysql-test/suite/sys_vars/t/wsrep_slave_threads_basic.test new file mode 100644 index 00000000000..cff4f433846 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_slave_threads_basic.test @@ -0,0 +1,16 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_slave_threads; + +set @@global.wsrep_slave_threads=1; +set @@global.wsrep_slave_threads=4; +show warnings; +set @@global.wsrep_slave_threads=0; +show warnings; +set @@global.wsrep_slave_threads=-1; +show warnings; +--Error 1232 +SET @@global.wsrep_slave_threads = r; + +set @@global.wsrep_slave_threads = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_slave_uk_checks_basic.test b/mysql-test/suite/sys_vars/t/wsrep_slave_uk_checks_basic.test new file mode 100644 index 00000000000..c9012954371 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_slave_uk_checks_basic.test @@ -0,0 +1,42 @@ +--source include/have_wsrep.inc + +--echo # +--echo # wsrep_slave_uk_checks +--echo # + +--echo # save the initial value +SET @wsrep_slave_uk_checks_global_saved = @@global.wsrep_slave_uk_checks; + +--echo # default +SELECT @@global.wsrep_slave_uk_checks; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_slave_uk_checks; +SET @@global.wsrep_slave_uk_checks=OFF; +SELECT @@global.wsrep_slave_uk_checks; +SET @@global.wsrep_slave_uk_checks=ON; +SELECT @@global.wsrep_slave_uk_checks; + +--echo +--echo # valid values +SET @@global.wsrep_slave_uk_checks='OFF'; +SELECT @@global.wsrep_slave_uk_checks; +SET @@global.wsrep_slave_uk_checks=ON; +SELECT @@global.wsrep_slave_uk_checks; +SET @@global.wsrep_slave_uk_checks=default; +SELECT @@global.wsrep_slave_uk_checks; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_slave_uk_checks=NULL; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_slave_uk_checks='junk'; + +--echo +--echo # restore the initial value +SET @@global.wsrep_slave_uk_checks = @wsrep_slave_uk_checks_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_sst_auth_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sst_auth_basic.test new file mode 100644 index 00000000000..6db2a4cd844 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_sst_auth_basic.test @@ -0,0 +1,12 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +SELECT COUNT(@@wsrep_sst_auth); + +# Cause crash, fix later +#set @start_value = @@wsrep_sst_auth; +#set @@global.wsrep_sst_auth='root:pass'; +#set @@global.wsrep_sst_auth=NULL; +#set @@global.wsrep_sst_auth=r; +#set @@global.wsrep_sst_auth=1; +#set @@global.wsrep_sst_auth = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_sst_donor_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sst_donor_basic.test new file mode 100644 index 00000000000..58d005282a0 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_sst_donor_basic.test @@ -0,0 +1,12 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +SELECT COUNT(@@wsrep_sst_donor); + +set @start_value = @@wsrep_sst_donor; +set @@global.wsrep_sst_donor='foo'; +set @@global.wsrep_sst_donor=NULL; +set @@global.wsrep_sst_donor=r; +--error 1232 +set @@global.wsrep_sst_donor=1; +set @@global.wsrep_sst_donor = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_sst_donor_rejects_queries_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sst_donor_rejects_queries_basic.test new file mode 100644 index 00000000000..fc8633ce00f --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_sst_donor_rejects_queries_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_sst_donor_rejects_queries; + +set @@global.wsrep_sst_donor_rejects_queries=ON; +set @@global.wsrep_sst_donor_rejects_queries=OFF; +set @@global.wsrep_sst_donor_rejects_queries=1; +set @@global.wsrep_sst_donor_rejects_queries=0; +--Error 1231 +SET @@global.wsrep_sst_donor_rejects_queries = -1; + +set @@global.wsrep_sst_donor_rejects_queries = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_sst_method_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sst_method_basic.test new file mode 100644 index 00000000000..dab5831ff01 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_sst_method_basic.test @@ -0,0 +1,17 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_sst_method; + +set @@global.wsrep_sst_method='xtrabackup'; +set @@global.wsrep_sst_method='xtrabackup-v2'; +set @@global.wsrep_sst_method='rsync'; +set @@global.wsrep_sst_method='mysqldump'; +set @@global.wsrep_sst_method='myscript'; +set @@global.wsrep_sst_method='skip'; +--error 1231 +set @@global.wsrep_sst_method=NULL; +--Error 1232 +SET @@global.wsrep_sst_method = -1; + +set @@global.wsrep_sst_method = @start_value; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/t/wsrep_sst_receive_address_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sst_receive_address_basic.test new file mode 100644 index 00000000000..0a18098d77f --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_sst_receive_address_basic.test @@ -0,0 +1,13 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_sst_receive_address; + +set @@global.wsrep_sst_receive_address='128.0.2.1'; +set @@global.wsrep_sst_receive_address=AUTO; +set @@global.wsrep_sst_receive_address='AUTO'; +set @@global.wsrep_sst_receive_address=NULL; +--Error 1232 +SET @@global.wsrep_sst_receive_address = -1; + +set @@global.wsrep_sst_receive_address = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_start_position_basic.test b/mysql-test/suite/sys_vars/t/wsrep_start_position_basic.test new file mode 100644 index 00000000000..3e30d10c016 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_start_position_basic.test @@ -0,0 +1,14 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_start_position; + +--error 1231 +set @@global.wsrep_start_position='foo:bar'; +--error 1231 +set @@global.wsrep_start_position=NULL; +--Error 1232 +SET @@global.wsrep_start_position = -1; + +set @@global.wsrep_start_position = @start_value; + diff --git a/mysql-test/suite/sys_vars/t/wsrep_sync_wait_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sync_wait_basic.test new file mode 100644 index 00000000000..cd0d545f80e --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_sync_wait_basic.test @@ -0,0 +1,47 @@ +--source include/have_wsrep.inc + +--echo # +--echo # wsrep_sync_wait +--echo # + +--echo # save the initial values +SET @wsrep_sync_wait_global_saved = @@global.wsrep_sync_wait; +SET @wsrep_sync_wait_session_saved = @@session.wsrep_sync_wait; + +--echo # default +SELECT @@global.wsrep_sync_wait; +SELECT @@session.wsrep_sync_wait; + +--echo +--echo # scope and valid values +SET @@global.wsrep_sync_wait=0; +SELECT @@global.wsrep_sync_wait; +SET @@global.wsrep_sync_wait=7; +SELECT @@global.wsrep_sync_wait; + +SET @@session.wsrep_sync_wait=0; +SELECT @@session.wsrep_sync_wait; +SET @@session.wsrep_sync_wait=7; +SELECT @@session.wsrep_sync_wait; +SET @@session.wsrep_sync_wait=default; +SELECT @@session.wsrep_sync_wait; +SET @@session.wsrep_sync_wait=8; +SELECT @@session.wsrep_sync_wait; + +--echo +--echo # invalid values +--error ER_WRONG_TYPE_FOR_VAR +SET @@global.wsrep_sync_wait=NULL; +--error ER_WRONG_TYPE_FOR_VAR +SET @@global.wsrep_sync_wait='junk'; +--error ER_WRONG_TYPE_FOR_VAR +SET @@session.wsrep_sync_wait=NULL; +--error ER_WRONG_TYPE_FOR_VAR +SET @@session.wsrep_sync_wait='junk'; + +--echo +--echo # restore the initial values +SET @@global.wsrep_sync_wait = @wsrep_sync_wait_global_saved; +SET @@session.wsrep_sync_wait = @wsrep_sync_wait_session_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_wsrep_provider_basic.test b/mysql-test/suite/sys_vars/t/wsrep_wsrep_provider_basic.test new file mode 100644 index 00000000000..f4faaccc6a7 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_wsrep_provider_basic.test @@ -0,0 +1,11 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +set @start_value = @@wsrep_provider; + +set @@global.wsrep_provider=none; + +--Error 1231 +SET @@global.wsrep_provider = -1; + +set @@global.wsrep_provider = @start_value; diff --git a/mysql-test/suite/wsrep/README b/mysql-test/suite/wsrep/README new file mode 100644 index 00000000000..988096071a4 --- /dev/null +++ b/mysql-test/suite/wsrep/README @@ -0,0 +1,7 @@ +* 'wsrep' suite is designated for tests which do not require a multi-node + galera cluster. + +* As these tests are specific to wsrep-related functionalities, they must skip + on server built without wsrep patch (vanilla). (-DWITH_WSREP=OFF) + See : include/have_wsrep.inc, include/have_wsrep_enabled.inc, not_wsrep.inc + diff --git a/mysql-test/suite/wsrep/r/binlog_format.result b/mysql-test/suite/wsrep/r/binlog_format.result new file mode 100644 index 00000000000..5b8da51f829 --- /dev/null +++ b/mysql-test/suite/wsrep/r/binlog_format.result @@ -0,0 +1,35 @@ +call mtr.add_suppression("WSREP: cannot get fake InnoDB transaction ID"); +call mtr.add_suppression("WSREP: Could not open saved state file for reading:.*"); +SHOW VARIABLES LIKE 'binlog_format'; +Variable_name Value +binlog_format ROW +SET binlog_format=STATEMENT; +ERROR 42000: Variable 'binlog_format' can't be set to the value of 'STATEMENT' +SHOW WARNINGS; +Level Code Message +Warning 1105 MariaDB Galera does not support binlog format: STATEMENT +Error 1231 Variable 'binlog_format' can't be set to the value of 'STATEMENT' +SHOW VARIABLES LIKE 'binlog_format'; +Variable_name Value +binlog_format ROW +CREATE TABLE IF NOT EXISTS test.t1 AS SELECT * FROM information_schema.routines WHERE 1 = 0; +SET binlog_format=MIXED; +ERROR 42000: Variable 'binlog_format' can't be set to the value of 'MIXED' +SHOW WARNINGS; +Level Code Message +Warning 1105 MariaDB Galera does not support binlog format: MIXED +Error 1231 Variable 'binlog_format' can't be set to the value of 'MIXED' +SHOW VARIABLES LIKE 'binlog_format'; +Variable_name Value +binlog_format ROW +CREATE TABLE IF NOT EXISTS test.t2 AS SELECT * FROM information_schema.routines WHERE 1 = 0; +SET binlog_format=ROW; +SHOW WARNINGS; +Level Code Message +SHOW VARIABLES LIKE 'binlog_format'; +Variable_name Value +binlog_format ROW +CREATE TABLE IF NOT EXISTS test.t3 AS SELECT * FROM information_schema.routines WHERE 1 = 0; +DROP TABLE IF EXISTS test.t1; +DROP TABLE IF EXISTS test.t2; +DROP TABLE IF EXISTS test.t3; diff --git a/mysql-test/suite/wsrep/r/innodb_load_xa_with_wsrep.result b/mysql-test/suite/wsrep/r/innodb_load_xa_with_wsrep.result new file mode 100644 index 00000000000..90faf766145 --- /dev/null +++ b/mysql-test/suite/wsrep/r/innodb_load_xa_with_wsrep.result @@ -0,0 +1,19 @@ +install plugin innodb soname 'ha_innodb'; +select engine,support,transactions,xa from information_schema.engines where engine='innodb'; +engine support transactions xa +InnoDB YES YES YES +create table t1 (a int) engine=innodb; +start transaction; +insert t1 values (1); +insert t1 values (2); +commit; +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +mysqld-bin.000001 # Gtid # # GTID #-#-# +mysqld-bin.000001 # Query # # use `test`; create table t1 (a int) engine=innodb +mysqld-bin.000001 # Gtid # # BEGIN GTID #-#-# +mysqld-bin.000001 # Query # # use `test`; insert t1 values (1) +mysqld-bin.000001 # Query # # use `test`; insert t1 values (2) +mysqld-bin.000001 # Xid # # COMMIT /* XID */ +drop table t1; +uninstall plugin innodb; diff --git a/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink.result b/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink.result new file mode 100644 index 00000000000..f77a655773a --- /dev/null +++ b/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink.result @@ -0,0 +1,70 @@ +# +# MDEV-5226 mysql_tzinfo_to_sql errors with tzdata 2013f and above +# +# Verbose run +SET GLOBAL wsrep_replicate_myisam= ON; +TRUNCATE TABLE time_zone; +TRUNCATE TABLE time_zone_name; +TRUNCATE TABLE time_zone_transition; +TRUNCATE TABLE time_zone_transition_type; +INSERT INTO time_zone (Use_leap_seconds) VALUES ('N'); +SET @time_zone_id= LAST_INSERT_ID(); +INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('GMT', @time_zone_id); +INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, Is_DST, Abbreviation) VALUES + (@time_zone_id, 0, 0, 0, 'GMT') +; +Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/garbage' as time zone. Skipping it. +Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/ignored.tab' as time zone. Skipping it. +INSERT INTO time_zone (Use_leap_seconds) VALUES ('N'); +SET @time_zone_id= LAST_INSERT_ID(); +INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('posix/GMT', @time_zone_id); +INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, Is_DST, Abbreviation) VALUES + (@time_zone_id, 0, 0, 0, 'GMT') +; +Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/garbage' as time zone. Skipping it. +Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/ignored.tab' as time zone. Skipping it. +Warning: Skipping directory 'MYSQLTEST_VARDIR/zoneinfo/posix/posix': to avoid infinite symlink recursion. +ALTER TABLE time_zone_transition ORDER BY Time_zone_id, Transition_time; +ALTER TABLE time_zone_transition_type ORDER BY Time_zone_id, Transition_type_id; +SET GLOBAL wsrep_replicate_myisam= OFF; +# Silent run +SET GLOBAL wsrep_replicate_myisam= ON; +TRUNCATE TABLE time_zone; +TRUNCATE TABLE time_zone_name; +TRUNCATE TABLE time_zone_transition; +TRUNCATE TABLE time_zone_transition_type; +INSERT INTO time_zone (Use_leap_seconds) VALUES ('N'); +SET @time_zone_id= LAST_INSERT_ID(); +INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('GMT', @time_zone_id); +INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, Is_DST, Abbreviation) VALUES + (@time_zone_id, 0, 0, 0, 'GMT') +; +Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/garbage' as time zone. Skipping it. +INSERT INTO time_zone (Use_leap_seconds) VALUES ('N'); +SET @time_zone_id= LAST_INSERT_ID(); +INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('posix/GMT', @time_zone_id); +INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, Is_DST, Abbreviation) VALUES + (@time_zone_id, 0, 0, 0, 'GMT') +; +Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/garbage' as time zone. Skipping it. +ALTER TABLE time_zone_transition ORDER BY Time_zone_id, Transition_time; +ALTER TABLE time_zone_transition_type ORDER BY Time_zone_id, Transition_type_id; +SET GLOBAL wsrep_replicate_myisam= OFF; +# +# Testing with explicit timezonefile +# +SET GLOBAL wsrep_replicate_myisam= ON; +INSERT INTO time_zone (Use_leap_seconds) VALUES ('N'); +SET @time_zone_id= LAST_INSERT_ID(); +INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('XXX', @time_zone_id); +INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, Is_DST, Abbreviation) VALUES + (@time_zone_id, 0, 0, 0, 'GMT') +; +SET GLOBAL wsrep_replicate_myisam= OFF; +# +# Testing --leap +# +SET GLOBAL wsrep_replicate_myisam= ON; +TRUNCATE TABLE time_zone_leap_second; +ALTER TABLE time_zone_leap_second ORDER BY Transition_time; +SET GLOBAL wsrep_replicate_myisam= OFF; diff --git a/mysql-test/suite/wsrep/r/pool_of_threads.result b/mysql-test/suite/wsrep/r/pool_of_threads.result new file mode 100644 index 00000000000..ffe309f2580 --- /dev/null +++ b/mysql-test/suite/wsrep/r/pool_of_threads.result @@ -0,0 +1,8 @@ + +# +# MDEV#5687: Maria doesn't shutdown following upgrade to 5.5.35-galera +# +SELECT @@GLOBAL.thread_handling; +@@GLOBAL.thread_handling +pool-of-threads +# End of test. diff --git a/mysql-test/suite/wsrep/r/trans.result b/mysql-test/suite/wsrep/r/trans.result new file mode 100644 index 00000000000..bc225897103 --- /dev/null +++ b/mysql-test/suite/wsrep/r/trans.result @@ -0,0 +1,9 @@ +# +# MDEV-4222 : Assertion `( ((global_system_variables.wsrep_on) && +# (thd && thd->variables.wsrep_on)) && srep_emulate_bin_log) +# || mysql_bin_log .is_open()' fails on SAVEPOINT with +# disabled wsrep_provider +# +START TRANSACTION WITH CONSISTENT SNAPSHOT; +SAVEPOINT A; +End of test. diff --git a/mysql-test/suite/wsrep/r/variables.result b/mysql-test/suite/wsrep/r/variables.result new file mode 100644 index 00000000000..bd762f916bc --- /dev/null +++ b/mysql-test/suite/wsrep/r/variables.result @@ -0,0 +1,222 @@ + +# MDEV#5534: mysql_tzinfo_to_sql generates wrong query +# +# Testing wsrep_replicate_myisam variable. +SELECT @@session.wsrep_replicate_myisam; +ERROR HY000: Variable 'wsrep_replicate_myisam' is a GLOBAL variable +SELECT @@global.wsrep_replicate_myisam; +@@global.wsrep_replicate_myisam +0 +SET SESSION wsrep_replicate_myisam= ON; +ERROR HY000: Variable 'wsrep_replicate_myisam' is a GLOBAL variable and should be set with SET GLOBAL +SET GLOBAL wsrep_replicate_myisam= ON; +SET GLOBAL wsrep_replicate_myisam= OFF; +SET GLOBAL wsrep_provider=none; +# +# MDEV#5790: SHOW GLOBAL STATUS LIKE does not show the correct list of +# variables when using "_" +# +CALL mtr.add_suppression("WSREP: Could not open saved state file for reading.*"); +SHOW GLOBAL STATUS LIKE 'wsrep%'; +Variable_name Value +wsrep_local_state_uuid # +wsrep_protocol_version # +wsrep_last_committed # +wsrep_replicated # +wsrep_replicated_bytes # +wsrep_repl_keys # +wsrep_repl_keys_bytes # +wsrep_repl_data_bytes # +wsrep_repl_other_bytes # +wsrep_received # +wsrep_received_bytes # +wsrep_local_commits # +wsrep_local_cert_failures # +wsrep_local_replays # +wsrep_local_send_queue # +wsrep_local_send_queue_avg # +wsrep_local_recv_queue # +wsrep_local_recv_queue_avg # +wsrep_local_cached_downto # +wsrep_flow_control_paused_ns # +wsrep_flow_control_paused # +wsrep_flow_control_sent # +wsrep_flow_control_recv # +wsrep_cert_deps_distance # +wsrep_apply_oooe # +wsrep_apply_oool # +wsrep_apply_window # +wsrep_commit_oooe # +wsrep_commit_oool # +wsrep_commit_window # +wsrep_local_state # +wsrep_local_state_comment # +wsrep_cert_index_size # +wsrep_causal_reads # +wsrep_cert_interval # +wsrep_incoming_addresses # +wsrep_cluster_conf_id # +wsrep_cluster_size # +wsrep_cluster_state_uuid # +wsrep_cluster_status # +wsrep_connected # +wsrep_local_bf_aborts # +wsrep_local_index # +wsrep_provider_name # +wsrep_provider_vendor # +wsrep_provider_version # +wsrep_ready # +wsrep_thread_count # + +SHOW GLOBAL STATUS LIKE 'wsrep_%'; +Variable_name Value +wsrep_local_state_uuid # +wsrep_protocol_version # +wsrep_last_committed # +wsrep_replicated # +wsrep_replicated_bytes # +wsrep_repl_keys # +wsrep_repl_keys_bytes # +wsrep_repl_data_bytes # +wsrep_repl_other_bytes # +wsrep_received # +wsrep_received_bytes # +wsrep_local_commits # +wsrep_local_cert_failures # +wsrep_local_replays # +wsrep_local_send_queue # +wsrep_local_send_queue_avg # +wsrep_local_recv_queue # +wsrep_local_recv_queue_avg # +wsrep_local_cached_downto # +wsrep_flow_control_paused_ns # +wsrep_flow_control_paused # +wsrep_flow_control_sent # +wsrep_flow_control_recv # +wsrep_cert_deps_distance # +wsrep_apply_oooe # +wsrep_apply_oool # +wsrep_apply_window # +wsrep_commit_oooe # +wsrep_commit_oool # +wsrep_commit_window # +wsrep_local_state # +wsrep_local_state_comment # +wsrep_cert_index_size # +wsrep_causal_reads # +wsrep_cert_interval # +wsrep_incoming_addresses # +wsrep_cluster_conf_id # +wsrep_cluster_size # +wsrep_cluster_state_uuid # +wsrep_cluster_status # +wsrep_connected # +wsrep_local_bf_aborts # +wsrep_local_index # +wsrep_provider_name # +wsrep_provider_vendor # +wsrep_provider_version # +wsrep_ready # +wsrep_thread_count # +SHOW GLOBAL STATUS LIKE 'wsrep_local_state_comment'; +Variable_name Value +wsrep_local_state_comment # +# Should show nothing. +SHOW STATUS LIKE 'x'; +Variable_name Value +SET GLOBAL wsrep_provider=none; +# +# MDEV#6079: xtrabackup SST failing with maria-10.0-galera +# + +SHOW STATUS LIKE 'wsrep_local_state_uuid'; +Variable_name Value +wsrep_local_state_uuid # + +SHOW STATUS LIKE 'wsrep_last_committed'; +Variable_name Value +wsrep_last_committed # +SET GLOBAL wsrep_provider=none; + +# +# MDEV#6206: wsrep_slave_threads subtracts from max_connections +# +call mtr.add_suppression("safe_mutex: Found wrong usage of mutex 'LOCK_wsrep_slave_threads' and 'LOCK_global_system_variables'"); +call mtr.add_suppression("WSREP: Failed to get provider options"); +SELECT @@global.wsrep_provider; +@@global.wsrep_provider +libgalera_smm.so +SELECT @@global.wsrep_slave_threads; +@@global.wsrep_slave_threads +1 +SELECT @@global.wsrep_cluster_address; +@@global.wsrep_cluster_address +NULL +SHOW STATUS LIKE 'threads_connected'; +Variable_name Value +Threads_connected 1 +SHOW STATUS LIKE 'wsrep_thread_count'; +Variable_name Value +wsrep_thread_count 0 + +SELECT @@global.wsrep_provider; +@@global.wsrep_provider +libgalera_smm.so +SELECT @@global.wsrep_cluster_address; +@@global.wsrep_cluster_address +NULL +SHOW STATUS LIKE 'threads_connected'; +Variable_name Value +Threads_connected 1 +SHOW STATUS LIKE 'wsrep_thread_count'; +Variable_name Value +wsrep_thread_count 0 + +# Setting wsrep_cluster_address triggers the creation of +# applier/rollbacker threads. +SET GLOBAL wsrep_cluster_address= 'gcomm://'; +# Wait for applier threads to get created. +SELECT @@global.wsrep_provider; +@@global.wsrep_provider +libgalera_smm.so +SELECT @@global.wsrep_cluster_address; +@@global.wsrep_cluster_address +gcomm:// +SHOW STATUS LIKE 'threads_connected'; +Variable_name Value +Threads_connected 1 +SHOW STATUS LIKE 'wsrep_thread_count'; +Variable_name Value +wsrep_thread_count 2 + +SET @wsrep_slave_threads_saved= @@global.wsrep_slave_threads; +SET GLOBAL wsrep_slave_threads= 10; +# Wait for applier threads to get created. +SHOW STATUS LIKE 'threads_connected'; +Variable_name Value +Threads_connected 1 +SHOW STATUS LIKE 'wsrep_thread_count'; +Variable_name Value +wsrep_thread_count 11 +SET GLOBAL wsrep_slave_threads= @wsrep_slave_threads_saved; +SET GLOBAL wsrep_provider= none; +SET GLOBAL wsrep_cluster_address= ''; +SET GLOBAL wsrep_provider_options= ''; +# +# MDEV#6411: Setting set @@global.wsrep_sst_auth=NULL causes crash +# +SET @wsrep_sst_auth_saved= @@global.wsrep_sst_auth; +SET @@global.wsrep_sst_auth= 'user:pass'; +SELECT @@global.wsrep_sst_auth; +@@global.wsrep_sst_auth +******** +SET @@global.wsrep_sst_auth= ''; +SELECT @@global.wsrep_sst_auth; +@@global.wsrep_sst_auth + +SET @@global.wsrep_sst_auth= NULL; +SELECT @@global.wsrep_sst_auth; +@@global.wsrep_sst_auth +NULL +SET @@global.wsrep_sst_auth= @wsrep_sst_auth_saved; +# End of test. diff --git a/mysql-test/suite/wsrep/t/binlog_format.opt b/mysql-test/suite/wsrep/t/binlog_format.opt new file mode 100644 index 00000000000..1b8937b91f3 --- /dev/null +++ b/mysql-test/suite/wsrep/t/binlog_format.opt @@ -0,0 +1 @@ +--binlog-format=row --innodb_autoinc_lock_mode=2 --innodb_locks_unsafe_for_binlog=1 --wsrep-provider=$WSREP_PROVIDER --wsrep-cluster-address=gcomm:// --wsrep_provider_options='base_port=$GALERA_BASE_PORT' --wsrep-on=1 --log-bin diff --git a/mysql-test/suite/wsrep/t/binlog_format.test b/mysql-test/suite/wsrep/t/binlog_format.test new file mode 100644 index 00000000000..99d34873512 --- /dev/null +++ b/mysql-test/suite/wsrep/t/binlog_format.test @@ -0,0 +1,27 @@ +--source include/have_wsrep_enabled.inc +--source include/have_binlog_format_row.inc +# +# MDEV-4227: Galera server should stop crashing on setting binlog_format STATEMENT +# +call mtr.add_suppression("WSREP: cannot get fake InnoDB transaction ID"); +call mtr.add_suppression("WSREP: Could not open saved state file for reading:.*"); + +SHOW VARIABLES LIKE 'binlog_format'; +-- error ER_WRONG_VALUE_FOR_VAR +SET binlog_format=STATEMENT; +SHOW WARNINGS; +SHOW VARIABLES LIKE 'binlog_format'; +CREATE TABLE IF NOT EXISTS test.t1 AS SELECT * FROM information_schema.routines WHERE 1 = 0; +-- error ER_WRONG_VALUE_FOR_VAR +SET binlog_format=MIXED; +SHOW WARNINGS; +SHOW VARIABLES LIKE 'binlog_format'; +CREATE TABLE IF NOT EXISTS test.t2 AS SELECT * FROM information_schema.routines WHERE 1 = 0; +SET binlog_format=ROW; +SHOW WARNINGS; +SHOW VARIABLES LIKE 'binlog_format'; +CREATE TABLE IF NOT EXISTS test.t3 AS SELECT * FROM information_schema.routines WHERE 1 = 0; +DROP TABLE IF EXISTS test.t1; +DROP TABLE IF EXISTS test.t2; +DROP TABLE IF EXISTS test.t3; + diff --git a/mysql-test/suite/wsrep/t/innodb_load_xa_with_wsrep.opt b/mysql-test/suite/wsrep/t/innodb_load_xa_with_wsrep.opt new file mode 100644 index 00000000000..4ff27e659ce --- /dev/null +++ b/mysql-test/suite/wsrep/t/innodb_load_xa_with_wsrep.opt @@ -0,0 +1 @@ +--ignore-builtin-innodb --loose-innodb --log-bin diff --git a/mysql-test/suite/wsrep/t/innodb_load_xa_with_wsrep.test b/mysql-test/suite/wsrep/t/innodb_load_xa_with_wsrep.test new file mode 100644 index 00000000000..413faf54864 --- /dev/null +++ b/mysql-test/suite/wsrep/t/innodb_load_xa_with_wsrep.test @@ -0,0 +1,19 @@ +# +# MDEV-6082 Assertion `0' fails in TC_LOG_DUMMY::log_and_order on DML after installing TokuDB at runtime on server with disabled InnoDB +# +--source include/not_embedded.inc +--source include/have_wsrep.inc + +if (!$HA_INNODB_SO) { + --skip Need InnoDB plugin +} +install plugin innodb soname 'ha_innodb'; +select engine,support,transactions,xa from information_schema.engines where engine='innodb'; +create table t1 (a int) engine=innodb; +start transaction; +insert t1 values (1); +insert t1 values (2); +commit; +--source include/show_binlog_events.inc +drop table t1; +uninstall plugin innodb; diff --git a/mysql-test/suite/wsrep/t/mysql_tzinfo_to_sql_symlink.test b/mysql-test/suite/wsrep/t/mysql_tzinfo_to_sql_symlink.test new file mode 100644 index 00000000000..100e09d3afb --- /dev/null +++ b/mysql-test/suite/wsrep/t/mysql_tzinfo_to_sql_symlink.test @@ -0,0 +1,40 @@ +--source include/have_wsrep.inc +--source include/have_symlink.inc +--source include/not_windows.inc + +--echo # +--echo # MDEV-5226 mysql_tzinfo_to_sql errors with tzdata 2013f and above +--echo # + +--exec mkdir $MYSQLTEST_VARDIR/zoneinfo +--exec ln -s $MYSQLTEST_VARDIR/zoneinfo $MYSQLTEST_VARDIR/zoneinfo/posix +--copy_file std_data/zoneinfo/GMT $MYSQLTEST_VARDIR/zoneinfo/GMT +--copy_file std_data/words.dat $MYSQLTEST_VARDIR/zoneinfo/garbage +--copy_file std_data/words.dat $MYSQLTEST_VARDIR/zoneinfo/ignored.tab + +--echo # Verbose run +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MYSQL_TZINFO_TO_SQL --verbose $MYSQLTEST_VARDIR/zoneinfo 2>&1 + +--echo # Silent run +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MYSQL_TZINFO_TO_SQL $MYSQLTEST_VARDIR/zoneinfo 2>&1 + +--echo # +--echo # Testing with explicit timezonefile +--echo # + +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MYSQL_TZINFO_TO_SQL $MYSQLTEST_VARDIR/zoneinfo/GMT XXX 2>&1 + +--echo # +--echo # Testing --leap +--echo # + +--exec $MYSQL_TZINFO_TO_SQL --leap $MYSQLTEST_VARDIR/zoneinfo/GMT 2>&1 + +# +# Cleanup +# + +--exec rm -rf $MYSQLTEST_VARDIR/zoneinfo diff --git a/mysql-test/suite/wsrep/t/pool_of_threads.opt b/mysql-test/suite/wsrep/t/pool_of_threads.opt new file mode 100644 index 00000000000..5ee38531a4a --- /dev/null +++ b/mysql-test/suite/wsrep/t/pool_of_threads.opt @@ -0,0 +1 @@ +--binlog-format=row --innodb_autoinc_lock_mode=2 --innodb_locks_unsafe_for_binlog=1 --wsrep-provider=$WSREP_PROVIDER --wsrep-cluster-address=gcomm:// --wsrep_provider_options='base_port=$GALERA_BASE_PORT' --thread_handling=pool-of-threads diff --git a/mysql-test/suite/wsrep/t/pool_of_threads.test b/mysql-test/suite/wsrep/t/pool_of_threads.test new file mode 100644 index 00000000000..f4fffaf4f9a --- /dev/null +++ b/mysql-test/suite/wsrep/t/pool_of_threads.test @@ -0,0 +1,11 @@ +--source include/have_wsrep.inc + +--echo +--echo # +--echo # MDEV#5687: Maria doesn't shutdown following upgrade to 5.5.35-galera +--echo # + +# Note: This test is to ensure that server shuts down properly. +SELECT @@GLOBAL.thread_handling; + +--echo # End of test. diff --git a/mysql-test/suite/wsrep/t/trans.test b/mysql-test/suite/wsrep/t/trans.test new file mode 100644 index 00000000000..d8c4a4722a0 --- /dev/null +++ b/mysql-test/suite/wsrep/t/trans.test @@ -0,0 +1,14 @@ +--source include/have_wsrep.inc +--source include/have_innodb.inc + +--echo # +--echo # MDEV-4222 : Assertion `( ((global_system_variables.wsrep_on) && +--echo # (thd && thd->variables.wsrep_on)) && srep_emulate_bin_log) +--echo # || mysql_bin_log .is_open()' fails on SAVEPOINT with +--echo # disabled wsrep_provider +--echo # + +START TRANSACTION WITH CONSISTENT SNAPSHOT; +SAVEPOINT A; + +--echo End of test. diff --git a/mysql-test/suite/wsrep/t/variables.test b/mysql-test/suite/wsrep/t/variables.test new file mode 100644 index 00000000000..6cc895a75d9 --- /dev/null +++ b/mysql-test/suite/wsrep/t/variables.test @@ -0,0 +1,146 @@ +--source include/have_wsrep.inc + +# Set galera's base_port so that test can run in parallel with other galera +# tests. +--disable_query_log +eval SET GLOBAL wsrep_provider_options='base_port=$GALERA_BASE_PORT'; +--enable_query_log + +--echo +--echo # MDEV#5534: mysql_tzinfo_to_sql generates wrong query +--echo # +--echo # Testing wsrep_replicate_myisam variable. + +--disable_query_log +eval SET GLOBAL wsrep_provider= '$WSREP_PROVIDER'; +--enable_query_log + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_replicate_myisam; +SELECT @@global.wsrep_replicate_myisam; + +--error ER_GLOBAL_VARIABLE +SET SESSION wsrep_replicate_myisam= ON; +SET GLOBAL wsrep_replicate_myisam= ON; + +# Reset it back. +SET GLOBAL wsrep_replicate_myisam= OFF; +SET GLOBAL wsrep_provider=none; + +--echo # +--echo # MDEV#5790: SHOW GLOBAL STATUS LIKE does not show the correct list of +--echo # variables when using "_" +--echo # + +CALL mtr.add_suppression("WSREP: Could not open saved state file for reading.*"); + +--disable_query_log +eval SET GLOBAL wsrep_provider= '$WSREP_PROVIDER'; +--enable_query_log + +--replace_column 2 # +SHOW GLOBAL STATUS LIKE 'wsrep%'; + +--echo +--replace_column 2 # +SHOW GLOBAL STATUS LIKE 'wsrep_%'; + +--replace_column 2 # +SHOW GLOBAL STATUS LIKE 'wsrep_local_state_comment'; + +--echo # Should show nothing. +SHOW STATUS LIKE 'x'; + +# Reset it back. +SET GLOBAL wsrep_provider=none; + +--echo # +--echo # MDEV#6079: xtrabackup SST failing with maria-10.0-galera +--echo # + +--disable_query_log +eval SET GLOBAL wsrep_provider= '$WSREP_PROVIDER'; +--enable_query_log + +# The following 2 variables are used in innobackupex during xtrabackup-based +# SST. +--echo +--replace_column 2 # +SHOW STATUS LIKE 'wsrep_local_state_uuid'; +--echo +--replace_column 2 # +SHOW STATUS LIKE 'wsrep_last_committed'; + +# Reset it back. +SET GLOBAL wsrep_provider=none; + +--echo +--echo # +--echo # MDEV#6206: wsrep_slave_threads subtracts from max_connections +--echo # +call mtr.add_suppression("safe_mutex: Found wrong usage of mutex 'LOCK_wsrep_slave_threads' and 'LOCK_global_system_variables'"); +call mtr.add_suppression("WSREP: Failed to get provider options"); + +--disable_query_log +eval SET GLOBAL wsrep_provider= '$WSREP_PROVIDER'; +--enable_query_log + +--replace_regex /.*libgalera_smm.*/libgalera_smm.so/ +SELECT @@global.wsrep_provider; +SELECT @@global.wsrep_slave_threads; +SELECT @@global.wsrep_cluster_address; +SHOW STATUS LIKE 'threads_connected'; +SHOW STATUS LIKE 'wsrep_thread_count'; +--echo + +--disable_query_log +eval SET GLOBAL wsrep_provider= '$WSREP_PROVIDER'; +--enable_query_log + +--replace_regex /.*libgalera_smm.*/libgalera_smm.so/ +SELECT @@global.wsrep_provider; +SELECT @@global.wsrep_cluster_address; +SHOW STATUS LIKE 'threads_connected'; +SHOW STATUS LIKE 'wsrep_thread_count'; +--echo + +--echo # Setting wsrep_cluster_address triggers the creation of +--echo # applier/rollbacker threads. +SET GLOBAL wsrep_cluster_address= 'gcomm://'; +--echo # Wait for applier threads to get created. +sleep 3; + +--replace_regex /.*libgalera_smm.*/libgalera_smm.so/ +SELECT @@global.wsrep_provider; +SELECT @@global.wsrep_cluster_address; +SHOW STATUS LIKE 'threads_connected'; +SHOW STATUS LIKE 'wsrep_thread_count'; +--echo + +SET @wsrep_slave_threads_saved= @@global.wsrep_slave_threads; +SET GLOBAL wsrep_slave_threads= 10; +--echo # Wait for applier threads to get created. +sleep 3; +SHOW STATUS LIKE 'threads_connected'; +SHOW STATUS LIKE 'wsrep_thread_count'; + +# reset (for mtr internal checks) +SET GLOBAL wsrep_slave_threads= @wsrep_slave_threads_saved; +SET GLOBAL wsrep_provider= none; +SET GLOBAL wsrep_cluster_address= ''; +SET GLOBAL wsrep_provider_options= ''; + +--echo # +--echo # MDEV#6411: Setting set @@global.wsrep_sst_auth=NULL causes crash +--echo # +SET @wsrep_sst_auth_saved= @@global.wsrep_sst_auth; +SET @@global.wsrep_sst_auth= 'user:pass'; +SELECT @@global.wsrep_sst_auth; +SET @@global.wsrep_sst_auth= ''; +SELECT @@global.wsrep_sst_auth; +SET @@global.wsrep_sst_auth= NULL; +SELECT @@global.wsrep_sst_auth; +SET @@global.wsrep_sst_auth= @wsrep_sst_auth_saved; + +--echo # End of test. + diff --git a/mysql-test/t/mysql_tzinfo_to_sql_symlink.test b/mysql-test/t/mysql_tzinfo_to_sql_symlink.test index 1ba4e91be3c..0c70315c93b 100644 --- a/mysql-test/t/mysql_tzinfo_to_sql_symlink.test +++ b/mysql-test/t/mysql_tzinfo_to_sql_symlink.test @@ -1,5 +1,16 @@ --source include/have_symlink.inc --source include/not_windows.inc +--source include/not_wsrep.inc + +# Note: The output of mysql_tzinfo_to_sql is different if server is compiled +# with wsrep. Hence a copy of this test has been placed under wsrep suite with +# the updated result. (lp:1161432) +--source include/not_wsrep.inc + +# Note: The output of mysql_tzinfo_to_sql is different if server is compiled +# with wsrep. Hence a copy of this test has been placed under wsrep suite with +# the updated result. (lp:1161432) +--source include/not_wsrep.inc --echo # --echo # MDEV-5226 mysql_tzinfo_to_sql errors with tzdata 2013f and above diff --git a/mysql-test/t/mysqld--help.test b/mysql-test/t/mysqld--help.test index c27fa58f935..a8cafed9efb 100644 --- a/mysql-test/t/mysqld--help.test +++ b/mysql-test/t/mysqld--help.test @@ -4,6 +4,7 @@ --source include/not_embedded.inc --source include/have_perfschema.inc --source include/platform.inc +--source include/not_wsrep.inc # # force lower-case-table-names=1 (linux/macosx have different defaults) @@ -22,7 +23,7 @@ perl; log-slow-queries pid-file slow-query-log-file log-basename datadir slave-load-tmpdir tmpdir socket thread-pool-size large-files-support lower-case-file-system system-time-zone - version.*/; + wsrep-node-name version.*/; # Plugins which may or may not be there: @plugins=qw/innodb ndb archive blackhole federated partition ndbcluster diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index f0d25dae6b9..e342427c737 100644 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -15,6 +15,10 @@ INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/mysys) +IF(WITH_WSREP) + BUILD_WITH_WSREP() +ENDIF() + SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c my_default.c errors.c hash.c list.c mf_cache.c mf_dirname.c mf_fn_ext.c diff --git a/mysys/my_default.c b/mysys/my_default.c index 1e4038d17fb..1a29fd87a34 100644 --- a/mysys/my_default.c +++ b/mysys/my_default.c @@ -88,6 +88,12 @@ static char my_defaults_extra_file_buffer[FN_REFLEN]; static my_bool defaults_already_read= FALSE; +#ifdef WITH_WSREP +/* The only purpose of this global array is to hold full name of my.cnf + * which seems to be otherwise unavailable */ +char wsrep_defaults_file[FN_REFLEN + 10]={0,}; +#endif /* WITH_WREP */ + /* Which directories are searched for options (and in which order) */ #define MAX_DEFAULT_DIRS 6 @@ -804,6 +810,12 @@ static int search_default_file_with_ext(Process_option_func opt_handler, if (!(fp= mysql_file_fopen(key_file_cnf, name, O_RDONLY, MYF(0)))) return 1; /* Ignore wrong files */ +#ifdef WITH_WSREP + /* make sure we do this only once - for top-level file */ + if ('\0' == wsrep_defaults_file[0]) + strmake(wsrep_defaults_file, name, sizeof(wsrep_defaults_file) - 1); +#endif /* WITH_WSREP */ + while (mysql_file_fgets(buff, sizeof(buff) - 1, fp)) { line++; diff --git a/mysys/my_static.c b/mysys/my_static.c index 84d2dc64fc6..4c977837e05 100644 --- a/mysys/my_static.c +++ b/mysys/my_static.c @@ -68,6 +68,10 @@ uint my_large_page_size= 0; int volatile my_have_got_alarm=0; /* declare variable to reset */ ulong my_time_to_wait_for_lock=2; /* In seconds */ +#ifdef WITH_WSREP +my_bool mysys_wsrep= 0; +#endif + /* from errors.c */ #ifdef SHARED_LIBRARY const char *globerrs[GLOBERRS]; /* my_error_messages is here */ diff --git a/mysys/mysys_priv.h b/mysys/mysys_priv.h index 9c6855bb92f..80c6a981db2 100644 --- a/mysys/mysys_priv.h +++ b/mysys/mysys_priv.h @@ -62,6 +62,8 @@ extern mysql_mutex_t THR_LOCK_malloc, THR_LOCK_open, THR_LOCK_keycache; extern mysql_mutex_t THR_LOCK_lock, THR_LOCK_net; extern mysql_mutex_t THR_LOCK_charset; +extern my_bool mysys_wsrep; + #include #ifdef HAVE_PSI_INTERFACE diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index 60e01974320..acc7d718546 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -95,6 +95,24 @@ my_bool thr_lock_inited=0; ulong locks_immediate = 0L, locks_waited = 0L; enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE; +#ifdef WITH_WSREP +static wsrep_thd_is_brute_force_fun wsrep_thd_is_brute_force= NULL; +static wsrep_abort_thd_fun wsrep_abort_thd= NULL; +static my_bool wsrep_debug; +static my_bool wsrep_convert_LOCK_to_trx; +static wsrep_on_fun wsrep_on = NULL; + +void wsrep_thr_lock_init( + wsrep_thd_is_brute_force_fun bf_fun, wsrep_abort_thd_fun abort_fun, + my_bool debug, my_bool convert_LOCK_to_trx, wsrep_on_fun on_fun +) { + wsrep_thd_is_brute_force = bf_fun; + wsrep_abort_thd = abort_fun; + wsrep_debug = debug; + wsrep_convert_LOCK_to_trx= convert_LOCK_to_trx; + wsrep_on = on_fun; +} +#endif /* The following constants are only for debug output */ #define MAX_THREADS 1000 #define MAX_LOCKS 1000 @@ -646,6 +664,92 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, DBUG_RETURN(result); } +#ifdef WITH_WSREP +/* + * If brute force applier would need to wait for a thr lock, + * it needs to make sure that it will get the lock without (too much) + * delay. + * We identify here the owners of blocking locks and ask them to + * abort. We then put our lock request in the first place in the + * wait queue. When lock holders abort (one by one) the lock release + * algorithm should grant the lock to us. We rely on this and proceed + * to wait_for_locks(). + * wsrep_break_locks() should be called in all the cases, where lock + * wait would happen. + * + * TODO: current implementation might not cover all possible lock wait + * situations. This needs an review still. + * TODO: lock release, might favor some other lock (instead our bf). + * This needs an condition to check for bf locks first. + * TODO: we still have a debug fprintf, this should be removed + */ +static my_bool +wsrep_break_lock( + THR_LOCK_DATA *data, struct st_lock_list *lock_queue1, + struct st_lock_list *wait_queue) +{ + if (wsrep_on(data->owner->mysql_thd) && + wsrep_thd_is_brute_force && + wsrep_thd_is_brute_force(data->owner->mysql_thd, TRUE)) + { + THR_LOCK_DATA *holder; + + /* if locking session conversion to transaction has been enabled, + we know that this conflicting lock must be read lock and furthermore, + lock holder is read-only. It is safe to wait for him. + */ +#ifdef TODO_WHEN_LOCK_TABLES_IS_A_TRANSACTION + if (wsrep_convert_LOCK_to_trx && + (THD*)(data->owner->mysql_thd)->in_lock_tables) + { + if (wsrep_debug) + fprintf(stderr,"WSREP wsrep_break_lock read lock untouched\n"); + return FALSE; + } +#endif + if (wsrep_debug) + fprintf(stderr,"WSREP wsrep_break_lock aborting locks\n"); + + /* aborting lock holder(s) here */ + for (holder=(lock_queue1) ? lock_queue1->data : NULL; + holder; + holder=holder->next) + { + if (!wsrep_thd_is_brute_force(holder->owner->mysql_thd, TRUE)) + { + wsrep_abort_thd(data->owner->mysql_thd, + holder->owner->mysql_thd, FALSE); + } + else + { + if (wsrep_debug) + fprintf(stderr,"WSREP wsrep_break_lock skipping BF lock conflict\n"); + return FALSE; + } + } + + /* Add our lock to the head of the wait queue */ + if (*(wait_queue->last)==wait_queue->data) + { + wait_queue->last=&data->next; + assert(wait_queue->data==0); + } + else + { + assert(wait_queue->data!=0); + wait_queue->data->prev=&data->next; + } + data->next=wait_queue->data; + data->prev=&wait_queue->data; + wait_queue->data=data; + data->cond=get_cond(); + + statistic_increment(locks_immediate,&THR_LOCK_lock); + return TRUE; + } + return FALSE; +} +#endif static enum enum_thr_lock_result thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) @@ -654,6 +758,9 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) enum enum_thr_lock_result result= THR_LOCK_SUCCESS; struct st_lock_list *wait_queue; enum thr_lock_type lock_type= data->type; +#ifdef WITH_WSREP + my_bool wsrep_lock_inserted= FALSE; +#endif MYSQL_TABLE_WAIT_VARIABLES(locker, state) /* no ';' */ DBUG_ENTER("thr_lock"); @@ -750,6 +857,14 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) lock but a high priority write waiting in the write_wait queue. In the latter case we should yield the lock to the writer. */ +#ifdef WITH_WSREP + if (mysys_wsrep && wsrep_break_lock(data, &lock->write, &lock->read_wait)) + { + wsrep_lock_inserted= TRUE; + } + wsrep_read_wait: +#endif + wait_queue= &lock->read_wait; } else /* Request for WRITE lock */ @@ -891,9 +1006,22 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) DBUG_PRINT("lock",("write locked 3 by thread: 0x%lx type: %d", lock->read.data->owner->thread_id, data->type)); } +#ifdef WITH_WSREP + if (mysys_wsrep && wsrep_break_lock(data, &lock->write, &lock->write_wait)) + { + wsrep_lock_inserted= TRUE; + } + wsrep_write_wait: + +#endif + wait_queue= &lock->write_wait; } /* Can't get lock yet; Wait for it */ +#ifdef WITH_WSREP + if (mysys_wsrep && wsrep_lock_inserted && wsrep_on(data->owner->mysql_thd)) + DBUG_RETURN(wait_for_lock(wait_queue, data, 1, lock_wait_timeout)); +#endif result= wait_for_lock(wait_queue, data, 0, lock_wait_timeout); MYSQL_END_TABLE_LOCK_WAIT(locker); DBUG_RETURN(result); diff --git a/plugin/feedback/CMakeLists.txt b/plugin/feedback/CMakeLists.txt index a243ba07751..9070de26ccb 100644 --- a/plugin/feedback/CMakeLists.txt +++ b/plugin/feedback/CMakeLists.txt @@ -18,6 +18,7 @@ IF(WIN32) ENDIF(WIN32) MYSQL_ADD_PLUGIN(FEEDBACK ${FEEDBACK_SOURCES} + RECOMPILE_FOR_EMBEDDED LINK_LIBRARIES ${SSL_LIBRARIES} ${MAYBE_STATIC_ONLY} DEFAULT) diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt index d3a7861269c..1f0f28061ed 100644 --- a/scripts/CMakeLists.txt +++ b/scripts/CMakeLists.txt @@ -327,6 +327,15 @@ IF(WIN32) INSTALL_SCRIPT(${CMAKE_CURRENT_BINARY_DIR}/${file}.pl COMPONENT Server_Scripts) ENDFOREACH() ELSE() + IF(WITH_WSREP) + SET(WSREP_BINARIES + wsrep_sst_common + wsrep_sst_mysqldump + wsrep_sst_rsync + wsrep_sst_xtrabackup + wsrep_sst_xtrabackup-v2 + ) + ENDIF() # Configure this one, for testing, but do not install it. CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/mysql_config.pl.in ${CMAKE_CURRENT_BINARY_DIR}/mysql_config.pl ESCAPE_QUOTES @ONLY) @@ -346,6 +355,7 @@ ELSE() mysqldumpslow mysqld_multi mysqld_safe + ${WSREP_BINARIES} ) FOREACH(file ${BIN_SCRIPTS}) IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${file}.sh) diff --git a/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh index cd1b6fc18b7..93ab717c8ae 100644 --- a/scripts/mysqld_multi.sh +++ b/scripts/mysqld_multi.sh @@ -38,7 +38,7 @@ use Getopt::Long; use POSIX qw(strftime getcwd); $|=1; -$VER="2.16"; +$VER="2.20"; my @defaults_options; # Leading --no-defaults, --defaults-file, etc. @@ -138,6 +138,7 @@ sub main print "will be disabled\nand some will be enabled.\n\n"; } + init_log() if (!defined($opt_log)); $groupids = $ARGV[1]; if ($opt_version) { @@ -163,7 +164,6 @@ sub main !($ARGV[0] =~ m/^stop$/i) && !($ARGV[0] =~ m/^report$/i))); - init_log() if (!defined($opt_log)); if (!$opt_no_log) { w2log("$my_progname log file version $VER; run: ", @@ -218,6 +218,10 @@ sub quote_shell_word return $option; } +#### +#### get options for a group +#### + sub defaults_for_group { my ($group) = @_; diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh index 9d0dd0e68ac..4e7b098c8d8 100644 --- a/scripts/mysqld_safe.sh +++ b/scripts/mysqld_safe.sh @@ -189,6 +189,89 @@ shell_quote_string() { echo "$1" | sed -e 's,\([^a-zA-Z0-9/_.=-]\),\\\1,g' } +wsrep_pick_url() { + [ $# -eq 0 ] && return 0 + + log_error "WSREP: 'wsrep_urls' is DEPRECATED! Use wsrep_cluster_address to specify multiple addresses instead." + + if ! which nc >/dev/null; then + log_error "ERROR: nc tool not found in PATH! Make sure you have it installed." + return 1 + fi + + local url + # Assuming URL in the form scheme://host:port + # If host and port are not NULL, the liveness of URL is assumed to be tested + # If port part is absent, the url is returned literally and unconditionally + # If every URL has port but none is reachable, nothing is returned + for url in `echo $@ | sed s/,/\ /g` 0; do + local host=`echo $url | cut -d \: -f 2 | sed s/^\\\/\\\///` + local port=`echo $url | cut -d \: -f 3` + [ -z "$port" ] && break + nc -z "$host" $port >/dev/null && break + done + + if [ "$url" == "0" ]; then + log_error "ERROR: none of the URLs in '$@' is reachable." + return 1 + fi + + echo $url +} + +# Run mysqld with --wsrep-recover and parse recovered position from log. +# Position will be stored in wsrep_start_position_opt global. +wsrep_start_position_opt="" +wsrep_recover_position() { + local mysqld_cmd="$@" + local euid=$(id -u) + local ret=0 + + local wr_logfile=$(mktemp $DATADIR/wsrep_recovery.XXXXXX) + + # safety checks + if [ -z $wr_logfile ]; then + log_error "WSREP: mktemp failed" + return 1 + fi + + if [ -f $wr_logfile ]; then + [ "$euid" = "0" ] && chown $user $wr_logfile + chmod 600 $wr_logfile + else + log_error "WSREP: mktemp failed" + return 1 + fi + + local wr_pidfile="$DATADIR/"`@HOSTNAME@`"-recover.pid" + + local wr_options="--log_error='$wr_logfile' --pid-file='$wr_pidfile'" + + log_notice "WSREP: Running position recovery with $wr_options" + + eval_log_error "$mysqld_cmd --wsrep_recover $wr_options" + + local rp="$(grep 'WSREP: Recovered position:' $wr_logfile)" + if [ -z "$rp" ]; then + local skipped="$(grep WSREP $wr_logfile | grep 'skipping position recovery')" + if [ -z "$skipped" ]; then + log_error "WSREP: Failed to recover position: '`cat $wr_logfile`'" + ret=1 + else + log_notice "WSREP: Position recovery skipped" + fi + else + local start_pos="$(echo $rp | sed 's/.*WSREP\:\ Recovered\ position://' \ + | sed 's/^[ \t]*//')" + log_notice "WSREP: Recovered position $start_pos" + wsrep_start_position_opt="--wsrep_start_position=$start_pos" + fi + + [ $ret -eq 0 ] && rm $wr_logfile + + return $ret +} + parse_arguments() { # We only need to pass arguments through to the server if we don't # handle them here. So, we collect unrecognized options (passed on @@ -245,6 +328,14 @@ parse_arguments() { --timezone=*) TZ="$val"; export TZ; ;; --flush[-_]caches) flush_caches=1 ;; --numa[-_]interleave) numa_interleave=1 ;; + --wsrep[-_]urls=*) wsrep_urls="$val"; ;; + --wsrep[-_]provider=*) + if test -n "$val" && test "$val" != "none" + then + wsrep_restart=1 + fi + append_arg_to_args "$arg" + ;; --help) usage ;; @@ -860,13 +951,28 @@ max_fast_restarts=5 # flag whether a usable sleep command exists have_sleep=1 +# maximum number of wsrep restarts +max_wsrep_restarts=0 + while true do rm -f "$pid_file" # Some extra safety start_time=`date +%M%S` - eval_log_error "$cmd" + # this sets wsrep_start_position_opt + wsrep_recover_position "$cmd" + + [ $? -ne 0 ] && exit 1 # + + [ -n "$wsrep_urls" ] && url=`wsrep_pick_url $wsrep_urls` # check connect address + + if [ -z "$url" ] + then + eval_log_error "$cmd $wsrep_start_position_opt $nohup_redir" + else + eval_log_error "$cmd $wsrep_start_position_opt --wsrep_cluster_address=$url $nohup_redir" + fi if [ $want_syslog -eq 0 -a ! -f "$err_log" ]; then touch "$err_log" # hypothetical: log was renamed but not @@ -936,6 +1042,20 @@ do I=`expr $I + 1` done fi + + if [ -n "$wsrep_restart" ] + then + if [ $wsrep_restart -le $max_wsrep_restarts ] + then + wsrep_restart=`expr $wsrep_restart + 1` + log_notice "WSREP: sleeping 15 seconds before restart" + sleep 15 + else + log_notice "WSREP: not restarting wsrep node automatically" + break + fi + fi + log_notice "mysqld restarted" if test -n "$CRASH_SCRIPT" then diff --git a/scripts/wsrep_sst_common b/scripts/wsrep_sst_common new file mode 100755 index 00000000000..88f5d80f53a --- /dev/null +++ b/scripts/wsrep_sst_common @@ -0,0 +1,157 @@ +# Copyright (C) 2012-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 +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1301 USA. + +# This is a common command line parser to be sourced by other SST scripts + +set -u + +WSREP_SST_OPT_BYPASS=0 +WSREP_SST_OPT_BINLOG="" +WSREP_SST_OPT_DATA="" +WSREP_SST_OPT_AUTH="" + +while [ $# -gt 0 ]; do +case "$1" in + '--address') + readonly WSREP_SST_OPT_ADDR="$2" + shift + ;; + '--auth') + WSREP_SST_OPT_AUTH="$2" + shift + ;; + '--bypass') + WSREP_SST_OPT_BYPASS=1 + ;; + '--datadir') + readonly WSREP_SST_OPT_DATA="$2" + shift + ;; + '--defaults-file') + readonly WSREP_SST_OPT_CONF="$2" + shift + ;; + '--host') + readonly WSREP_SST_OPT_HOST="$2" + shift + ;; + '--local-port') + readonly WSREP_SST_OPT_LPORT="$2" + shift + ;; + '--parent') + readonly WSREP_SST_OPT_PARENT="$2" + shift + ;; + '--password') + WSREP_SST_OPT_PSWD="$2" + shift + ;; + '--port') + readonly WSREP_SST_OPT_PORT="$2" + shift + ;; + '--role') + readonly WSREP_SST_OPT_ROLE="$2" + shift + ;; + '--socket') + readonly WSREP_SST_OPT_SOCKET="$2" + shift + ;; + '--user') + WSREP_SST_OPT_USER="$2" + shift + ;; + '--gtid') + readonly WSREP_SST_OPT_GTID="$2" + shift + ;; + '--binlog') + WSREP_SST_OPT_BINLOG="$2" + shift + ;; + *) # must be command + # usage + # exit 1 + ;; +esac +shift +done +readonly WSREP_SST_OPT_BYPASS +readonly WSREP_SST_OPT_BINLOG + +# State Snapshot Transfer authentication password was displayed in the ps output. Bug fixed #1200727. +if my_print_defaults -c $WSREP_SST_OPT_CONF sst | grep -q "wsrep_sst_auth";then + if [ -z "$WSREP_SST_OPT_AUTH" -o "$WSREP_SST_OPT_AUTH" = "(null)" ];then + WSREP_SST_OPT_AUTH=$(my_print_defaults -c $WSREP_SST_OPT_CONF sst | grep -- "--wsrep_sst_auth" | cut -d= -f2) + fi +fi + +if [ -n "${WSREP_SST_OPT_DATA:-}" ] +then + SST_PROGRESS_FILE="$WSREP_SST_OPT_DATA/sst_in_progress" +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 "$tst WSREP_SST: " >&2 +} + +wsrep_log_error() +{ + wsrep_log "[ERROR] $*" +} + +wsrep_log_info() +{ + wsrep_log "[INFO] $*" +} + +wsrep_cleanup_progress_file() +{ + [ -n "$SST_PROGRESS_FILE" ] && rm -f "$SST_PROGRESS_FILE" 2>/dev/null +} + +wsrep_check_program() +{ + local prog=$1 + + if ! which $prog >/dev/null + then + echo "'$prog' not found in PATH" + return 2 # no such file or directory + fi +} + +wsrep_check_programs() +{ + local ret=0 + + while [ $# -gt 0 ] + do + wsrep_check_program $1 || ret=$? + shift + done + + return $ret +} diff --git a/scripts/wsrep_sst_common.sh b/scripts/wsrep_sst_common.sh new file mode 100644 index 00000000000..88f5d80f53a --- /dev/null +++ b/scripts/wsrep_sst_common.sh @@ -0,0 +1,157 @@ +# Copyright (C) 2012-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 +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1301 USA. + +# This is a common command line parser to be sourced by other SST scripts + +set -u + +WSREP_SST_OPT_BYPASS=0 +WSREP_SST_OPT_BINLOG="" +WSREP_SST_OPT_DATA="" +WSREP_SST_OPT_AUTH="" + +while [ $# -gt 0 ]; do +case "$1" in + '--address') + readonly WSREP_SST_OPT_ADDR="$2" + shift + ;; + '--auth') + WSREP_SST_OPT_AUTH="$2" + shift + ;; + '--bypass') + WSREP_SST_OPT_BYPASS=1 + ;; + '--datadir') + readonly WSREP_SST_OPT_DATA="$2" + shift + ;; + '--defaults-file') + readonly WSREP_SST_OPT_CONF="$2" + shift + ;; + '--host') + readonly WSREP_SST_OPT_HOST="$2" + shift + ;; + '--local-port') + readonly WSREP_SST_OPT_LPORT="$2" + shift + ;; + '--parent') + readonly WSREP_SST_OPT_PARENT="$2" + shift + ;; + '--password') + WSREP_SST_OPT_PSWD="$2" + shift + ;; + '--port') + readonly WSREP_SST_OPT_PORT="$2" + shift + ;; + '--role') + readonly WSREP_SST_OPT_ROLE="$2" + shift + ;; + '--socket') + readonly WSREP_SST_OPT_SOCKET="$2" + shift + ;; + '--user') + WSREP_SST_OPT_USER="$2" + shift + ;; + '--gtid') + readonly WSREP_SST_OPT_GTID="$2" + shift + ;; + '--binlog') + WSREP_SST_OPT_BINLOG="$2" + shift + ;; + *) # must be command + # usage + # exit 1 + ;; +esac +shift +done +readonly WSREP_SST_OPT_BYPASS +readonly WSREP_SST_OPT_BINLOG + +# State Snapshot Transfer authentication password was displayed in the ps output. Bug fixed #1200727. +if my_print_defaults -c $WSREP_SST_OPT_CONF sst | grep -q "wsrep_sst_auth";then + if [ -z "$WSREP_SST_OPT_AUTH" -o "$WSREP_SST_OPT_AUTH" = "(null)" ];then + WSREP_SST_OPT_AUTH=$(my_print_defaults -c $WSREP_SST_OPT_CONF sst | grep -- "--wsrep_sst_auth" | cut -d= -f2) + fi +fi + +if [ -n "${WSREP_SST_OPT_DATA:-}" ] +then + SST_PROGRESS_FILE="$WSREP_SST_OPT_DATA/sst_in_progress" +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 "$tst WSREP_SST: " >&2 +} + +wsrep_log_error() +{ + wsrep_log "[ERROR] $*" +} + +wsrep_log_info() +{ + wsrep_log "[INFO] $*" +} + +wsrep_cleanup_progress_file() +{ + [ -n "$SST_PROGRESS_FILE" ] && rm -f "$SST_PROGRESS_FILE" 2>/dev/null +} + +wsrep_check_program() +{ + local prog=$1 + + if ! which $prog >/dev/null + then + echo "'$prog' not found in PATH" + return 2 # no such file or directory + fi +} + +wsrep_check_programs() +{ + local ret=0 + + while [ $# -gt 0 ] + do + wsrep_check_program $1 || ret=$? + shift + done + + return $ret +} diff --git a/scripts/wsrep_sst_mysqldump b/scripts/wsrep_sst_mysqldump new file mode 100755 index 00000000000..d4093dbcaef --- /dev/null +++ b/scripts/wsrep_sst_mysqldump @@ -0,0 +1,131 @@ +#!/bin/bash -e +# Copyright (C) 2009 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 +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1301 USA. + +# This is a reference script for mysqldump-based state snapshot tansfer + +# This variable is not used in mysqldump sst, so better initialize it +# to avoid shell's "parameter not set" message. +WSREP_SST_OPT_CONF="" + +. $(dirname $0)/wsrep_sst_common + +EINVAL=22 +PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin + +local_ip() +{ + [ "$1" = "127.0.0.1" ] && return 0 + [ "$1" = "localhost" ] && return 0 + [ "$1" = "$(hostname -s)" ] && return 0 + [ "$1" = "$(hostname -f)" ] && return 0 + [ "$1" = "$(hostname -d)" ] && return 0 + + # Now if ip program is not found in the path, we can't return 0 since + # it would block any address. Thankfully grep should fail in this case + ip route get "$1" | grep local >/dev/null && return 0 + + return 1 +} + +if test -z "$WSREP_SST_OPT_USER"; then wsrep_log_error "USER cannot be nil"; exit $EINVAL; fi +if test -z "$WSREP_SST_OPT_HOST"; then wsrep_log_error "HOST cannot be nil"; exit $EINVAL; fi +if test -z "$WSREP_SST_OPT_PORT"; then wsrep_log_error "PORT cannot be nil"; exit $EINVAL; fi +if test -z "$WSREP_SST_OPT_LPORT"; then wsrep_log_error "LPORT cannot be nil"; exit $EINVAL; fi +if test -z "$WSREP_SST_OPT_SOCKET";then wsrep_log_error "SOCKET cannot be nil";exit $EINVAL; fi +if test -z "$WSREP_SST_OPT_GTID"; then wsrep_log_error "GTID cannot be nil"; exit $EINVAL; fi + +if local_ip $WSREP_SST_OPT_HOST && \ + [ "$WSREP_SST_OPT_PORT" = "$WSREP_SST_OPT_LPORT" ] +then + wsrep_log_error \ + "destination address '$WSREP_SST_OPT_HOST:$WSREP_SST_OPT_PORT' matches source address." + exit $EINVAL +fi + +# Check client version +if ! mysql --version | grep 'Distrib 10' >/dev/null +then + mysql --version >&2 + wsrep_log_error "this operation requires MySQL client version 10 or newer" + exit $EINVAL +fi + +# For Bug:1293798 +if [ -z "$WSREP_SST_OPT_PSWD" -a -n "$WSREP_SST_OPT_AUTH" ]; then + WSREP_SST_OPT_USER=$(echo $WSREP_SST_OPT_AUTH | cut -d: -f1) + WSREP_SST_OPT_PSWD=$(echo $WSREP_SST_OPT_AUTH | cut -d: -f2) +fi +AUTH="-u$WSREP_SST_OPT_USER" +if test -n "$WSREP_SST_OPT_PSWD"; then AUTH="$AUTH -p$WSREP_SST_OPT_PSWD"; fi + +STOP_WSREP="SET wsrep_on=OFF;" + +# NOTE: we don't use --routines here because we're dumping mysql.proc table +MYSQLDUMP="mysqldump $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" + +# mysqldump cannot restore CSV tables, fix this issue +CSV_TABLES_FIX=" +set sql_mode=''; + +USE mysql; + +SET @cond = (SELECT (SUPPORT = 'YES' or SUPPORT = 'DEFAULT') FROM INFORMATION_SCHEMA.ENGINES WHERE ENGINE = 'csv'); + +SET @stmt = IF (@cond = '1', 'CREATE TABLE IF NOT EXISTS general_log ( event_time timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), user_host mediumtext NOT NULL, thread_id bigint(21) unsigned NOT NULL, server_id int(10) unsigned NOT NULL, command_type varchar(64) NOT NULL, argument mediumtext NOT NULL) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT=\"General log\"', 'SET @dummy = 0'); + +PREPARE stmt FROM @stmt; +EXECUTE stmt; +DROP PREPARE stmt; + +SET @stmt = IF (@cond = '1', 'CREATE TABLE IF NOT EXISTS slow_log ( start_time timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), user_host mediumtext NOT NULL, query_time time(6) NOT NULL, lock_time time(6) NOT NULL, rows_sent int(11) NOT NULL, rows_examined int(11) NOT NULL, db varchar(512) NOT NULL, last_insert_id int(11) NOT NULL, insert_id int(11) NOT NULL, server_id int(10) unsigned NOT NULL, sql_text mediumtext NOT NULL, thread_id bigint(21) unsigned NOT NULL) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT=\"Slow log\"', 'SET @dummy = 0'); + +PREPARE stmt FROM @stmt; +EXECUTE stmt; +DROP PREPARE stmt;" + +SET_START_POSITION="SET GLOBAL wsrep_start_position='$WSREP_SST_OPT_GTID';" + +MYSQL="mysql $AUTH -h$WSREP_SST_OPT_HOST -P$WSREP_SST_OPT_PORT "\ +"--disable-reconnect --connect_timeout=10" + +# need to disable logging when loading the dump +# reason is that dump contains ALTER TABLE for log tables, and +# this causes an error if logging is enabled +GENERAL_LOG_OPT=`$MYSQL --skip-column-names -e"$STOP_WSREP SELECT @@GENERAL_LOG"` +SLOW_LOG_OPT=`$MYSQL --skip-column-names -e"$STOP_WSREP SELECT @@SLOW_QUERY_LOG"` +$MYSQL -e"$STOP_WSREP SET GLOBAL GENERAL_LOG=OFF" +$MYSQL -e"$STOP_WSREP SET GLOBAL SLOW_QUERY_LOG=OFF" + +# commands to restore log settings +RESTORE_GENERAL_LOG="SET GLOBAL GENERAL_LOG=$GENERAL_LOG_OPT;" +RESTORE_SLOW_QUERY_LOG="SET GLOBAL SLOW_QUERY_LOG=$SLOW_LOG_OPT;" + +if [ $WSREP_SST_OPT_BYPASS -eq 0 ] +then + (echo $STOP_WSREP && $MYSQLDUMP && echo $CSV_TABLES_FIX \ + && echo $RESTORE_GENERAL_LOG && echo $RESTORE_SLOW_QUERY_LOG \ + && echo $SET_START_POSITION \ + || echo "SST failed to complete;") | $MYSQL +else + wsrep_log_info "Bypassing state dump." + echo $SET_START_POSITION | $MYSQL +fi + +# diff --git a/scripts/wsrep_sst_mysqldump.sh b/scripts/wsrep_sst_mysqldump.sh new file mode 100644 index 00000000000..d4093dbcaef --- /dev/null +++ b/scripts/wsrep_sst_mysqldump.sh @@ -0,0 +1,131 @@ +#!/bin/bash -e +# Copyright (C) 2009 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 +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1301 USA. + +# This is a reference script for mysqldump-based state snapshot tansfer + +# This variable is not used in mysqldump sst, so better initialize it +# to avoid shell's "parameter not set" message. +WSREP_SST_OPT_CONF="" + +. $(dirname $0)/wsrep_sst_common + +EINVAL=22 +PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin + +local_ip() +{ + [ "$1" = "127.0.0.1" ] && return 0 + [ "$1" = "localhost" ] && return 0 + [ "$1" = "$(hostname -s)" ] && return 0 + [ "$1" = "$(hostname -f)" ] && return 0 + [ "$1" = "$(hostname -d)" ] && return 0 + + # Now if ip program is not found in the path, we can't return 0 since + # it would block any address. Thankfully grep should fail in this case + ip route get "$1" | grep local >/dev/null && return 0 + + return 1 +} + +if test -z "$WSREP_SST_OPT_USER"; then wsrep_log_error "USER cannot be nil"; exit $EINVAL; fi +if test -z "$WSREP_SST_OPT_HOST"; then wsrep_log_error "HOST cannot be nil"; exit $EINVAL; fi +if test -z "$WSREP_SST_OPT_PORT"; then wsrep_log_error "PORT cannot be nil"; exit $EINVAL; fi +if test -z "$WSREP_SST_OPT_LPORT"; then wsrep_log_error "LPORT cannot be nil"; exit $EINVAL; fi +if test -z "$WSREP_SST_OPT_SOCKET";then wsrep_log_error "SOCKET cannot be nil";exit $EINVAL; fi +if test -z "$WSREP_SST_OPT_GTID"; then wsrep_log_error "GTID cannot be nil"; exit $EINVAL; fi + +if local_ip $WSREP_SST_OPT_HOST && \ + [ "$WSREP_SST_OPT_PORT" = "$WSREP_SST_OPT_LPORT" ] +then + wsrep_log_error \ + "destination address '$WSREP_SST_OPT_HOST:$WSREP_SST_OPT_PORT' matches source address." + exit $EINVAL +fi + +# Check client version +if ! mysql --version | grep 'Distrib 10' >/dev/null +then + mysql --version >&2 + wsrep_log_error "this operation requires MySQL client version 10 or newer" + exit $EINVAL +fi + +# For Bug:1293798 +if [ -z "$WSREP_SST_OPT_PSWD" -a -n "$WSREP_SST_OPT_AUTH" ]; then + WSREP_SST_OPT_USER=$(echo $WSREP_SST_OPT_AUTH | cut -d: -f1) + WSREP_SST_OPT_PSWD=$(echo $WSREP_SST_OPT_AUTH | cut -d: -f2) +fi +AUTH="-u$WSREP_SST_OPT_USER" +if test -n "$WSREP_SST_OPT_PSWD"; then AUTH="$AUTH -p$WSREP_SST_OPT_PSWD"; fi + +STOP_WSREP="SET wsrep_on=OFF;" + +# NOTE: we don't use --routines here because we're dumping mysql.proc table +MYSQLDUMP="mysqldump $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" + +# mysqldump cannot restore CSV tables, fix this issue +CSV_TABLES_FIX=" +set sql_mode=''; + +USE mysql; + +SET @cond = (SELECT (SUPPORT = 'YES' or SUPPORT = 'DEFAULT') FROM INFORMATION_SCHEMA.ENGINES WHERE ENGINE = 'csv'); + +SET @stmt = IF (@cond = '1', 'CREATE TABLE IF NOT EXISTS general_log ( event_time timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), user_host mediumtext NOT NULL, thread_id bigint(21) unsigned NOT NULL, server_id int(10) unsigned NOT NULL, command_type varchar(64) NOT NULL, argument mediumtext NOT NULL) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT=\"General log\"', 'SET @dummy = 0'); + +PREPARE stmt FROM @stmt; +EXECUTE stmt; +DROP PREPARE stmt; + +SET @stmt = IF (@cond = '1', 'CREATE TABLE IF NOT EXISTS slow_log ( start_time timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), user_host mediumtext NOT NULL, query_time time(6) NOT NULL, lock_time time(6) NOT NULL, rows_sent int(11) NOT NULL, rows_examined int(11) NOT NULL, db varchar(512) NOT NULL, last_insert_id int(11) NOT NULL, insert_id int(11) NOT NULL, server_id int(10) unsigned NOT NULL, sql_text mediumtext NOT NULL, thread_id bigint(21) unsigned NOT NULL) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT=\"Slow log\"', 'SET @dummy = 0'); + +PREPARE stmt FROM @stmt; +EXECUTE stmt; +DROP PREPARE stmt;" + +SET_START_POSITION="SET GLOBAL wsrep_start_position='$WSREP_SST_OPT_GTID';" + +MYSQL="mysql $AUTH -h$WSREP_SST_OPT_HOST -P$WSREP_SST_OPT_PORT "\ +"--disable-reconnect --connect_timeout=10" + +# need to disable logging when loading the dump +# reason is that dump contains ALTER TABLE for log tables, and +# this causes an error if logging is enabled +GENERAL_LOG_OPT=`$MYSQL --skip-column-names -e"$STOP_WSREP SELECT @@GENERAL_LOG"` +SLOW_LOG_OPT=`$MYSQL --skip-column-names -e"$STOP_WSREP SELECT @@SLOW_QUERY_LOG"` +$MYSQL -e"$STOP_WSREP SET GLOBAL GENERAL_LOG=OFF" +$MYSQL -e"$STOP_WSREP SET GLOBAL SLOW_QUERY_LOG=OFF" + +# commands to restore log settings +RESTORE_GENERAL_LOG="SET GLOBAL GENERAL_LOG=$GENERAL_LOG_OPT;" +RESTORE_SLOW_QUERY_LOG="SET GLOBAL SLOW_QUERY_LOG=$SLOW_LOG_OPT;" + +if [ $WSREP_SST_OPT_BYPASS -eq 0 ] +then + (echo $STOP_WSREP && $MYSQLDUMP && echo $CSV_TABLES_FIX \ + && echo $RESTORE_GENERAL_LOG && echo $RESTORE_SLOW_QUERY_LOG \ + && echo $SET_START_POSITION \ + || echo "SST failed to complete;") | $MYSQL +else + wsrep_log_info "Bypassing state dump." + echo $SET_START_POSITION | $MYSQL +fi + +# diff --git a/scripts/wsrep_sst_rsync b/scripts/wsrep_sst_rsync new file mode 100755 index 00000000000..86bf557662d --- /dev/null +++ b/scripts/wsrep_sst_rsync @@ -0,0 +1,335 @@ +#!/bin/bash -ue + +# 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 +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1301 USA. + +# This is a reference script for rsync-based state snapshot tansfer + +RSYNC_PID= +RSYNC_CONF= +OS=$(uname) +[ "$OS" == "Darwin" ] && export -n LD_LIBRARY_PATH + +# Setting the path for lsof on CentOS +export PATH="/usr/sbin:/sbin:$PATH" + +. $(dirname $0)/wsrep_sst_common + +wsrep_check_programs rsync + +cleanup_joiner() +{ + wsrep_log_info "Joiner cleanup." + local PID=$(cat "$RSYNC_PID" 2>/dev/null || echo 0) + [ "0" != "$PID" ] && kill $PID && sleep 0.5 && kill -9 $PID >/dev/null 2>&1 \ + || : + rm -rf "$RSYNC_CONF" + rm -rf "$MAGIC_FILE" + rm -rf "$RSYNC_PID" + wsrep_log_info "Joiner cleanup done." + if [ "${WSREP_SST_OPT_ROLE}" = "joiner" ];then + wsrep_cleanup_progress_file + fi +} + +check_pid() +{ + local pid_file=$1 + [ -r "$pid_file" ] && ps -p $(cat $pid_file) >/dev/null 2>&1 +} + +check_pid_and_port() +{ + local pid_file=$1 + local rsync_pid=$2 + local rsync_port=$3 + + if ! which lsof > /dev/null; then + wsrep_log_error "lsof tool not found in PATH! Make sure you have it installed." + exit 2 # ENOENT + fi + + local port_info=$(lsof -i :$rsync_port -Pn 2>/dev/null | \ + grep "(LISTEN)") + local is_rsync=$(echo $port_info | \ + grep -w '^rsync[[:space:]]\+'"$rsync_pid" 2>/dev/null) + + if [ -n "$port_info" -a -z "$is_rsync" ]; then + wsrep_log_error "rsync daemon port '$rsync_port' has been taken" + exit 16 # EBUSY + fi + check_pid $pid_file && \ + [ -n "$port_info" ] && [ -n "$is_rsync" ] && \ + [ $(cat $pid_file) -eq $rsync_pid ] +} + +MAGIC_FILE="$WSREP_SST_OPT_DATA/rsync_sst_complete" +rm -rf "$MAGIC_FILE" + +BINLOG_TAR_FILE="$WSREP_SST_OPT_DATA/wsrep_sst_binlog.tar" +BINLOG_N_FILES=1 +rm -f "$BINLOG_TAR_FILE" || : + +if ! [ -z $WSREP_SST_OPT_BINLOG ] +then + BINLOG_DIRNAME=$(dirname $WSREP_SST_OPT_BINLOG) + BINLOG_FILENAME=$(basename $WSREP_SST_OPT_BINLOG) +fi + +WSREP_LOG_DIR=${WSREP_LOG_DIR:-""} +# if WSREP_LOG_DIR env. variable is not set, try to get it from my.cnf +if [ -z "$WSREP_LOG_DIR" ]; then + SCRIPT_DIR="$(cd $(dirname "$0"); pwd -P)" + WSREP_LOG_DIR=$($SCRIPT_DIR/my_print_defaults --defaults-file \ + "$WSREP_SST_OPT_CONF" mysqld server mysqld-10.0 mariadb mariadb-10.0 \ + | grep -- '--innodb[-_]log[-_]group[-_]home[-_]dir=' \ + | cut -b 29- ) +fi + +if [ -n "$WSREP_LOG_DIR" ]; then + # handle both relative and absolute paths + WSREP_LOG_DIR=$(cd $WSREP_SST_OPT_DATA; mkdir -p "$WSREP_LOG_DIR"; cd $WSREP_LOG_DIR; pwd -P) +else + # default to datadir + WSREP_LOG_DIR=$(cd $WSREP_SST_OPT_DATA; pwd -P) +fi + +# Old filter - include everything except selected +# FILTER=(--exclude '*.err' --exclude '*.pid' --exclude '*.sock' \ +# --exclude '*.conf' --exclude core --exclude 'galera.*' \ +# --exclude grastate.txt --exclude '*.pem' \ +# --exclude '*.[0-9][0-9][0-9][0-9][0-9][0-9]' --exclude '*.index') + +# New filter - exclude everything except dirs (schemas) and innodb files +FILTER=(-f '- /lost+found' -f '- /.fseventsd' -f '- /.Trashes' + -f '+ /wsrep_sst_binlog.tar' -f '+ /ib_lru_dump' -f '+ /ibdata*' -f '+ /*/' -f '- /*') + +if [ "$WSREP_SST_OPT_ROLE" = "donor" ] +then + + if [ $WSREP_SST_OPT_BYPASS -eq 0 ] + then + + FLUSHED="$WSREP_SST_OPT_DATA/tables_flushed" + rm -rf "$FLUSHED" + + # Use deltaxfer only for WAN + inv=$(basename $0) + [ "$inv" = "wsrep_sst_rsync_wan" ] && WHOLE_FILE_OPT="" \ + || WHOLE_FILE_OPT="--whole-file" + + echo "flush tables" + + # wait for tables flushed and state ID written to the file + while [ ! -r "$FLUSHED" ] && ! grep -q ':' "$FLUSHED" >/dev/null 2>&1 + do + sleep 0.2 + done + + STATE="$(cat $FLUSHED)" + rm -rf "$FLUSHED" + + sync + + if ! [ -z $WSREP_SST_OPT_BINLOG ] + then + # Prepare binlog files + pushd $BINLOG_DIRNAME &> /dev/null + binlog_files_full=$(tail -n $BINLOG_N_FILES ${BINLOG_FILENAME}.index) + binlog_files="" + for ii in $binlog_files_full + do + binlog_files="$binlog_files $(basename $ii)" + done + if ! [ -z "$binlog_files" ] + then + wsrep_log_info "Preparing binlog files for transfer:" + tar -cvf $BINLOG_TAR_FILE $binlog_files >&2 + fi + popd &> /dev/null + fi + + # first, the normal directories, so that we can detect incompatible protocol + RC=0 + rsync --owner --group --perms --links --specials \ + --ignore-times --inplace --dirs --delete --quiet \ + $WHOLE_FILE_OPT "${FILTER[@]}" "$WSREP_SST_OPT_DATA/" \ + rsync://$WSREP_SST_OPT_ADDR >&2 || RC=$? + + if [ "$RC" -ne 0 ]; then + wsrep_log_error "rsync returned code $RC:" + + case $RC in + 12) RC=71 # EPROTO + wsrep_log_error \ + "rsync server on the other end has incompatible protocol. " \ + "Make sure you have the same version of rsync on all nodes." + ;; + 22) RC=12 # ENOMEM + ;; + *) RC=255 # unknown error + ;; + esac + exit $RC + fi + + # second, we transfer InnoDB log files + rsync --owner --group --perms --links --specials \ + --ignore-times --inplace --dirs --delete --quiet \ + $WHOLE_FILE_OPT -f '+ /ib_logfile[0-9]*' -f '- **' "$WSREP_LOG_DIR/" \ + rsync://$WSREP_SST_OPT_ADDR-log_dir >&2 || RC=$? + + if [ $RC -ne 0 ]; then + wsrep_log_error "rsync innodb_log_group_home_dir returned code $RC:" + exit 255 # unknown error + fi + + # then, we parallelize the transfer of database directories, use . so that pathconcatenation works + pushd "$WSREP_SST_OPT_DATA" >/dev/null + + count=1 + [ "$OS" == "Linux" ] && count=$(grep -c processor /proc/cpuinfo) + [ "$OS" == "Darwin" -o "$OS" == "FreeBSD" ] && count=$(sysctl -n hw.ncpu) + + find . -maxdepth 1 -mindepth 1 -type d -print0 | xargs -I{} -0 -P $count \ + rsync --owner --group --perms --links --specials \ + --ignore-times --inplace --recursive --delete --quiet \ + $WHOLE_FILE_OPT --exclude '*/ib_logfile*' "$WSREP_SST_OPT_DATA"/{}/ \ + rsync://$WSREP_SST_OPT_ADDR/{} >&2 || RC=$? + + popd >/dev/null + + if [ $RC -ne 0 ]; then + wsrep_log_error "find/rsync returned code $RC:" + exit 255 # unknown error + fi + + else # BYPASS + wsrep_log_info "Bypassing state dump." + STATE="$WSREP_SST_OPT_GTID" + fi + + echo "continue" # now server can resume updating data + + echo "$STATE" > "$MAGIC_FILE" + rsync --archive --quiet --checksum "$MAGIC_FILE" rsync://$WSREP_SST_OPT_ADDR + + echo "done $STATE" + +elif [ "$WSREP_SST_OPT_ROLE" = "joiner" ] +then + wsrep_check_programs lsof + + touch $SST_PROGRESS_FILE + MYSQLD_PID=$WSREP_SST_OPT_PARENT + + MODULE="rsync_sst" + + RSYNC_PID="$WSREP_SST_OPT_DATA/$MODULE.pid" + + if check_pid $RSYNC_PID + then + wsrep_log_error "rsync daemon already running." + exit 114 # EALREADY + fi + rm -rf "$RSYNC_PID" + + ADDR=$WSREP_SST_OPT_ADDR + RSYNC_PORT=$(echo $ADDR | awk -F ':' '{ print $2 }') + if [ -z "$RSYNC_PORT" ] + then + RSYNC_PORT=4444 + ADDR="$(echo $ADDR | awk -F ':' '{ print $1 }'):$RSYNC_PORT" + fi + + trap "exit 32" HUP PIPE + trap "exit 3" INT TERM ABRT + trap cleanup_joiner EXIT + + RSYNC_CONF="$WSREP_SST_OPT_DATA/$MODULE.conf" + +cat << EOF > "$RSYNC_CONF" +pid file = $RSYNC_PID +use chroot = no +read only = no +timeout = 300 +[$MODULE] + path = $WSREP_SST_OPT_DATA +[$MODULE-log_dir] + path = $WSREP_LOG_DIR +EOF + +# rm -rf "$DATA"/ib_logfile* # we don't want old logs around + + # listen at all interfaces (for firewalled setups) + rsync --daemon --no-detach --port $RSYNC_PORT --config "$RSYNC_CONF" & + RSYNC_REAL_PID=$! + + until check_pid_and_port $RSYNC_PID $RSYNC_REAL_PID $RSYNC_PORT + do + sleep 0.2 + done + + echo "ready $ADDR/$MODULE" + + # wait for SST to complete by monitoring magic file + while [ ! -r "$MAGIC_FILE" ] && check_pid "$RSYNC_PID" && \ + ps -p $MYSQLD_PID >/dev/null + do + sleep 1 + done + + if ! ps -p $MYSQLD_PID >/dev/null + then + wsrep_log_error \ + "Parent mysqld process (PID:$MYSQLD_PID) terminated unexpectedly." + exit 32 + fi + + if ! [ -z $WSREP_SST_OPT_BINLOG ] + then + + pushd $BINLOG_DIRNAME &> /dev/null + if [ -f $BINLOG_TAR_FILE ] + then + # Clean up old binlog files first + rm -f ${BINLOG_FILENAME}.* + wsrep_log_info "Extracting binlog files:" + tar -xvf $BINLOG_TAR_FILE >&2 + for ii in $(ls -1 ${BINLOG_FILENAME}.*) + do + echo ${BINLOG_DIRNAME}/${ii} >> ${BINLOG_FILENAME}.index + done + fi + popd &> /dev/null + fi + if [ -r "$MAGIC_FILE" ] + then + cat "$MAGIC_FILE" # output UUID:seqno + else + # this message should cause joiner to abort + echo "rsync process ended without creating '$MAGIC_FILE'" + fi + wsrep_cleanup_progress_file +# cleanup_joiner +else + wsrep_log_error "Unrecognized role: '$WSREP_SST_OPT_ROLE'" + exit 22 # EINVAL +fi + +rm -f $BINLOG_TAR_FILE || : + +exit 0 diff --git a/scripts/wsrep_sst_rsync.sh b/scripts/wsrep_sst_rsync.sh new file mode 100644 index 00000000000..86bf557662d --- /dev/null +++ b/scripts/wsrep_sst_rsync.sh @@ -0,0 +1,335 @@ +#!/bin/bash -ue + +# 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 +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1301 USA. + +# This is a reference script for rsync-based state snapshot tansfer + +RSYNC_PID= +RSYNC_CONF= +OS=$(uname) +[ "$OS" == "Darwin" ] && export -n LD_LIBRARY_PATH + +# Setting the path for lsof on CentOS +export PATH="/usr/sbin:/sbin:$PATH" + +. $(dirname $0)/wsrep_sst_common + +wsrep_check_programs rsync + +cleanup_joiner() +{ + wsrep_log_info "Joiner cleanup." + local PID=$(cat "$RSYNC_PID" 2>/dev/null || echo 0) + [ "0" != "$PID" ] && kill $PID && sleep 0.5 && kill -9 $PID >/dev/null 2>&1 \ + || : + rm -rf "$RSYNC_CONF" + rm -rf "$MAGIC_FILE" + rm -rf "$RSYNC_PID" + wsrep_log_info "Joiner cleanup done." + if [ "${WSREP_SST_OPT_ROLE}" = "joiner" ];then + wsrep_cleanup_progress_file + fi +} + +check_pid() +{ + local pid_file=$1 + [ -r "$pid_file" ] && ps -p $(cat $pid_file) >/dev/null 2>&1 +} + +check_pid_and_port() +{ + local pid_file=$1 + local rsync_pid=$2 + local rsync_port=$3 + + if ! which lsof > /dev/null; then + wsrep_log_error "lsof tool not found in PATH! Make sure you have it installed." + exit 2 # ENOENT + fi + + local port_info=$(lsof -i :$rsync_port -Pn 2>/dev/null | \ + grep "(LISTEN)") + local is_rsync=$(echo $port_info | \ + grep -w '^rsync[[:space:]]\+'"$rsync_pid" 2>/dev/null) + + if [ -n "$port_info" -a -z "$is_rsync" ]; then + wsrep_log_error "rsync daemon port '$rsync_port' has been taken" + exit 16 # EBUSY + fi + check_pid $pid_file && \ + [ -n "$port_info" ] && [ -n "$is_rsync" ] && \ + [ $(cat $pid_file) -eq $rsync_pid ] +} + +MAGIC_FILE="$WSREP_SST_OPT_DATA/rsync_sst_complete" +rm -rf "$MAGIC_FILE" + +BINLOG_TAR_FILE="$WSREP_SST_OPT_DATA/wsrep_sst_binlog.tar" +BINLOG_N_FILES=1 +rm -f "$BINLOG_TAR_FILE" || : + +if ! [ -z $WSREP_SST_OPT_BINLOG ] +then + BINLOG_DIRNAME=$(dirname $WSREP_SST_OPT_BINLOG) + BINLOG_FILENAME=$(basename $WSREP_SST_OPT_BINLOG) +fi + +WSREP_LOG_DIR=${WSREP_LOG_DIR:-""} +# if WSREP_LOG_DIR env. variable is not set, try to get it from my.cnf +if [ -z "$WSREP_LOG_DIR" ]; then + SCRIPT_DIR="$(cd $(dirname "$0"); pwd -P)" + WSREP_LOG_DIR=$($SCRIPT_DIR/my_print_defaults --defaults-file \ + "$WSREP_SST_OPT_CONF" mysqld server mysqld-10.0 mariadb mariadb-10.0 \ + | grep -- '--innodb[-_]log[-_]group[-_]home[-_]dir=' \ + | cut -b 29- ) +fi + +if [ -n "$WSREP_LOG_DIR" ]; then + # handle both relative and absolute paths + WSREP_LOG_DIR=$(cd $WSREP_SST_OPT_DATA; mkdir -p "$WSREP_LOG_DIR"; cd $WSREP_LOG_DIR; pwd -P) +else + # default to datadir + WSREP_LOG_DIR=$(cd $WSREP_SST_OPT_DATA; pwd -P) +fi + +# Old filter - include everything except selected +# FILTER=(--exclude '*.err' --exclude '*.pid' --exclude '*.sock' \ +# --exclude '*.conf' --exclude core --exclude 'galera.*' \ +# --exclude grastate.txt --exclude '*.pem' \ +# --exclude '*.[0-9][0-9][0-9][0-9][0-9][0-9]' --exclude '*.index') + +# New filter - exclude everything except dirs (schemas) and innodb files +FILTER=(-f '- /lost+found' -f '- /.fseventsd' -f '- /.Trashes' + -f '+ /wsrep_sst_binlog.tar' -f '+ /ib_lru_dump' -f '+ /ibdata*' -f '+ /*/' -f '- /*') + +if [ "$WSREP_SST_OPT_ROLE" = "donor" ] +then + + if [ $WSREP_SST_OPT_BYPASS -eq 0 ] + then + + FLUSHED="$WSREP_SST_OPT_DATA/tables_flushed" + rm -rf "$FLUSHED" + + # Use deltaxfer only for WAN + inv=$(basename $0) + [ "$inv" = "wsrep_sst_rsync_wan" ] && WHOLE_FILE_OPT="" \ + || WHOLE_FILE_OPT="--whole-file" + + echo "flush tables" + + # wait for tables flushed and state ID written to the file + while [ ! -r "$FLUSHED" ] && ! grep -q ':' "$FLUSHED" >/dev/null 2>&1 + do + sleep 0.2 + done + + STATE="$(cat $FLUSHED)" + rm -rf "$FLUSHED" + + sync + + if ! [ -z $WSREP_SST_OPT_BINLOG ] + then + # Prepare binlog files + pushd $BINLOG_DIRNAME &> /dev/null + binlog_files_full=$(tail -n $BINLOG_N_FILES ${BINLOG_FILENAME}.index) + binlog_files="" + for ii in $binlog_files_full + do + binlog_files="$binlog_files $(basename $ii)" + done + if ! [ -z "$binlog_files" ] + then + wsrep_log_info "Preparing binlog files for transfer:" + tar -cvf $BINLOG_TAR_FILE $binlog_files >&2 + fi + popd &> /dev/null + fi + + # first, the normal directories, so that we can detect incompatible protocol + RC=0 + rsync --owner --group --perms --links --specials \ + --ignore-times --inplace --dirs --delete --quiet \ + $WHOLE_FILE_OPT "${FILTER[@]}" "$WSREP_SST_OPT_DATA/" \ + rsync://$WSREP_SST_OPT_ADDR >&2 || RC=$? + + if [ "$RC" -ne 0 ]; then + wsrep_log_error "rsync returned code $RC:" + + case $RC in + 12) RC=71 # EPROTO + wsrep_log_error \ + "rsync server on the other end has incompatible protocol. " \ + "Make sure you have the same version of rsync on all nodes." + ;; + 22) RC=12 # ENOMEM + ;; + *) RC=255 # unknown error + ;; + esac + exit $RC + fi + + # second, we transfer InnoDB log files + rsync --owner --group --perms --links --specials \ + --ignore-times --inplace --dirs --delete --quiet \ + $WHOLE_FILE_OPT -f '+ /ib_logfile[0-9]*' -f '- **' "$WSREP_LOG_DIR/" \ + rsync://$WSREP_SST_OPT_ADDR-log_dir >&2 || RC=$? + + if [ $RC -ne 0 ]; then + wsrep_log_error "rsync innodb_log_group_home_dir returned code $RC:" + exit 255 # unknown error + fi + + # then, we parallelize the transfer of database directories, use . so that pathconcatenation works + pushd "$WSREP_SST_OPT_DATA" >/dev/null + + count=1 + [ "$OS" == "Linux" ] && count=$(grep -c processor /proc/cpuinfo) + [ "$OS" == "Darwin" -o "$OS" == "FreeBSD" ] && count=$(sysctl -n hw.ncpu) + + find . -maxdepth 1 -mindepth 1 -type d -print0 | xargs -I{} -0 -P $count \ + rsync --owner --group --perms --links --specials \ + --ignore-times --inplace --recursive --delete --quiet \ + $WHOLE_FILE_OPT --exclude '*/ib_logfile*' "$WSREP_SST_OPT_DATA"/{}/ \ + rsync://$WSREP_SST_OPT_ADDR/{} >&2 || RC=$? + + popd >/dev/null + + if [ $RC -ne 0 ]; then + wsrep_log_error "find/rsync returned code $RC:" + exit 255 # unknown error + fi + + else # BYPASS + wsrep_log_info "Bypassing state dump." + STATE="$WSREP_SST_OPT_GTID" + fi + + echo "continue" # now server can resume updating data + + echo "$STATE" > "$MAGIC_FILE" + rsync --archive --quiet --checksum "$MAGIC_FILE" rsync://$WSREP_SST_OPT_ADDR + + echo "done $STATE" + +elif [ "$WSREP_SST_OPT_ROLE" = "joiner" ] +then + wsrep_check_programs lsof + + touch $SST_PROGRESS_FILE + MYSQLD_PID=$WSREP_SST_OPT_PARENT + + MODULE="rsync_sst" + + RSYNC_PID="$WSREP_SST_OPT_DATA/$MODULE.pid" + + if check_pid $RSYNC_PID + then + wsrep_log_error "rsync daemon already running." + exit 114 # EALREADY + fi + rm -rf "$RSYNC_PID" + + ADDR=$WSREP_SST_OPT_ADDR + RSYNC_PORT=$(echo $ADDR | awk -F ':' '{ print $2 }') + if [ -z "$RSYNC_PORT" ] + then + RSYNC_PORT=4444 + ADDR="$(echo $ADDR | awk -F ':' '{ print $1 }'):$RSYNC_PORT" + fi + + trap "exit 32" HUP PIPE + trap "exit 3" INT TERM ABRT + trap cleanup_joiner EXIT + + RSYNC_CONF="$WSREP_SST_OPT_DATA/$MODULE.conf" + +cat << EOF > "$RSYNC_CONF" +pid file = $RSYNC_PID +use chroot = no +read only = no +timeout = 300 +[$MODULE] + path = $WSREP_SST_OPT_DATA +[$MODULE-log_dir] + path = $WSREP_LOG_DIR +EOF + +# rm -rf "$DATA"/ib_logfile* # we don't want old logs around + + # listen at all interfaces (for firewalled setups) + rsync --daemon --no-detach --port $RSYNC_PORT --config "$RSYNC_CONF" & + RSYNC_REAL_PID=$! + + until check_pid_and_port $RSYNC_PID $RSYNC_REAL_PID $RSYNC_PORT + do + sleep 0.2 + done + + echo "ready $ADDR/$MODULE" + + # wait for SST to complete by monitoring magic file + while [ ! -r "$MAGIC_FILE" ] && check_pid "$RSYNC_PID" && \ + ps -p $MYSQLD_PID >/dev/null + do + sleep 1 + done + + if ! ps -p $MYSQLD_PID >/dev/null + then + wsrep_log_error \ + "Parent mysqld process (PID:$MYSQLD_PID) terminated unexpectedly." + exit 32 + fi + + if ! [ -z $WSREP_SST_OPT_BINLOG ] + then + + pushd $BINLOG_DIRNAME &> /dev/null + if [ -f $BINLOG_TAR_FILE ] + then + # Clean up old binlog files first + rm -f ${BINLOG_FILENAME}.* + wsrep_log_info "Extracting binlog files:" + tar -xvf $BINLOG_TAR_FILE >&2 + for ii in $(ls -1 ${BINLOG_FILENAME}.*) + do + echo ${BINLOG_DIRNAME}/${ii} >> ${BINLOG_FILENAME}.index + done + fi + popd &> /dev/null + fi + if [ -r "$MAGIC_FILE" ] + then + cat "$MAGIC_FILE" # output UUID:seqno + else + # this message should cause joiner to abort + echo "rsync process ended without creating '$MAGIC_FILE'" + fi + wsrep_cleanup_progress_file +# cleanup_joiner +else + wsrep_log_error "Unrecognized role: '$WSREP_SST_OPT_ROLE'" + exit 22 # EINVAL +fi + +rm -f $BINLOG_TAR_FILE || : + +exit 0 diff --git a/scripts/wsrep_sst_xtrabackup b/scripts/wsrep_sst_xtrabackup new file mode 100755 index 00000000000..6b33eabee23 --- /dev/null +++ b/scripts/wsrep_sst_xtrabackup @@ -0,0 +1,715 @@ +#!/bin/bash -ue +# Copyright (C) 2013 Percona Inc +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1301 USA. + +# Optional dependencies and options documented here: http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html +# Make sure to read that before proceeding! + + + + +. $(dirname $0)/wsrep_sst_common + +ealgo="" +ekey="" +ekeyfile="" +encrypt=0 +nproc=1 +ecode=0 +XTRABACKUP_PID="" +SST_PORT="" +REMOTEIP="" +tcert="" +tpem="" +sockopt="" +progress="" +ttime=0 +totime=0 +lsn="" +incremental=0 +ecmd="" +rlimit="" + +sfmt="tar" +strmcmd="" +tfmt="" +tcmd="" +rebuild=0 +rebuildcmd="" +payload=0 +pvformat="-F '%N => Rate:%r Avg:%a Elapsed:%t %e Bytes: %b %p' " +pvopts="-f -i 10 -N $WSREP_SST_OPT_ROLE " +uextra=0 + +if which pv &>/dev/null && pv --help | grep -q FORMAT;then + pvopts+=$pvformat +fi +pcmd="pv $pvopts" +declare -a RC + +INNOBACKUPEX_BIN=innobackupex +readonly AUTH=(${WSREP_SST_OPT_AUTH//:/ }) +DATA="${WSREP_SST_OPT_DATA}" +INFO_FILE="xtrabackup_galera_info" +IST_FILE="xtrabackup_ist" +MAGIC_FILE="${DATA}/${INFO_FILE}" + +# Setting the path for ss and ip +export PATH="/usr/sbin:/sbin:$PATH" + +timeit(){ + local stage=$1 + shift + local cmd="$@" + local x1 x2 took extcode + + if [[ $ttime -eq 1 ]];then + x1=$(date +%s) + wsrep_log_info "Evaluating $cmd" + eval "$cmd" + extcode=$? + x2=$(date +%s) + took=$(( x2-x1 )) + wsrep_log_info "NOTE: $stage took $took seconds" + totime=$(( totime+took )) + else + wsrep_log_info "Evaluating $cmd" + eval "$cmd" + extcode=$? + fi + return $extcode +} + +get_keys() +{ + if [[ $encrypt -eq 2 ]];then + return + fi + + if [[ $encrypt -eq 0 ]];then + if my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -q encrypt;then + wsrep_log_error "Unexpected option combination. SST may fail. Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html " + fi + return + fi + + if [[ $sfmt == 'tar' ]];then + wsrep_log_info "NOTE: Xtrabackup-based encryption - encrypt=1 - cannot be enabled with tar format" + encrypt=0 + return + fi + + wsrep_log_info "Xtrabackup based encryption enabled in my.cnf - Supported only from Xtrabackup 2.1.4" + + if [[ -z $ealgo ]];then + wsrep_log_error "FATAL: Encryption algorithm empty from my.cnf, bailing out" + exit 3 + fi + + if [[ -z $ekey && ! -r $ekeyfile ]];then + wsrep_log_error "FATAL: Either key or keyfile must be readable" + exit 3 + fi + + if [[ -z $ekey ]];then + ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key-file=$ekeyfile" + else + ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key=$ekey" + fi + + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + ecmd+=" -d" + fi +} + +get_transfer() +{ + if [[ -z $SST_PORT ]];then + TSST_PORT=4444 + else + TSST_PORT=$SST_PORT + fi + + if [[ $tfmt == 'nc' ]];then + if [[ ! -x `which nc` ]];then + wsrep_log_error "nc(netcat) not found in path: $PATH" + exit 2 + fi + wsrep_log_info "Using netcat as streamer" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + tcmd="nc -dl ${TSST_PORT}" + else + tcmd="nc ${REMOTEIP} ${TSST_PORT}" + fi + else + tfmt='socat' + wsrep_log_info "Using socat as streamer" + if [[ ! -x `which socat` ]];then + wsrep_log_error "socat not found in path: $PATH" + exit 2 + fi + + if [[ $encrypt -eq 2 ]] && ! socat -V | grep -q OPENSSL;then + wsrep_log_info "NOTE: socat is not openssl enabled, falling back to plain transfer" + encrypt=0 + fi + + if [[ $encrypt -eq 2 ]];then + wsrep_log_info "Using openssl based encryption with socat" + if [[ -z $tpem || -z $tcert ]];then + wsrep_log_error "Both PEM and CRT files required" + exit 22 + fi + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + wsrep_log_info "Decrypting with PEM $tpem, CA: $tcert" + tcmd="socat -u openssl-listen:${TSST_PORT},reuseaddr,cert=$tpem,cafile=${tcert}${sockopt} stdio" + else + wsrep_log_info "Encrypting with PEM $tpem, CA: $tcert" + tcmd="socat -u stdio openssl-connect:${REMOTEIP}:${TSST_PORT},cert=$tpem,cafile=${tcert}${sockopt}" + 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 + fi + fi + +} + +parse_cnf() +{ + local group=$1 + local var=$2 + reval=$(my_print_defaults -c $WSREP_SST_OPT_CONF $group | awk -F= '{if ($1 ~ /_/) { gsub(/_/,"-",$1); print $1"="$2 } else { print $0 }}' | grep -- "--$var=" | cut -d= -f2-) + if [[ -z $reval ]];then + [[ -n $3 ]] && reval=$3 + fi + echo $reval +} + +get_footprint() +{ + pushd $WSREP_SST_OPT_DATA 1>/dev/null + payload=$(find . -regex '.*\.ibd$\|.*\.MYI$\|.*\.MYD$\|.*ibdata1$' -type f -print0 | xargs -0 du --block-size=1 -c | awk 'END { print $1 }') + if my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -q -- "--compress";then + # QuickLZ has around 50% compression ratio + # When compression/compaction used, the progress is only an approximate. + payload=$(( payload*1/2 )) + fi + popd 1>/dev/null + pcmd+=" -s $payload" + adjust_progress +} + +adjust_progress() +{ + if [[ -n $progress && $progress != '1' ]];then + if [[ -e $progress ]];then + pcmd+=" 2>>$progress" + else + pcmd+=" 2>$progress" + fi + elif [[ -z $progress && -n $rlimit ]];then + # When rlimit is non-zero + pcmd="pv -q" + fi + + if [[ -n $rlimit && "$WSREP_SST_OPT_ROLE" == "donor" ]];then + wsrep_log_info "Rate-limiting SST to $rlimit" + pcmd+=" -L \$rlimit" + fi +} + +read_cnf() +{ + sfmt=$(parse_cnf sst streamfmt "tar") + tfmt=$(parse_cnf sst transferfmt "socat") + tcert=$(parse_cnf sst tca "") + tpem=$(parse_cnf sst tcert "") + encrypt=$(parse_cnf sst encrypt 0) + sockopt=$(parse_cnf sst sockopt "") + progress=$(parse_cnf sst progress "") + rebuild=$(parse_cnf sst rebuild 0) + ttime=$(parse_cnf sst time 0) + incremental=$(parse_cnf sst incremental 0) + ealgo=$(parse_cnf xtrabackup encrypt "") + ekey=$(parse_cnf xtrabackup encrypt-key "") + ekeyfile=$(parse_cnf xtrabackup encrypt-key-file "") + + # Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html + if [[ -z $ealgo ]];then + ealgo=$(parse_cnf sst encrypt-algo "") + ekey=$(parse_cnf sst encrypt-key "") + ekeyfile=$(parse_cnf sst encrypt-key-file "") + fi + rlimit=$(parse_cnf sst rlimit "") + uextra=$(parse_cnf sst use_extra 0) +} + +get_stream() +{ + if [[ $sfmt == 'xbstream' ]];then + wsrep_log_info "Streaming with xbstream" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + strmcmd="xbstream -x" + else + strmcmd="xbstream -c \${INFO_FILE} \${IST_FILE}" + fi + else + sfmt="tar" + wsrep_log_info "Streaming with tar" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + strmcmd="tar xfi - --recursive-unlink -h" + else + strmcmd="tar cf - \${INFO_FILE} \${IST_FILE}" + fi + + fi +} + +get_proc() +{ + set +e + nproc=$(grep -c processor /proc/cpuinfo) + [[ -z $nproc || $nproc -eq 0 ]] && nproc=1 + set -e +} + +sig_joiner_cleanup() +{ + wsrep_log_error "Removing $MAGIC_FILE file due to signal" + 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" + fi + if [ "${WSREP_SST_OPT_ROLE}" = "joiner" ];then + wsrep_log_info "Removing the sst_in_progress file" + wsrep_cleanup_progress_file + fi + if [[ -n $progress && -p $progress ]];then + wsrep_log_info "Cleaning up fifo file $progress" + rm $progress + fi +} + +check_pid() +{ + local pid_file="$1" + [ -r "$pid_file" ] && ps -p $(cat "$pid_file") >/dev/null 2>&1 +} + +cleanup_donor() +{ + # Since this is invoked just after exit NNN + local estatus=$? + if [[ $estatus -ne 0 ]];then + wsrep_log_error "Cleanup after exit with status:$estatus" + fi + + if [[ -n $XTRABACKUP_PID ]];then + if check_pid $XTRABACKUP_PID + then + wsrep_log_error "xtrabackup process is still running. Killing... " + kill_xtrabackup + fi + + rm -f $XTRABACKUP_PID + fi + rm -f ${DATA}/${IST_FILE} + + if [[ -n $progress && -p $progress ]];then + wsrep_log_info "Cleaning up fifo file $progress" + rm $progress + fi +} + +kill_xtrabackup() +{ + local PID=$(cat $XTRABACKUP_PID) + [ -n "$PID" -a "0" != "$PID" ] && kill $PID && (kill $PID && kill -9 $PID) || : + rm -f "$XTRABACKUP_PID" +} + +setup_ports() +{ + if [[ "$WSREP_SST_OPT_ROLE" == "donor" ]];then + SST_PORT=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $2 }') + REMOTEIP=$(echo $WSREP_SST_OPT_ADDR | awk -F ':' '{ print $1 }') + lsn=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $4 }') + else + SST_PORT=$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $2 }') + fi +} + +# waits ~10 seconds for 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 + ss -p state listening "( sport = :$PORT )" | grep -qE 'socat|nc' && break + sleep 0.2 + done + if [[ $incremental -eq 1 ]];then + echo "ready ${ADDR}/${MODULE}/$lsn" + else + echo "ready ${ADDR}/${MODULE}" + fi +} + +check_extra() +{ + local use_socket=1 + if [[ $uextra -eq 1 ]];then + if my_print_defaults -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--thread-handling=" | grep -q 'pool-of-threads';then + local eport=$(my_print_defaults -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--extra-port=" | cut -d= -f2) + if [[ -n $eport ]];then + # Xtrabackup works only locally. + # Hence, setting host to 127.0.0.1 unconditionally. + wsrep_log_info "SST through extra_port $eport" + INNOEXTRA+=" --host=127.0.0.1 --port=$eport " + use_socket=0 + else + wsrep_log_error "Extra port $eport null, failing" + exit 1 + fi + else + wsrep_log_info "Thread pool not set, ignore the option use_extra" + fi + fi + if [[ $use_socket -eq 1 ]] && [[ -n "${WSREP_SST_OPT_SOCKET}" ]];then + INNOEXTRA+=" --socket=${WSREP_SST_OPT_SOCKET}" + fi +} + +if [[ ! -x `which innobackupex` ]];then + wsrep_log_error "innobackupex not in path: $PATH" + exit 2 +fi + +rm -f "${MAGIC_FILE}" + +if [[ ! ${WSREP_SST_OPT_ROLE} == 'joiner' && ! ${WSREP_SST_OPT_ROLE} == 'donor' ]];then + wsrep_log_error "Invalid role ${WSREP_SST_OPT_ROLE}" + exit 22 +fi + +read_cnf +setup_ports +get_stream +get_transfer + +INNOEXTRA="" +INNOAPPLY="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} --apply-log \$rebuildcmd \${DATA} &>\${DATA}/innobackup.prepare.log" +INNOBACKUP="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} \$INNOEXTRA --galera-info --stream=\$sfmt \${TMPDIR} 2>\${DATA}/innobackup.backup.log" + +if [ "$WSREP_SST_OPT_ROLE" = "donor" ] +then + trap cleanup_donor EXIT + + if [ $WSREP_SST_OPT_BYPASS -eq 0 ] + then + TMPDIR="${TMPDIR:-/tmp}" + + if [ "${AUTH[0]}" != "(null)" ]; then + INNOEXTRA+=" --user=${AUTH[0]}" + fi + + if [ ${#AUTH[*]} -eq 2 ]; then + INNOEXTRA+=" --password=${AUTH[1]}" + elif [ "${AUTH[0]}" != "(null)" ]; then + # Empty password, used for testing, debugging etc. + INNOEXTRA+=" --password=" + fi + + get_keys + if [[ $encrypt -eq 1 ]];then + if [[ -n $ekey ]];then + INNOEXTRA+=" --encrypt=$ealgo --encrypt-key=$ekey " + else + INNOEXTRA+=" --encrypt=$ealgo --encrypt-key-file=$ekeyfile " + fi + fi + + if [[ -n $lsn ]];then + INNOEXTRA+=" --incremental --incremental-lsn=$lsn " + fi + + check_extra + + wsrep_log_info "Streaming the backup to joiner at ${REMOTEIP} ${SST_PORT}" + + if [[ -n $progress ]];then + get_footprint + tcmd="$pcmd | $tcmd" + elif [[ -n $rlimit ]];then + adjust_progress + tcmd="$pcmd | $tcmd" + fi + + set +e + timeit "Donor-Transfer" "$INNOBACKUP | $tcmd; RC=( "\${PIPESTATUS[@]}" )" + set -e + + if [ ${RC[0]} -ne 0 ]; then + wsrep_log_error "${INNOBACKUPEX_BIN} finished with error: ${RC[0]}. " \ + "Check ${DATA}/innobackup.backup.log" + exit 22 + elif [[ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]];then + wsrep_log_error "$tcmd finished with error: ${RC[1]}" + exit 22 + fi + + # innobackupex implicitly writes PID to fixed location in ${TMPDIR} + XTRABACKUP_PID="${TMPDIR}/xtrabackup_pid" + + + else # BYPASS FOR IST + + wsrep_log_info "Bypassing the SST for IST" + STATE="${WSREP_SST_OPT_GTID}" + echo "continue" # now server can resume updating data + echo "${STATE}" > "${MAGIC_FILE}" + echo "1" > "${DATA}/${IST_FILE}" + get_keys + pushd ${DATA} 1>/dev/null + set +e + if [[ $encrypt -eq 1 ]];then + tcmd=" $ecmd | $tcmd" + fi + timeit "Donor-IST-Unencrypted-transfer" "$strmcmd | $tcmd; RC=( "\${PIPESTATUS[@]}" )" + set -e + popd 1>/dev/null + + for ecode in "${RC[@]}";do + if [[ $ecode -ne 0 ]];then + wsrep_log_error "Error while streaming data to joiner node: " \ + "exit codes: ${RC[@]}" + exit 1 + fi + done + fi + + echo "done ${WSREP_SST_OPT_GTID}" + wsrep_log_info "Total time on donor: $totime seconds" + +elif [ "${WSREP_SST_OPT_ROLE}" = "joiner" ] +then + [[ -e $SST_PROGRESS_FILE ]] && wsrep_log_info "Stale sst_in_progress file: $SST_PROGRESS_FILE" + touch $SST_PROGRESS_FILE + + if [[ ! -e ${DATA}/ibdata1 ]];then + incremental=0 + fi + + if [[ $incremental -eq 1 ]];then + wsrep_log_info "Incremental SST enabled" + #lsn=$(/pxc/bin/mysqld --defaults-file=$WSREP_SST_OPT_CONF --basedir=/pxc --wsrep-recover 2>&1 | grep -o 'log sequence number .*' | cut -d " " -f 4 | head -1) + lsn=$(grep to_lsn xtrabackup_checkpoints | cut -d= -f2 | tr -d ' ') + wsrep_log_info "Recovered LSN: $lsn" + fi + + sencrypted=1 + nthreads=1 + + MODULE="xtrabackup_sst" + + # May need xtrabackup_checkpoints later on + rm -f ${DATA}/xtrabackup_binary ${DATA}/xtrabackup_galera_info ${DATA}/xtrabackup_logfile + + ADDR=${WSREP_SST_OPT_ADDR} + if [ -z "${SST_PORT}" ] + then + SST_PORT=4444 + ADDR="$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $1 }'):${SST_PORT}" + fi + + wait_for_listen ${SST_PORT} ${ADDR} ${MODULE} & + + trap sig_joiner_cleanup HUP PIPE INT TERM + trap cleanup_joiner EXIT + + if [[ -n $progress ]];then + adjust_progress + tcmd+=" | $pcmd" + fi + + if [[ $incremental -eq 1 ]];then + BDATA=$DATA + DATA=$(mktemp -d) + MAGIC_FILE="${DATA}/${INFO_FILE}" + fi + + get_keys + set +e + if [[ $encrypt -eq 1 && $sencrypted -eq 1 ]];then + strmcmd=" $ecmd | $strmcmd" + fi + + pushd ${DATA} 1>/dev/null + timeit "Joiner-Recv-Unencrypted" "$tcmd | $strmcmd; RC=( "\${PIPESTATUS[@]}" )" + popd 1>/dev/null + + set -e + + if [[ $sfmt == 'xbstream' ]];then + # Special handling till lp:1193240 is fixed" + if [[ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]];then + wsrep_log_error "Xbstream failed" + wsrep_log_error "Data directory ${DATA} may not be empty: lp:1193240" \ + "Manual intervention required in that case" + exit 32 + fi + fi + + wait %% # join for wait_for_listen thread + + for ecode in "${RC[@]}";do + if [[ $ecode -ne 0 ]];then + wsrep_log_error "Error while getting data from donor node: " \ + "exit codes: ${RC[@]}" + exit 32 + fi + done + + if [ ! -r "${MAGIC_FILE}" ] + then + # this message should cause joiner to abort + wsrep_log_error "xtrabackup process ended without creating '${MAGIC_FILE}'" + wsrep_log_info "Contents of datadir" + wsrep_log_info "$(ls -l ${DATA}/**/*)" + exit 32 + fi + + if ! ps -p ${WSREP_SST_OPT_PARENT} &>/dev/null + then + wsrep_log_error "Parent mysqld process (PID:${WSREP_SST_OPT_PARENT}) terminated unexpectedly." + exit 32 + fi + + if [ ! -r "${DATA}/${IST_FILE}" ] + then + wsrep_log_info "Proceeding with SST" + wsrep_log_info "Removing existing ib_logfile files" + if [[ $incremental -ne 1 ]];then + rm -f ${DATA}/ib_logfile* + else + rm -f ${BDATA}/ib_logfile* + fi + + get_proc + + # Rebuild indexes for compact backups + if grep -q 'compact = 1' ${DATA}/xtrabackup_checkpoints;then + wsrep_log_info "Index compaction detected" + rebuild=1 + fi + + if [[ $rebuild -eq 1 ]];then + nthreads=$(parse_cnf xtrabackup rebuild-threads $nproc) + wsrep_log_info "Rebuilding during prepare with $nthreads threads" + rebuildcmd="--rebuild-indexes --rebuild-threads=$nthreads" + fi + + if test -n "$(find ${DATA} -maxdepth 1 -type f -name '*.qp' -print -quit)";then + + wsrep_log_info "Compressed qpress files found" + + if [[ ! -x `which qpress` ]];then + wsrep_log_error "qpress not found in path: $PATH" + exit 22 + fi + + if [[ -n $progress ]] && pv --help | grep -q 'line-mode';then + count=$(find ${DATA} -type f -name '*.qp' | wc -l) + count=$(( count*2 )) + if pv --help | grep -q FORMAT;then + pvopts="-f -s $count -l -N Decompression -F '%N => Rate:%r Elapsed:%t %e Progress: [%b/$count]'" + else + pvopts="-f -s $count -l -N Decompression" + fi + pcmd="pv $pvopts" + adjust_progress + dcmd="$pcmd | xargs -n 2 qpress -T${nproc}d" + else + dcmd="xargs -n 2 qpress -T${nproc}d" + fi + + wsrep_log_info "Removing existing ibdata1 file" + rm -f ${DATA}/ibdata1 + + # Decompress the qpress files + wsrep_log_info "Decompression with $nproc threads" + timeit "Decompression" "find ${DATA} -type f -name '*.qp' -printf '%p\n%h\n' | $dcmd" + extcode=$? + + if [[ $extcode -eq 0 ]];then + wsrep_log_info "Removing qpress files after decompression" + find ${DATA} -type f -name '*.qp' -delete + if [[ $? -ne 0 ]];then + wsrep_log_error "Something went wrong with deletion of qpress files. Investigate" + fi + else + wsrep_log_error "Decompression failed. Exit code: $extcode" + exit 22 + fi + fi + + if [[ $incremental -eq 1 ]];then + # Added --ibbackup=xtrabackup_55 because it fails otherwise citing connection issues. + INNOAPPLY="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} \ + --ibbackup=xtrabackup_55 --apply-log $rebuildcmd --redo-only $BDATA --incremental-dir=${DATA} &>>${BDATA}/innobackup.prepare.log" + fi + + wsrep_log_info "Preparing the backup at ${DATA}" + timeit "Xtrabackup prepare stage" "$INNOAPPLY" + + if [[ $incremental -eq 1 ]];then + wsrep_log_info "Cleaning up ${DATA} after incremental SST" + [[ -d ${DATA} ]] && rm -rf ${DATA} + DATA=$BDATA + fi + + if [ $? -ne 0 ]; + then + wsrep_log_error "${INNOBACKUPEX_BIN} finished with errors. Check ${DATA}/innobackup.prepare.log" + exit 22 + fi + else + 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" + exit 2 + fi + + cat "${MAGIC_FILE}" # output UUID:seqno + wsrep_log_info "Total time on joiner: $totime seconds" +fi + +exit 0 diff --git a/scripts/wsrep_sst_xtrabackup-v2 b/scripts/wsrep_sst_xtrabackup-v2 new file mode 100755 index 00000000000..f4d133d4f8e --- /dev/null +++ b/scripts/wsrep_sst_xtrabackup-v2 @@ -0,0 +1,930 @@ +#!/bin/bash -ue +# Copyright (C) 2013 Percona Inc +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1301 USA. + +# Documentation: http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html +# Make sure to read that before proceeding! + + + + +. $(dirname $0)/wsrep_sst_common + +ealgo="" +ekey="" +ekeyfile="" +encrypt=0 +nproc=1 +ecode=0 +XTRABACKUP_PID="" +SST_PORT="" +REMOTEIP="" +tcert="" +tpem="" +tkey="" +sockopt="" +progress="" +ttime=0 +totime=0 +lsn="" +incremental=0 +ecmd="" +rlimit="" +# Initially +stagemsg="${WSREP_SST_OPT_ROLE}" +cpat="" +speciald=0 +ib_home_dir="" +ib_log_dir="" + +sfmt="tar" +strmcmd="" +tfmt="" +tcmd="" +rebuild=0 +rebuildcmd="" +payload=0 +pvformat="-F '%N => Rate:%r Avg:%a Elapsed:%t %e Bytes: %b %p' " +pvopts="-f -i 10 -N $WSREP_SST_OPT_ROLE " +STATDIR="" +uextra=0 +disver="" + +tmpopts="" +itmpdir="" +xtmpdir="" + +scomp="" +sdecomp="" + +if which pv &>/dev/null && pv --help | grep -q FORMAT;then + pvopts+=$pvformat +fi +pcmd="pv $pvopts" +declare -a RC + +INNOBACKUPEX_BIN=innobackupex +readonly AUTH=(${WSREP_SST_OPT_AUTH//:/ }) +DATA="${WSREP_SST_OPT_DATA}" +INFO_FILE="xtrabackup_galera_info" +IST_FILE="xtrabackup_ist" +MAGIC_FILE="${DATA}/${INFO_FILE}" + +# Setting the path for ss and ip +export PATH="/usr/sbin:/sbin:$PATH" + +timeit(){ + local stage=$1 + shift + local cmd="$@" + local x1 x2 took extcode + + if [[ $ttime -eq 1 ]];then + x1=$(date +%s) + wsrep_log_info "Evaluating $cmd" + eval "$cmd" + extcode=$? + x2=$(date +%s) + took=$(( x2-x1 )) + wsrep_log_info "NOTE: $stage took $took seconds" + totime=$(( totime+took )) + else + wsrep_log_info "Evaluating $cmd" + eval "$cmd" + extcode=$? + fi + return $extcode +} + +get_keys() +{ + # $encrypt -eq 1 is for internal purposes only + if [[ $encrypt -ge 2 || $encrypt -eq -1 ]];then + return + fi + + if [[ $encrypt -eq 0 ]];then + if my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -q encrypt;then + wsrep_log_error "Unexpected option combination. SST may fail. Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html " + fi + return + fi + + if [[ $sfmt == 'tar' ]];then + wsrep_log_info "NOTE: Xtrabackup-based encryption - encrypt=1 - cannot be enabled with tar format" + encrypt=-1 + return + fi + + wsrep_log_info "Xtrabackup based encryption enabled in my.cnf - Supported only from Xtrabackup 2.1.4" + + if [[ -z $ealgo ]];then + wsrep_log_error "FATAL: Encryption algorithm empty from my.cnf, bailing out" + exit 3 + fi + + if [[ -z $ekey && ! -r $ekeyfile ]];then + wsrep_log_error "FATAL: Either key or keyfile must be readable" + exit 3 + fi + + if [[ -z $ekey ]];then + ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key-file=$ekeyfile" + else + ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key=$ekey" + fi + + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + ecmd+=" -d" + fi + + stagemsg+="-XB-Encrypted" +} + +get_transfer() +{ + if [[ -z $SST_PORT ]];then + TSST_PORT=4444 + else + TSST_PORT=$SST_PORT + fi + + if [[ $tfmt == 'nc' ]];then + if [[ ! -x `which nc` ]];then + wsrep_log_error "nc(netcat) not found in path: $PATH" + exit 2 + fi + wsrep_log_info "Using netcat as streamer" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + tcmd="nc -dl ${TSST_PORT}" + else + tcmd="nc ${REMOTEIP} ${TSST_PORT}" + fi + else + tfmt='socat' + wsrep_log_info "Using socat as streamer" + if [[ ! -x `which socat` ]];then + wsrep_log_error "socat not found in path: $PATH" + exit 2 + fi + + if [[ $encrypt -eq 2 || $encrypt -eq 3 ]] && ! socat -V | grep -q WITH_OPENSSL;then + wsrep_log_info "NOTE: socat is not openssl enabled, falling back to plain transfer" + encrypt=-1 + fi + + if [[ $encrypt -eq 2 ]];then + wsrep_log_info "Using openssl based encryption with socat: with crt and pem" + if [[ -z $tpem || -z $tcert ]];then + wsrep_log_error "Both PEM and CRT files required" + exit 22 + fi + stagemsg+="-OpenSSL-Encrypted-2" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + wsrep_log_info "Decrypting with PEM $tpem, CA: $tcert" + tcmd="socat -u openssl-listen:${TSST_PORT},reuseaddr,cert=$tpem,cafile=${tcert}${sockopt} stdio" + else + wsrep_log_info "Encrypting with PEM $tpem, CA: $tcert" + tcmd="socat -u stdio openssl-connect:${REMOTEIP}:${TSST_PORT},cert=$tpem,cafile=${tcert}${sockopt}" + fi + elif [[ $encrypt -eq 3 ]];then + wsrep_log_info "Using openssl based encryption with socat: with key and crt" + if [[ -z $tpem || -z $tkey ]];then + wsrep_log_error "Both certificate and key files required" + exit 22 + fi + stagemsg+="-OpenSSL-Encrypted-3" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + wsrep_log_info "Decrypting with certificate $tpem, key $tkey" + tcmd="socat -u openssl-listen:${TSST_PORT},reuseaddr,cert=$tpem,key=${tkey},verify=0${sockopt} stdio" + else + wsrep_log_info "Encrypting with certificate $tpem, key $tkey" + tcmd="socat -u stdio openssl-connect:${REMOTEIP}:${TSST_PORT},cert=$tpem,key=${tkey},verify=0${sockopt}" + 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 + fi + fi + +} + +parse_cnf() +{ + local group=$1 + local var=$2 + reval=$(my_print_defaults -c $WSREP_SST_OPT_CONF $group | awk -F= '{if ($1 ~ /_/) { gsub(/_/,"-",$1); print $1"="$2 } else { print $0 }}' | grep -- "--$var=" | cut -d= -f2-) + if [[ -z $reval ]];then + [[ -n $3 ]] && reval=$3 + fi + echo $reval +} + +get_footprint() +{ + pushd $WSREP_SST_OPT_DATA 1>/dev/null + payload=$(find . -regex '.*\.ibd$\|.*\.MYI$\|.*\.MYD$\|.*ibdata1$' -type f -print0 | xargs -0 du --block-size=1 -c | awk 'END { print $1 }') + if my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -q -- "--compress";then + # QuickLZ has around 50% compression ratio + # When compression/compaction used, the progress is only an approximate. + payload=$(( payload*1/2 )) + fi + popd 1>/dev/null + pcmd+=" -s $payload" + adjust_progress +} + +adjust_progress() +{ + if [[ -n $progress && $progress != '1' ]];then + if [[ -e $progress ]];then + pcmd+=" 2>>$progress" + else + pcmd+=" 2>$progress" + fi + elif [[ -z $progress && -n $rlimit ]];then + # When rlimit is non-zero + pcmd="pv -q" + fi + + if [[ -n $rlimit && "$WSREP_SST_OPT_ROLE" == "donor" ]];then + wsrep_log_info "Rate-limiting SST to $rlimit" + pcmd+=" -L \$rlimit" + fi +} + +read_cnf() +{ + sfmt=$(parse_cnf sst streamfmt "xbstream") + tfmt=$(parse_cnf sst transferfmt "socat") + tcert=$(parse_cnf sst tca "") + tpem=$(parse_cnf sst tcert "") + tkey=$(parse_cnf sst tkey "") + encrypt=$(parse_cnf sst encrypt 0) + sockopt=$(parse_cnf sst sockopt "") + progress=$(parse_cnf sst progress "") + rebuild=$(parse_cnf sst rebuild 0) + ttime=$(parse_cnf sst time 0) + cpat=$(parse_cnf sst cpat '.*galera\.cache$\|.*sst_in_progress$\|.*grastate\.dat$\|.*\.err$\|.*\.log$\|.*RPM_UPGRADE_MARKER$\|.*RPM_UPGRADE_HISTORY$') + incremental=$(parse_cnf sst incremental 0) + ealgo=$(parse_cnf xtrabackup encrypt "") + ekey=$(parse_cnf xtrabackup encrypt-key "") + ekeyfile=$(parse_cnf xtrabackup encrypt-key-file "") + scomp=$(parse_cnf sst compressor "") + sdecomp=$(parse_cnf sst decompressor "") + + + # Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html + if [[ -z $ealgo ]];then + ealgo=$(parse_cnf sst encrypt-algo "") + ekey=$(parse_cnf sst encrypt-key "") + ekeyfile=$(parse_cnf sst encrypt-key-file "") + fi + rlimit=$(parse_cnf sst rlimit "") + uextra=$(parse_cnf sst use-extra 0) + speciald=$(parse_cnf sst sst-special-dirs 1) + iopts=$(parse_cnf sst inno-backup-opts "") + iapts=$(parse_cnf sst inno-apply-opts "") + impts=$(parse_cnf sst inno-move-opts "") + stimeout=$(parse_cnf sst sst-initial-timeout 100) +} + +get_stream() +{ + if [[ $sfmt == 'xbstream' ]];then + wsrep_log_info "Streaming with xbstream" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + strmcmd="xbstream -x" + else + strmcmd="xbstream -c \${INFO_FILE}" + fi + else + sfmt="tar" + wsrep_log_info "Streaming with 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 || $nproc -eq 0 ]] && nproc=1 + set -e +} + +sig_joiner_cleanup() +{ + wsrep_log_error "Removing $MAGIC_FILE file due to signal" + 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" + fi + if [ "${WSREP_SST_OPT_ROLE}" = "joiner" ];then + wsrep_log_info "Removing the sst_in_progress file" + wsrep_cleanup_progress_file + fi + if [[ -n $progress && -p $progress ]];then + wsrep_log_info "Cleaning up fifo file $progress" + rm $progress + fi + if [[ -n ${STATDIR:-} ]];then + [[ -d $STATDIR ]] && rm -rf $STATDIR + fi +} + +check_pid() +{ + local pid_file="$1" + [ -r "$pid_file" ] && ps -p $(cat "$pid_file") >/dev/null 2>&1 +} + +cleanup_donor() +{ + # Since this is invoked just after exit NNN + local estatus=$? + if [[ $estatus -ne 0 ]];then + wsrep_log_error "Cleanup after exit with status:$estatus" + fi + + if [[ -n ${XTRABACKUP_PID:-} ]];then + if check_pid $XTRABACKUP_PID + then + wsrep_log_error "xtrabackup process is still running. Killing... " + kill_xtrabackup + fi + + fi + rm -f ${DATA}/${IST_FILE} || true + + if [[ -n $progress && -p $progress ]];then + wsrep_log_info "Cleaning up fifo file $progress" + rm -f $progress || true + fi + + wsrep_log_info "Cleaning up temporary directories" + + if [[ -n $xtmpdir ]];then + [[ -d $xtmpdir ]] && rm -rf $xtmpdir || true + fi + + if [[ -n $itmpdir ]];then + [[ -d $itmpdir ]] && rm -rf $itmpdir || true + fi +} + +kill_xtrabackup() +{ + local PID=$(cat $XTRABACKUP_PID) + [ -n "$PID" -a "0" != "$PID" ] && kill $PID && (kill $PID && kill -9 $PID) || : + wsrep_log_info "Removing xtrabackup pid file $XTRABACKUP_PID" + rm -f "$XTRABACKUP_PID" || true +} + +setup_ports() +{ + if [[ "$WSREP_SST_OPT_ROLE" == "donor" ]];then + SST_PORT=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $2 }') + REMOTEIP=$(echo $WSREP_SST_OPT_ADDR | awk -F ':' '{ print $1 }') + lsn=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $4 }') + else + SST_PORT=$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $2 }') + fi +} + +# waits ~10 seconds for 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 + ss -p state listening "( sport = :$PORT )" | grep -qE 'socat|nc' && break + sleep 0.2 + done + if [[ $incremental -eq 1 ]];then + echo "ready ${ADDR}/${MODULE}/$lsn" + else + echo "ready ${ADDR}/${MODULE}" + fi +} + +check_extra() +{ + local use_socket=1 + if [[ $uextra -eq 1 ]];then + if my_print_defaults -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--thread-handling=" | grep -q 'pool-of-threads';then + local eport=$(my_print_defaults -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--extra-port=" | cut -d= -f2) + if [[ -n $eport ]];then + # Xtrabackup works only locally. + # Hence, setting host to 127.0.0.1 unconditionally. + wsrep_log_info "SST through extra_port $eport" + INNOEXTRA+=" --host=127.0.0.1 --port=$eport " + use_socket=0 + else + wsrep_log_error "Extra port $eport null, failing" + exit 1 + fi + else + wsrep_log_info "Thread pool not set, ignore the option use_extra" + fi + fi + if [[ $use_socket -eq 1 ]] && [[ -n "${WSREP_SST_OPT_SOCKET}" ]];then + INNOEXTRA+=" --socket=${WSREP_SST_OPT_SOCKET}" + fi +} + +recv_joiner() +{ + local dir=$1 + local msg=$2 + local tmt=$3 + local ltcmd + + pushd ${dir} 1>/dev/null + set +e + + if [[ $tmt -gt 0 && -x `which timeout` ]];then + if timeout --help | grep -q -- '-k';then + ltcmd="timeout -k $(( tmt+10 )) $tmt $tcmd" + else + ltcmd="timeout $tmt $tcmd" + fi + timeit "$msg" "$ltcmd | $strmcmd; RC=( "\${PIPESTATUS[@]}" )" + else + timeit "$msg" "$tcmd | $strmcmd; RC=( "\${PIPESTATUS[@]}" )" + fi + + set -e + popd 1>/dev/null + + if [[ ${RC[0]} -eq 124 ]];then + wsrep_log_error "Possible timeout in receving first data from donor in gtid stage" + exit 32 + fi + + for ecode in "${RC[@]}";do + if [[ $ecode -ne 0 ]];then + wsrep_log_error "Error while getting data from donor node: " \ + "exit codes: ${RC[@]}" + exit 32 + fi + done + + if [ ! -r "${MAGIC_FILE}" ];then + # this message should cause joiner to abort + wsrep_log_error "xtrabackup process ended without creating '${MAGIC_FILE}'" + wsrep_log_info "Contents of datadir" + wsrep_log_info "$(ls -l ${dir}/*)" + exit 32 + fi +} + + +send_donor() +{ + local dir=$1 + local msg=$2 + + pushd ${dir} 1>/dev/null + set +e + timeit "$msg" "$strmcmd | $tcmd; RC=( "\${PIPESTATUS[@]}" )" + set -e + popd 1>/dev/null + + + for ecode in "${RC[@]}";do + if [[ $ecode -ne 0 ]];then + wsrep_log_error "Error while getting data from donor node: " \ + "exit codes: ${RC[@]}" + exit 32 + fi + done + +} + +if [[ ! -x `which $INNOBACKUPEX_BIN` ]];then + wsrep_log_error "innobackupex not in path: $PATH" + exit 2 +fi + +rm -f "${MAGIC_FILE}" + +if [[ ! ${WSREP_SST_OPT_ROLE} == 'joiner' && ! ${WSREP_SST_OPT_ROLE} == 'donor' ]];then + wsrep_log_error "Invalid role ${WSREP_SST_OPT_ROLE}" + exit 22 +fi + +read_cnf +setup_ports +get_stream +get_transfer + +if ${INNOBACKUPEX_BIN} /tmp --help | grep -q -- '--version-check'; then + disver="--no-version-check" +fi + + +INNOEXTRA="" +INNOAPPLY="${INNOBACKUPEX_BIN} $disver $iapts --apply-log \$rebuildcmd \${DATA} &>\${DATA}/innobackup.prepare.log" +INNOMOVE="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} $disver $impts --move-back --force-non-empty-directories \${DATA} &>\${DATA}/innobackup.move.log" +INNOBACKUP="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} $disver $iopts \$tmpopts \$INNOEXTRA --galera-info --stream=\$sfmt \$itmpdir 2>\${DATA}/innobackup.backup.log" + +if [ "$WSREP_SST_OPT_ROLE" = "donor" ] +then + trap cleanup_donor EXIT + + if [ $WSREP_SST_OPT_BYPASS -eq 0 ] + then + + if [[ -z $(parse_cnf mysqld tmpdir "") && -z $(parse_cnf xtrabackup tmpdir "") ]];then + xtmpdir=$(mktemp -d) + tmpopts=" --tmpdir=$xtmpdir " + wsrep_log_info "Using $xtmpdir as xtrabackup temporary directory" + fi + + itmpdir=$(mktemp -d) + wsrep_log_info "Using $itmpdir as innobackupex temporary directory" + + if [ "${AUTH[0]}" != "(null)" ]; then + INNOEXTRA+=" --user=${AUTH[0]}" + fi + + if [ ${#AUTH[*]} -eq 2 ]; then + INNOEXTRA+=" --password=${AUTH[1]}" + elif [ "${AUTH[0]}" != "(null)" ]; then + # Empty password, used for testing, debugging etc. + INNOEXTRA+=" --password=" + fi + + get_keys + if [[ $encrypt -eq 1 ]];then + if [[ -n $ekey ]];then + INNOEXTRA+=" --encrypt=$ealgo --encrypt-key=$ekey " + else + INNOEXTRA+=" --encrypt=$ealgo --encrypt-key-file=$ekeyfile " + fi + fi + + if [[ -n $lsn ]];then + INNOEXTRA+=" --incremental --incremental-lsn=$lsn " + fi + + check_extra + + wsrep_log_info "Streaming GTID file before SST" + + echo "${WSREP_SST_OPT_GTID}" > "${MAGIC_FILE}" + + ttcmd="$tcmd" + + if [[ $encrypt -eq 1 ]];then + if [[ -n $scomp ]];then + tcmd=" $ecmd | $scomp | $tcmd " + else + tcmd=" $ecmd | $tcmd " + fi + elif [[ -n $scomp ]];then + tcmd=" $scomp | $tcmd " + fi + + + send_donor $DATA "${stagemsg}-gtid" + + tcmd="$ttcmd" + if [[ -n $progress ]];then + get_footprint + tcmd="$pcmd | $tcmd" + elif [[ -n $rlimit ]];then + adjust_progress + tcmd="$pcmd | $tcmd" + fi + + wsrep_log_info "Sleeping before data transfer for SST" + sleep 10 + + wsrep_log_info "Streaming the backup to joiner at ${REMOTEIP} ${SST_PORT:-4444}" + + if [[ -n $scomp ]];then + tcmd="$scomp | $tcmd" + fi + + set +e + timeit "${stagemsg}-SST" "$INNOBACKUP | $tcmd; RC=( "\${PIPESTATUS[@]}" )" + set -e + + if [ ${RC[0]} -ne 0 ]; then + wsrep_log_error "${INNOBACKUPEX_BIN} finished with error: ${RC[0]}. " \ + "Check ${DATA}/innobackup.backup.log" + exit 22 + elif [[ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]];then + wsrep_log_error "$tcmd finished with error: ${RC[1]}" + exit 22 + fi + + # innobackupex implicitly writes PID to fixed location in $xtmpdir + XTRABACKUP_PID="$xtmpdir/xtrabackup_pid" + + + else # BYPASS FOR IST + + wsrep_log_info "Bypassing the SST for IST" + echo "continue" # now server can resume updating data + echo "${WSREP_SST_OPT_GTID}" > "${MAGIC_FILE}" + echo "1" > "${DATA}/${IST_FILE}" + get_keys + if [[ $encrypt -eq 1 ]];then + if [[ -n $scomp ]];then + tcmd=" $ecmd | $scomp | $tcmd " + else + tcmd=" $ecmd | $tcmd " + fi + elif [[ -n $scomp ]];then + tcmd=" $scomp | $tcmd " + fi + strmcmd+=" \${IST_FILE}" + + send_donor $DATA "${stagemsg}-IST" + + fi + + echo "done ${WSREP_SST_OPT_GTID}" + wsrep_log_info "Total time on donor: $totime seconds" + +elif [ "${WSREP_SST_OPT_ROLE}" = "joiner" ] +then + [[ -e $SST_PROGRESS_FILE ]] && wsrep_log_info "Stale sst_in_progress file: $SST_PROGRESS_FILE" + [[ -n $SST_PROGRESS_FILE ]] && touch $SST_PROGRESS_FILE + + if [[ $speciald -eq 1 ]];then + ib_home_dir=$(parse_cnf mysqld innodb-data-home-dir "") + ib_log_dir=$(parse_cnf mysqld innodb-log-group-home-dir "") + if [[ -z $ib_home_dir && -z $ib_log_dir ]];then + speciald=0 + fi + fi + + stagemsg="Joiner-Recv" + + if [[ ! -e ${DATA}/ibdata1 ]];then + incremental=0 + fi + + if [[ $incremental -eq 1 ]];then + wsrep_log_info "Incremental SST enabled: NOT SUPPORTED yet" + lsn=$(grep to_lsn xtrabackup_checkpoints | cut -d= -f2 | tr -d ' ') + wsrep_log_info "Recovered LSN: $lsn" + fi + + sencrypted=1 + nthreads=1 + + MODULE="xtrabackup_sst" + + rm -f "${DATA}/${IST_FILE}" + + # May need xtrabackup_checkpoints later on + rm -f ${DATA}/xtrabackup_binary ${DATA}/xtrabackup_galera_info ${DATA}/xtrabackup_logfile + + ADDR=${WSREP_SST_OPT_ADDR} + if [ -z "${SST_PORT}" ] + then + SST_PORT=4444 + ADDR="$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $1 }'):${SST_PORT}" + fi + + wait_for_listen ${SST_PORT} ${ADDR} ${MODULE} & + + trap sig_joiner_cleanup HUP PIPE INT TERM + trap cleanup_joiner EXIT + + if [[ -n $progress ]];then + adjust_progress + tcmd+=" | $pcmd" + fi + + if [[ $incremental -eq 1 ]];then + BDATA=$DATA + DATA=$(mktemp -d) + MAGIC_FILE="${DATA}/${INFO_FILE}" + fi + + get_keys + if [[ $encrypt -eq 1 && $sencrypted -eq 1 ]];then + if [[ -n $sdecomp ]];then + strmcmd=" $sdecomp | $ecmd | $strmcmd" + else + strmcmd=" $ecmd | $strmcmd" + fi + elif [[ -n $sdecomp ]];then + strmcmd=" $sdecomp | $strmcmd" + fi + + STATDIR=$(mktemp -d) + MAGIC_FILE="${STATDIR}/${INFO_FILE}" + recv_joiner $STATDIR "${stagemsg}-gtid" $stimeout + + if ! ps -p ${WSREP_SST_OPT_PARENT} &>/dev/null + then + wsrep_log_error "Parent mysqld process (PID:${WSREP_SST_OPT_PARENT}) terminated unexpectedly." + exit 32 + fi + + if [ ! -r "${STATDIR}/${IST_FILE}" ] + then + wsrep_log_info "Proceeding with SST" + + if [[ $speciald -eq 1 && -d ${DATA}/.sst ]];then + wsrep_log_info "WARNING: Stale temporary SST directory: ${DATA}/.sst from previous SST" + fi + + if [[ $incremental -ne 1 ]];then + if [[ $speciald -eq 1 ]];then + wsrep_log_info "Cleaning the existing datadir and innodb-data/log directories" + find $ib_home_dir $ib_log_dir $DATA -mindepth 1 -regex $cpat -prune -o -exec rm -rfv {} 1>&2 \+ + else + wsrep_log_info "Cleaning the existing datadir" + find $DATA -mindepth 1 -regex $cpat -prune -o -exec rm -rfv {} 1>&2 \+ + fi + tempdir=$(parse_cnf mysqld log-bin "") + if [[ -n ${tempdir:-} ]];then + binlog_dir=$(dirname $tempdir) + binlog_file=$(basename $tempdir) + if [[ -n ${binlog_dir:-} && $binlog_dir != '.' && $binlog_dir != $DATA ]];then + pattern="$binlog_dir/$binlog_file\.[0-9]+$" + wsrep_log_info "Cleaning the binlog directory $binlog_dir as well" + find $binlog_dir -maxdepth 1 -type f -regex $pattern -exec rm -fv {} 1>&2 \+ + rm $binlog_dir/*.index || true + fi + fi + + else + wsrep_log_info "Removing existing ib_logfile files" + rm -f ${BDATA}/ib_logfile* + fi + + + if [[ $speciald -eq 1 ]];then + mkdir -p ${DATA}/.sst + TDATA=${DATA} + DATA="${DATA}/.sst" + fi + + + MAGIC_FILE="${DATA}/${INFO_FILE}" + recv_joiner $DATA "${stagemsg}-SST" 0 + + get_proc + + # Rebuild indexes for compact backups + if grep -q 'compact = 1' ${DATA}/xtrabackup_checkpoints;then + wsrep_log_info "Index compaction detected" + rebuild=1 + fi + + if [[ $rebuild -eq 1 ]];then + nthreads=$(parse_cnf xtrabackup rebuild-threads $nproc) + wsrep_log_info "Rebuilding during prepare with $nthreads threads" + rebuildcmd="--rebuild-indexes --rebuild-threads=$nthreads" + fi + + if test -n "$(find ${DATA} -maxdepth 1 -type f -name '*.qp' -print -quit)";then + + wsrep_log_info "Compressed qpress files found" + + if [[ ! -x `which qpress` ]];then + wsrep_log_error "qpress not found in path: $PATH" + exit 22 + fi + + if [[ -n $progress ]] && pv --help | grep -q 'line-mode';then + count=$(find ${DATA} -type f -name '*.qp' | wc -l) + count=$(( count*2 )) + if pv --help | grep -q FORMAT;then + pvopts="-f -s $count -l -N Decompression -F '%N => Rate:%r Elapsed:%t %e Progress: [%b/$count]'" + else + pvopts="-f -s $count -l -N Decompression" + fi + pcmd="pv $pvopts" + adjust_progress + dcmd="$pcmd | xargs -n 2 qpress -T${nproc}d" + else + dcmd="xargs -n 2 qpress -T${nproc}d" + fi + + + # Decompress the qpress files + wsrep_log_info "Decompression with $nproc threads" + timeit "Joiner-Decompression" "find ${DATA} -type f -name '*.qp' -printf '%p\n%h\n' | $dcmd" + extcode=$? + + if [[ $extcode -eq 0 ]];then + wsrep_log_info "Removing qpress files after decompression" + find ${DATA} -type f -name '*.qp' -delete + if [[ $? -ne 0 ]];then + wsrep_log_error "Something went wrong with deletion of qpress files. Investigate" + fi + else + wsrep_log_error "Decompression failed. Exit code: $extcode" + exit 22 + fi + fi + + + if [[ ! -z $WSREP_SST_OPT_BINLOG ]];then + + BINLOG_DIRNAME=$(dirname $WSREP_SST_OPT_BINLOG) + BINLOG_FILENAME=$(basename $WSREP_SST_OPT_BINLOG) + + # To avoid comparing data directory and BINLOG_DIRNAME + mv $DATA/${BINLOG_FILENAME}.* $BINLOG_DIRNAME/ 2>/dev/null || true + + pushd $BINLOG_DIRNAME &>/dev/null + for bfiles in $(ls -1 ${BINLOG_FILENAME}.*);do + echo ${BINLOG_DIRNAME}/${bfiles} >> ${BINLOG_FILENAME}.index + done + popd &> /dev/null + + fi + + if [[ $incremental -eq 1 ]];then + # Added --ibbackup=xtrabackup_55 because it fails otherwise citing connection issues. + INNOAPPLY="${INNOBACKUPEX_BIN} $disver --defaults-file=${WSREP_SST_OPT_CONF} \ + --ibbackup=xtrabackup_56 --apply-log $rebuildcmd --redo-only $BDATA --incremental-dir=${DATA} &>>${BDATA}/innobackup.prepare.log" + fi + + wsrep_log_info "Preparing the backup at ${DATA}" + timeit "Xtrabackup prepare stage" "$INNOAPPLY" + + if [ $? -ne 0 ]; + then + wsrep_log_error "${INNOBACKUPEX_BIN} apply finished with errors. Check ${DATA}/innobackup.prepare.log" + exit 22 + fi + + if [[ $speciald -eq 1 ]];then + MAGIC_FILE="${TDATA}/${INFO_FILE}" + set +e + rm $TDATA/innobackup.prepare.log $TDATA/innobackup.move.log + set -e + wsrep_log_info "Moving the backup to ${TDATA}" + timeit "Xtrabackup move stage" "$INNOMOVE" + if [[ $? -eq 0 ]];then + 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 ${DATA}/innobackup.move.log for details" + fi + fi + + if [[ $incremental -eq 1 ]];then + wsrep_log_info "Cleaning up ${DATA} after incremental SST" + [[ -d ${DATA} ]] && rm -rf ${DATA} + DATA=$BDATA + fi + + else + 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" + exit 2 + fi + cat "${MAGIC_FILE}" # output UUID:seqno + wsrep_log_info "Total time on joiner: $totime seconds" +fi + +exit 0 diff --git a/scripts/wsrep_sst_xtrabackup-v2.sh b/scripts/wsrep_sst_xtrabackup-v2.sh new file mode 100644 index 00000000000..f4d133d4f8e --- /dev/null +++ b/scripts/wsrep_sst_xtrabackup-v2.sh @@ -0,0 +1,930 @@ +#!/bin/bash -ue +# Copyright (C) 2013 Percona Inc +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1301 USA. + +# Documentation: http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html +# Make sure to read that before proceeding! + + + + +. $(dirname $0)/wsrep_sst_common + +ealgo="" +ekey="" +ekeyfile="" +encrypt=0 +nproc=1 +ecode=0 +XTRABACKUP_PID="" +SST_PORT="" +REMOTEIP="" +tcert="" +tpem="" +tkey="" +sockopt="" +progress="" +ttime=0 +totime=0 +lsn="" +incremental=0 +ecmd="" +rlimit="" +# Initially +stagemsg="${WSREP_SST_OPT_ROLE}" +cpat="" +speciald=0 +ib_home_dir="" +ib_log_dir="" + +sfmt="tar" +strmcmd="" +tfmt="" +tcmd="" +rebuild=0 +rebuildcmd="" +payload=0 +pvformat="-F '%N => Rate:%r Avg:%a Elapsed:%t %e Bytes: %b %p' " +pvopts="-f -i 10 -N $WSREP_SST_OPT_ROLE " +STATDIR="" +uextra=0 +disver="" + +tmpopts="" +itmpdir="" +xtmpdir="" + +scomp="" +sdecomp="" + +if which pv &>/dev/null && pv --help | grep -q FORMAT;then + pvopts+=$pvformat +fi +pcmd="pv $pvopts" +declare -a RC + +INNOBACKUPEX_BIN=innobackupex +readonly AUTH=(${WSREP_SST_OPT_AUTH//:/ }) +DATA="${WSREP_SST_OPT_DATA}" +INFO_FILE="xtrabackup_galera_info" +IST_FILE="xtrabackup_ist" +MAGIC_FILE="${DATA}/${INFO_FILE}" + +# Setting the path for ss and ip +export PATH="/usr/sbin:/sbin:$PATH" + +timeit(){ + local stage=$1 + shift + local cmd="$@" + local x1 x2 took extcode + + if [[ $ttime -eq 1 ]];then + x1=$(date +%s) + wsrep_log_info "Evaluating $cmd" + eval "$cmd" + extcode=$? + x2=$(date +%s) + took=$(( x2-x1 )) + wsrep_log_info "NOTE: $stage took $took seconds" + totime=$(( totime+took )) + else + wsrep_log_info "Evaluating $cmd" + eval "$cmd" + extcode=$? + fi + return $extcode +} + +get_keys() +{ + # $encrypt -eq 1 is for internal purposes only + if [[ $encrypt -ge 2 || $encrypt -eq -1 ]];then + return + fi + + if [[ $encrypt -eq 0 ]];then + if my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -q encrypt;then + wsrep_log_error "Unexpected option combination. SST may fail. Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html " + fi + return + fi + + if [[ $sfmt == 'tar' ]];then + wsrep_log_info "NOTE: Xtrabackup-based encryption - encrypt=1 - cannot be enabled with tar format" + encrypt=-1 + return + fi + + wsrep_log_info "Xtrabackup based encryption enabled in my.cnf - Supported only from Xtrabackup 2.1.4" + + if [[ -z $ealgo ]];then + wsrep_log_error "FATAL: Encryption algorithm empty from my.cnf, bailing out" + exit 3 + fi + + if [[ -z $ekey && ! -r $ekeyfile ]];then + wsrep_log_error "FATAL: Either key or keyfile must be readable" + exit 3 + fi + + if [[ -z $ekey ]];then + ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key-file=$ekeyfile" + else + ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key=$ekey" + fi + + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + ecmd+=" -d" + fi + + stagemsg+="-XB-Encrypted" +} + +get_transfer() +{ + if [[ -z $SST_PORT ]];then + TSST_PORT=4444 + else + TSST_PORT=$SST_PORT + fi + + if [[ $tfmt == 'nc' ]];then + if [[ ! -x `which nc` ]];then + wsrep_log_error "nc(netcat) not found in path: $PATH" + exit 2 + fi + wsrep_log_info "Using netcat as streamer" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + tcmd="nc -dl ${TSST_PORT}" + else + tcmd="nc ${REMOTEIP} ${TSST_PORT}" + fi + else + tfmt='socat' + wsrep_log_info "Using socat as streamer" + if [[ ! -x `which socat` ]];then + wsrep_log_error "socat not found in path: $PATH" + exit 2 + fi + + if [[ $encrypt -eq 2 || $encrypt -eq 3 ]] && ! socat -V | grep -q WITH_OPENSSL;then + wsrep_log_info "NOTE: socat is not openssl enabled, falling back to plain transfer" + encrypt=-1 + fi + + if [[ $encrypt -eq 2 ]];then + wsrep_log_info "Using openssl based encryption with socat: with crt and pem" + if [[ -z $tpem || -z $tcert ]];then + wsrep_log_error "Both PEM and CRT files required" + exit 22 + fi + stagemsg+="-OpenSSL-Encrypted-2" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + wsrep_log_info "Decrypting with PEM $tpem, CA: $tcert" + tcmd="socat -u openssl-listen:${TSST_PORT},reuseaddr,cert=$tpem,cafile=${tcert}${sockopt} stdio" + else + wsrep_log_info "Encrypting with PEM $tpem, CA: $tcert" + tcmd="socat -u stdio openssl-connect:${REMOTEIP}:${TSST_PORT},cert=$tpem,cafile=${tcert}${sockopt}" + fi + elif [[ $encrypt -eq 3 ]];then + wsrep_log_info "Using openssl based encryption with socat: with key and crt" + if [[ -z $tpem || -z $tkey ]];then + wsrep_log_error "Both certificate and key files required" + exit 22 + fi + stagemsg+="-OpenSSL-Encrypted-3" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + wsrep_log_info "Decrypting with certificate $tpem, key $tkey" + tcmd="socat -u openssl-listen:${TSST_PORT},reuseaddr,cert=$tpem,key=${tkey},verify=0${sockopt} stdio" + else + wsrep_log_info "Encrypting with certificate $tpem, key $tkey" + tcmd="socat -u stdio openssl-connect:${REMOTEIP}:${TSST_PORT},cert=$tpem,key=${tkey},verify=0${sockopt}" + 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 + fi + fi + +} + +parse_cnf() +{ + local group=$1 + local var=$2 + reval=$(my_print_defaults -c $WSREP_SST_OPT_CONF $group | awk -F= '{if ($1 ~ /_/) { gsub(/_/,"-",$1); print $1"="$2 } else { print $0 }}' | grep -- "--$var=" | cut -d= -f2-) + if [[ -z $reval ]];then + [[ -n $3 ]] && reval=$3 + fi + echo $reval +} + +get_footprint() +{ + pushd $WSREP_SST_OPT_DATA 1>/dev/null + payload=$(find . -regex '.*\.ibd$\|.*\.MYI$\|.*\.MYD$\|.*ibdata1$' -type f -print0 | xargs -0 du --block-size=1 -c | awk 'END { print $1 }') + if my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -q -- "--compress";then + # QuickLZ has around 50% compression ratio + # When compression/compaction used, the progress is only an approximate. + payload=$(( payload*1/2 )) + fi + popd 1>/dev/null + pcmd+=" -s $payload" + adjust_progress +} + +adjust_progress() +{ + if [[ -n $progress && $progress != '1' ]];then + if [[ -e $progress ]];then + pcmd+=" 2>>$progress" + else + pcmd+=" 2>$progress" + fi + elif [[ -z $progress && -n $rlimit ]];then + # When rlimit is non-zero + pcmd="pv -q" + fi + + if [[ -n $rlimit && "$WSREP_SST_OPT_ROLE" == "donor" ]];then + wsrep_log_info "Rate-limiting SST to $rlimit" + pcmd+=" -L \$rlimit" + fi +} + +read_cnf() +{ + sfmt=$(parse_cnf sst streamfmt "xbstream") + tfmt=$(parse_cnf sst transferfmt "socat") + tcert=$(parse_cnf sst tca "") + tpem=$(parse_cnf sst tcert "") + tkey=$(parse_cnf sst tkey "") + encrypt=$(parse_cnf sst encrypt 0) + sockopt=$(parse_cnf sst sockopt "") + progress=$(parse_cnf sst progress "") + rebuild=$(parse_cnf sst rebuild 0) + ttime=$(parse_cnf sst time 0) + cpat=$(parse_cnf sst cpat '.*galera\.cache$\|.*sst_in_progress$\|.*grastate\.dat$\|.*\.err$\|.*\.log$\|.*RPM_UPGRADE_MARKER$\|.*RPM_UPGRADE_HISTORY$') + incremental=$(parse_cnf sst incremental 0) + ealgo=$(parse_cnf xtrabackup encrypt "") + ekey=$(parse_cnf xtrabackup encrypt-key "") + ekeyfile=$(parse_cnf xtrabackup encrypt-key-file "") + scomp=$(parse_cnf sst compressor "") + sdecomp=$(parse_cnf sst decompressor "") + + + # Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html + if [[ -z $ealgo ]];then + ealgo=$(parse_cnf sst encrypt-algo "") + ekey=$(parse_cnf sst encrypt-key "") + ekeyfile=$(parse_cnf sst encrypt-key-file "") + fi + rlimit=$(parse_cnf sst rlimit "") + uextra=$(parse_cnf sst use-extra 0) + speciald=$(parse_cnf sst sst-special-dirs 1) + iopts=$(parse_cnf sst inno-backup-opts "") + iapts=$(parse_cnf sst inno-apply-opts "") + impts=$(parse_cnf sst inno-move-opts "") + stimeout=$(parse_cnf sst sst-initial-timeout 100) +} + +get_stream() +{ + if [[ $sfmt == 'xbstream' ]];then + wsrep_log_info "Streaming with xbstream" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + strmcmd="xbstream -x" + else + strmcmd="xbstream -c \${INFO_FILE}" + fi + else + sfmt="tar" + wsrep_log_info "Streaming with 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 || $nproc -eq 0 ]] && nproc=1 + set -e +} + +sig_joiner_cleanup() +{ + wsrep_log_error "Removing $MAGIC_FILE file due to signal" + 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" + fi + if [ "${WSREP_SST_OPT_ROLE}" = "joiner" ];then + wsrep_log_info "Removing the sst_in_progress file" + wsrep_cleanup_progress_file + fi + if [[ -n $progress && -p $progress ]];then + wsrep_log_info "Cleaning up fifo file $progress" + rm $progress + fi + if [[ -n ${STATDIR:-} ]];then + [[ -d $STATDIR ]] && rm -rf $STATDIR + fi +} + +check_pid() +{ + local pid_file="$1" + [ -r "$pid_file" ] && ps -p $(cat "$pid_file") >/dev/null 2>&1 +} + +cleanup_donor() +{ + # Since this is invoked just after exit NNN + local estatus=$? + if [[ $estatus -ne 0 ]];then + wsrep_log_error "Cleanup after exit with status:$estatus" + fi + + if [[ -n ${XTRABACKUP_PID:-} ]];then + if check_pid $XTRABACKUP_PID + then + wsrep_log_error "xtrabackup process is still running. Killing... " + kill_xtrabackup + fi + + fi + rm -f ${DATA}/${IST_FILE} || true + + if [[ -n $progress && -p $progress ]];then + wsrep_log_info "Cleaning up fifo file $progress" + rm -f $progress || true + fi + + wsrep_log_info "Cleaning up temporary directories" + + if [[ -n $xtmpdir ]];then + [[ -d $xtmpdir ]] && rm -rf $xtmpdir || true + fi + + if [[ -n $itmpdir ]];then + [[ -d $itmpdir ]] && rm -rf $itmpdir || true + fi +} + +kill_xtrabackup() +{ + local PID=$(cat $XTRABACKUP_PID) + [ -n "$PID" -a "0" != "$PID" ] && kill $PID && (kill $PID && kill -9 $PID) || : + wsrep_log_info "Removing xtrabackup pid file $XTRABACKUP_PID" + rm -f "$XTRABACKUP_PID" || true +} + +setup_ports() +{ + if [[ "$WSREP_SST_OPT_ROLE" == "donor" ]];then + SST_PORT=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $2 }') + REMOTEIP=$(echo $WSREP_SST_OPT_ADDR | awk -F ':' '{ print $1 }') + lsn=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $4 }') + else + SST_PORT=$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $2 }') + fi +} + +# waits ~10 seconds for 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 + ss -p state listening "( sport = :$PORT )" | grep -qE 'socat|nc' && break + sleep 0.2 + done + if [[ $incremental -eq 1 ]];then + echo "ready ${ADDR}/${MODULE}/$lsn" + else + echo "ready ${ADDR}/${MODULE}" + fi +} + +check_extra() +{ + local use_socket=1 + if [[ $uextra -eq 1 ]];then + if my_print_defaults -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--thread-handling=" | grep -q 'pool-of-threads';then + local eport=$(my_print_defaults -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--extra-port=" | cut -d= -f2) + if [[ -n $eport ]];then + # Xtrabackup works only locally. + # Hence, setting host to 127.0.0.1 unconditionally. + wsrep_log_info "SST through extra_port $eport" + INNOEXTRA+=" --host=127.0.0.1 --port=$eport " + use_socket=0 + else + wsrep_log_error "Extra port $eport null, failing" + exit 1 + fi + else + wsrep_log_info "Thread pool not set, ignore the option use_extra" + fi + fi + if [[ $use_socket -eq 1 ]] && [[ -n "${WSREP_SST_OPT_SOCKET}" ]];then + INNOEXTRA+=" --socket=${WSREP_SST_OPT_SOCKET}" + fi +} + +recv_joiner() +{ + local dir=$1 + local msg=$2 + local tmt=$3 + local ltcmd + + pushd ${dir} 1>/dev/null + set +e + + if [[ $tmt -gt 0 && -x `which timeout` ]];then + if timeout --help | grep -q -- '-k';then + ltcmd="timeout -k $(( tmt+10 )) $tmt $tcmd" + else + ltcmd="timeout $tmt $tcmd" + fi + timeit "$msg" "$ltcmd | $strmcmd; RC=( "\${PIPESTATUS[@]}" )" + else + timeit "$msg" "$tcmd | $strmcmd; RC=( "\${PIPESTATUS[@]}" )" + fi + + set -e + popd 1>/dev/null + + if [[ ${RC[0]} -eq 124 ]];then + wsrep_log_error "Possible timeout in receving first data from donor in gtid stage" + exit 32 + fi + + for ecode in "${RC[@]}";do + if [[ $ecode -ne 0 ]];then + wsrep_log_error "Error while getting data from donor node: " \ + "exit codes: ${RC[@]}" + exit 32 + fi + done + + if [ ! -r "${MAGIC_FILE}" ];then + # this message should cause joiner to abort + wsrep_log_error "xtrabackup process ended without creating '${MAGIC_FILE}'" + wsrep_log_info "Contents of datadir" + wsrep_log_info "$(ls -l ${dir}/*)" + exit 32 + fi +} + + +send_donor() +{ + local dir=$1 + local msg=$2 + + pushd ${dir} 1>/dev/null + set +e + timeit "$msg" "$strmcmd | $tcmd; RC=( "\${PIPESTATUS[@]}" )" + set -e + popd 1>/dev/null + + + for ecode in "${RC[@]}";do + if [[ $ecode -ne 0 ]];then + wsrep_log_error "Error while getting data from donor node: " \ + "exit codes: ${RC[@]}" + exit 32 + fi + done + +} + +if [[ ! -x `which $INNOBACKUPEX_BIN` ]];then + wsrep_log_error "innobackupex not in path: $PATH" + exit 2 +fi + +rm -f "${MAGIC_FILE}" + +if [[ ! ${WSREP_SST_OPT_ROLE} == 'joiner' && ! ${WSREP_SST_OPT_ROLE} == 'donor' ]];then + wsrep_log_error "Invalid role ${WSREP_SST_OPT_ROLE}" + exit 22 +fi + +read_cnf +setup_ports +get_stream +get_transfer + +if ${INNOBACKUPEX_BIN} /tmp --help | grep -q -- '--version-check'; then + disver="--no-version-check" +fi + + +INNOEXTRA="" +INNOAPPLY="${INNOBACKUPEX_BIN} $disver $iapts --apply-log \$rebuildcmd \${DATA} &>\${DATA}/innobackup.prepare.log" +INNOMOVE="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} $disver $impts --move-back --force-non-empty-directories \${DATA} &>\${DATA}/innobackup.move.log" +INNOBACKUP="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} $disver $iopts \$tmpopts \$INNOEXTRA --galera-info --stream=\$sfmt \$itmpdir 2>\${DATA}/innobackup.backup.log" + +if [ "$WSREP_SST_OPT_ROLE" = "donor" ] +then + trap cleanup_donor EXIT + + if [ $WSREP_SST_OPT_BYPASS -eq 0 ] + then + + if [[ -z $(parse_cnf mysqld tmpdir "") && -z $(parse_cnf xtrabackup tmpdir "") ]];then + xtmpdir=$(mktemp -d) + tmpopts=" --tmpdir=$xtmpdir " + wsrep_log_info "Using $xtmpdir as xtrabackup temporary directory" + fi + + itmpdir=$(mktemp -d) + wsrep_log_info "Using $itmpdir as innobackupex temporary directory" + + if [ "${AUTH[0]}" != "(null)" ]; then + INNOEXTRA+=" --user=${AUTH[0]}" + fi + + if [ ${#AUTH[*]} -eq 2 ]; then + INNOEXTRA+=" --password=${AUTH[1]}" + elif [ "${AUTH[0]}" != "(null)" ]; then + # Empty password, used for testing, debugging etc. + INNOEXTRA+=" --password=" + fi + + get_keys + if [[ $encrypt -eq 1 ]];then + if [[ -n $ekey ]];then + INNOEXTRA+=" --encrypt=$ealgo --encrypt-key=$ekey " + else + INNOEXTRA+=" --encrypt=$ealgo --encrypt-key-file=$ekeyfile " + fi + fi + + if [[ -n $lsn ]];then + INNOEXTRA+=" --incremental --incremental-lsn=$lsn " + fi + + check_extra + + wsrep_log_info "Streaming GTID file before SST" + + echo "${WSREP_SST_OPT_GTID}" > "${MAGIC_FILE}" + + ttcmd="$tcmd" + + if [[ $encrypt -eq 1 ]];then + if [[ -n $scomp ]];then + tcmd=" $ecmd | $scomp | $tcmd " + else + tcmd=" $ecmd | $tcmd " + fi + elif [[ -n $scomp ]];then + tcmd=" $scomp | $tcmd " + fi + + + send_donor $DATA "${stagemsg}-gtid" + + tcmd="$ttcmd" + if [[ -n $progress ]];then + get_footprint + tcmd="$pcmd | $tcmd" + elif [[ -n $rlimit ]];then + adjust_progress + tcmd="$pcmd | $tcmd" + fi + + wsrep_log_info "Sleeping before data transfer for SST" + sleep 10 + + wsrep_log_info "Streaming the backup to joiner at ${REMOTEIP} ${SST_PORT:-4444}" + + if [[ -n $scomp ]];then + tcmd="$scomp | $tcmd" + fi + + set +e + timeit "${stagemsg}-SST" "$INNOBACKUP | $tcmd; RC=( "\${PIPESTATUS[@]}" )" + set -e + + if [ ${RC[0]} -ne 0 ]; then + wsrep_log_error "${INNOBACKUPEX_BIN} finished with error: ${RC[0]}. " \ + "Check ${DATA}/innobackup.backup.log" + exit 22 + elif [[ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]];then + wsrep_log_error "$tcmd finished with error: ${RC[1]}" + exit 22 + fi + + # innobackupex implicitly writes PID to fixed location in $xtmpdir + XTRABACKUP_PID="$xtmpdir/xtrabackup_pid" + + + else # BYPASS FOR IST + + wsrep_log_info "Bypassing the SST for IST" + echo "continue" # now server can resume updating data + echo "${WSREP_SST_OPT_GTID}" > "${MAGIC_FILE}" + echo "1" > "${DATA}/${IST_FILE}" + get_keys + if [[ $encrypt -eq 1 ]];then + if [[ -n $scomp ]];then + tcmd=" $ecmd | $scomp | $tcmd " + else + tcmd=" $ecmd | $tcmd " + fi + elif [[ -n $scomp ]];then + tcmd=" $scomp | $tcmd " + fi + strmcmd+=" \${IST_FILE}" + + send_donor $DATA "${stagemsg}-IST" + + fi + + echo "done ${WSREP_SST_OPT_GTID}" + wsrep_log_info "Total time on donor: $totime seconds" + +elif [ "${WSREP_SST_OPT_ROLE}" = "joiner" ] +then + [[ -e $SST_PROGRESS_FILE ]] && wsrep_log_info "Stale sst_in_progress file: $SST_PROGRESS_FILE" + [[ -n $SST_PROGRESS_FILE ]] && touch $SST_PROGRESS_FILE + + if [[ $speciald -eq 1 ]];then + ib_home_dir=$(parse_cnf mysqld innodb-data-home-dir "") + ib_log_dir=$(parse_cnf mysqld innodb-log-group-home-dir "") + if [[ -z $ib_home_dir && -z $ib_log_dir ]];then + speciald=0 + fi + fi + + stagemsg="Joiner-Recv" + + if [[ ! -e ${DATA}/ibdata1 ]];then + incremental=0 + fi + + if [[ $incremental -eq 1 ]];then + wsrep_log_info "Incremental SST enabled: NOT SUPPORTED yet" + lsn=$(grep to_lsn xtrabackup_checkpoints | cut -d= -f2 | tr -d ' ') + wsrep_log_info "Recovered LSN: $lsn" + fi + + sencrypted=1 + nthreads=1 + + MODULE="xtrabackup_sst" + + rm -f "${DATA}/${IST_FILE}" + + # May need xtrabackup_checkpoints later on + rm -f ${DATA}/xtrabackup_binary ${DATA}/xtrabackup_galera_info ${DATA}/xtrabackup_logfile + + ADDR=${WSREP_SST_OPT_ADDR} + if [ -z "${SST_PORT}" ] + then + SST_PORT=4444 + ADDR="$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $1 }'):${SST_PORT}" + fi + + wait_for_listen ${SST_PORT} ${ADDR} ${MODULE} & + + trap sig_joiner_cleanup HUP PIPE INT TERM + trap cleanup_joiner EXIT + + if [[ -n $progress ]];then + adjust_progress + tcmd+=" | $pcmd" + fi + + if [[ $incremental -eq 1 ]];then + BDATA=$DATA + DATA=$(mktemp -d) + MAGIC_FILE="${DATA}/${INFO_FILE}" + fi + + get_keys + if [[ $encrypt -eq 1 && $sencrypted -eq 1 ]];then + if [[ -n $sdecomp ]];then + strmcmd=" $sdecomp | $ecmd | $strmcmd" + else + strmcmd=" $ecmd | $strmcmd" + fi + elif [[ -n $sdecomp ]];then + strmcmd=" $sdecomp | $strmcmd" + fi + + STATDIR=$(mktemp -d) + MAGIC_FILE="${STATDIR}/${INFO_FILE}" + recv_joiner $STATDIR "${stagemsg}-gtid" $stimeout + + if ! ps -p ${WSREP_SST_OPT_PARENT} &>/dev/null + then + wsrep_log_error "Parent mysqld process (PID:${WSREP_SST_OPT_PARENT}) terminated unexpectedly." + exit 32 + fi + + if [ ! -r "${STATDIR}/${IST_FILE}" ] + then + wsrep_log_info "Proceeding with SST" + + if [[ $speciald -eq 1 && -d ${DATA}/.sst ]];then + wsrep_log_info "WARNING: Stale temporary SST directory: ${DATA}/.sst from previous SST" + fi + + if [[ $incremental -ne 1 ]];then + if [[ $speciald -eq 1 ]];then + wsrep_log_info "Cleaning the existing datadir and innodb-data/log directories" + find $ib_home_dir $ib_log_dir $DATA -mindepth 1 -regex $cpat -prune -o -exec rm -rfv {} 1>&2 \+ + else + wsrep_log_info "Cleaning the existing datadir" + find $DATA -mindepth 1 -regex $cpat -prune -o -exec rm -rfv {} 1>&2 \+ + fi + tempdir=$(parse_cnf mysqld log-bin "") + if [[ -n ${tempdir:-} ]];then + binlog_dir=$(dirname $tempdir) + binlog_file=$(basename $tempdir) + if [[ -n ${binlog_dir:-} && $binlog_dir != '.' && $binlog_dir != $DATA ]];then + pattern="$binlog_dir/$binlog_file\.[0-9]+$" + wsrep_log_info "Cleaning the binlog directory $binlog_dir as well" + find $binlog_dir -maxdepth 1 -type f -regex $pattern -exec rm -fv {} 1>&2 \+ + rm $binlog_dir/*.index || true + fi + fi + + else + wsrep_log_info "Removing existing ib_logfile files" + rm -f ${BDATA}/ib_logfile* + fi + + + if [[ $speciald -eq 1 ]];then + mkdir -p ${DATA}/.sst + TDATA=${DATA} + DATA="${DATA}/.sst" + fi + + + MAGIC_FILE="${DATA}/${INFO_FILE}" + recv_joiner $DATA "${stagemsg}-SST" 0 + + get_proc + + # Rebuild indexes for compact backups + if grep -q 'compact = 1' ${DATA}/xtrabackup_checkpoints;then + wsrep_log_info "Index compaction detected" + rebuild=1 + fi + + if [[ $rebuild -eq 1 ]];then + nthreads=$(parse_cnf xtrabackup rebuild-threads $nproc) + wsrep_log_info "Rebuilding during prepare with $nthreads threads" + rebuildcmd="--rebuild-indexes --rebuild-threads=$nthreads" + fi + + if test -n "$(find ${DATA} -maxdepth 1 -type f -name '*.qp' -print -quit)";then + + wsrep_log_info "Compressed qpress files found" + + if [[ ! -x `which qpress` ]];then + wsrep_log_error "qpress not found in path: $PATH" + exit 22 + fi + + if [[ -n $progress ]] && pv --help | grep -q 'line-mode';then + count=$(find ${DATA} -type f -name '*.qp' | wc -l) + count=$(( count*2 )) + if pv --help | grep -q FORMAT;then + pvopts="-f -s $count -l -N Decompression -F '%N => Rate:%r Elapsed:%t %e Progress: [%b/$count]'" + else + pvopts="-f -s $count -l -N Decompression" + fi + pcmd="pv $pvopts" + adjust_progress + dcmd="$pcmd | xargs -n 2 qpress -T${nproc}d" + else + dcmd="xargs -n 2 qpress -T${nproc}d" + fi + + + # Decompress the qpress files + wsrep_log_info "Decompression with $nproc threads" + timeit "Joiner-Decompression" "find ${DATA} -type f -name '*.qp' -printf '%p\n%h\n' | $dcmd" + extcode=$? + + if [[ $extcode -eq 0 ]];then + wsrep_log_info "Removing qpress files after decompression" + find ${DATA} -type f -name '*.qp' -delete + if [[ $? -ne 0 ]];then + wsrep_log_error "Something went wrong with deletion of qpress files. Investigate" + fi + else + wsrep_log_error "Decompression failed. Exit code: $extcode" + exit 22 + fi + fi + + + if [[ ! -z $WSREP_SST_OPT_BINLOG ]];then + + BINLOG_DIRNAME=$(dirname $WSREP_SST_OPT_BINLOG) + BINLOG_FILENAME=$(basename $WSREP_SST_OPT_BINLOG) + + # To avoid comparing data directory and BINLOG_DIRNAME + mv $DATA/${BINLOG_FILENAME}.* $BINLOG_DIRNAME/ 2>/dev/null || true + + pushd $BINLOG_DIRNAME &>/dev/null + for bfiles in $(ls -1 ${BINLOG_FILENAME}.*);do + echo ${BINLOG_DIRNAME}/${bfiles} >> ${BINLOG_FILENAME}.index + done + popd &> /dev/null + + fi + + if [[ $incremental -eq 1 ]];then + # Added --ibbackup=xtrabackup_55 because it fails otherwise citing connection issues. + INNOAPPLY="${INNOBACKUPEX_BIN} $disver --defaults-file=${WSREP_SST_OPT_CONF} \ + --ibbackup=xtrabackup_56 --apply-log $rebuildcmd --redo-only $BDATA --incremental-dir=${DATA} &>>${BDATA}/innobackup.prepare.log" + fi + + wsrep_log_info "Preparing the backup at ${DATA}" + timeit "Xtrabackup prepare stage" "$INNOAPPLY" + + if [ $? -ne 0 ]; + then + wsrep_log_error "${INNOBACKUPEX_BIN} apply finished with errors. Check ${DATA}/innobackup.prepare.log" + exit 22 + fi + + if [[ $speciald -eq 1 ]];then + MAGIC_FILE="${TDATA}/${INFO_FILE}" + set +e + rm $TDATA/innobackup.prepare.log $TDATA/innobackup.move.log + set -e + wsrep_log_info "Moving the backup to ${TDATA}" + timeit "Xtrabackup move stage" "$INNOMOVE" + if [[ $? -eq 0 ]];then + 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 ${DATA}/innobackup.move.log for details" + fi + fi + + if [[ $incremental -eq 1 ]];then + wsrep_log_info "Cleaning up ${DATA} after incremental SST" + [[ -d ${DATA} ]] && rm -rf ${DATA} + DATA=$BDATA + fi + + else + 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" + exit 2 + fi + cat "${MAGIC_FILE}" # output UUID:seqno + wsrep_log_info "Total time on joiner: $totime seconds" +fi + +exit 0 diff --git a/scripts/wsrep_sst_xtrabackup.sh b/scripts/wsrep_sst_xtrabackup.sh new file mode 100644 index 00000000000..6b33eabee23 --- /dev/null +++ b/scripts/wsrep_sst_xtrabackup.sh @@ -0,0 +1,715 @@ +#!/bin/bash -ue +# Copyright (C) 2013 Percona Inc +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1301 USA. + +# Optional dependencies and options documented here: http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html +# Make sure to read that before proceeding! + + + + +. $(dirname $0)/wsrep_sst_common + +ealgo="" +ekey="" +ekeyfile="" +encrypt=0 +nproc=1 +ecode=0 +XTRABACKUP_PID="" +SST_PORT="" +REMOTEIP="" +tcert="" +tpem="" +sockopt="" +progress="" +ttime=0 +totime=0 +lsn="" +incremental=0 +ecmd="" +rlimit="" + +sfmt="tar" +strmcmd="" +tfmt="" +tcmd="" +rebuild=0 +rebuildcmd="" +payload=0 +pvformat="-F '%N => Rate:%r Avg:%a Elapsed:%t %e Bytes: %b %p' " +pvopts="-f -i 10 -N $WSREP_SST_OPT_ROLE " +uextra=0 + +if which pv &>/dev/null && pv --help | grep -q FORMAT;then + pvopts+=$pvformat +fi +pcmd="pv $pvopts" +declare -a RC + +INNOBACKUPEX_BIN=innobackupex +readonly AUTH=(${WSREP_SST_OPT_AUTH//:/ }) +DATA="${WSREP_SST_OPT_DATA}" +INFO_FILE="xtrabackup_galera_info" +IST_FILE="xtrabackup_ist" +MAGIC_FILE="${DATA}/${INFO_FILE}" + +# Setting the path for ss and ip +export PATH="/usr/sbin:/sbin:$PATH" + +timeit(){ + local stage=$1 + shift + local cmd="$@" + local x1 x2 took extcode + + if [[ $ttime -eq 1 ]];then + x1=$(date +%s) + wsrep_log_info "Evaluating $cmd" + eval "$cmd" + extcode=$? + x2=$(date +%s) + took=$(( x2-x1 )) + wsrep_log_info "NOTE: $stage took $took seconds" + totime=$(( totime+took )) + else + wsrep_log_info "Evaluating $cmd" + eval "$cmd" + extcode=$? + fi + return $extcode +} + +get_keys() +{ + if [[ $encrypt -eq 2 ]];then + return + fi + + if [[ $encrypt -eq 0 ]];then + if my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -q encrypt;then + wsrep_log_error "Unexpected option combination. SST may fail. Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html " + fi + return + fi + + if [[ $sfmt == 'tar' ]];then + wsrep_log_info "NOTE: Xtrabackup-based encryption - encrypt=1 - cannot be enabled with tar format" + encrypt=0 + return + fi + + wsrep_log_info "Xtrabackup based encryption enabled in my.cnf - Supported only from Xtrabackup 2.1.4" + + if [[ -z $ealgo ]];then + wsrep_log_error "FATAL: Encryption algorithm empty from my.cnf, bailing out" + exit 3 + fi + + if [[ -z $ekey && ! -r $ekeyfile ]];then + wsrep_log_error "FATAL: Either key or keyfile must be readable" + exit 3 + fi + + if [[ -z $ekey ]];then + ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key-file=$ekeyfile" + else + ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key=$ekey" + fi + + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + ecmd+=" -d" + fi +} + +get_transfer() +{ + if [[ -z $SST_PORT ]];then + TSST_PORT=4444 + else + TSST_PORT=$SST_PORT + fi + + if [[ $tfmt == 'nc' ]];then + if [[ ! -x `which nc` ]];then + wsrep_log_error "nc(netcat) not found in path: $PATH" + exit 2 + fi + wsrep_log_info "Using netcat as streamer" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + tcmd="nc -dl ${TSST_PORT}" + else + tcmd="nc ${REMOTEIP} ${TSST_PORT}" + fi + else + tfmt='socat' + wsrep_log_info "Using socat as streamer" + if [[ ! -x `which socat` ]];then + wsrep_log_error "socat not found in path: $PATH" + exit 2 + fi + + if [[ $encrypt -eq 2 ]] && ! socat -V | grep -q OPENSSL;then + wsrep_log_info "NOTE: socat is not openssl enabled, falling back to plain transfer" + encrypt=0 + fi + + if [[ $encrypt -eq 2 ]];then + wsrep_log_info "Using openssl based encryption with socat" + if [[ -z $tpem || -z $tcert ]];then + wsrep_log_error "Both PEM and CRT files required" + exit 22 + fi + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + wsrep_log_info "Decrypting with PEM $tpem, CA: $tcert" + tcmd="socat -u openssl-listen:${TSST_PORT},reuseaddr,cert=$tpem,cafile=${tcert}${sockopt} stdio" + else + wsrep_log_info "Encrypting with PEM $tpem, CA: $tcert" + tcmd="socat -u stdio openssl-connect:${REMOTEIP}:${TSST_PORT},cert=$tpem,cafile=${tcert}${sockopt}" + 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 + fi + fi + +} + +parse_cnf() +{ + local group=$1 + local var=$2 + reval=$(my_print_defaults -c $WSREP_SST_OPT_CONF $group | awk -F= '{if ($1 ~ /_/) { gsub(/_/,"-",$1); print $1"="$2 } else { print $0 }}' | grep -- "--$var=" | cut -d= -f2-) + if [[ -z $reval ]];then + [[ -n $3 ]] && reval=$3 + fi + echo $reval +} + +get_footprint() +{ + pushd $WSREP_SST_OPT_DATA 1>/dev/null + payload=$(find . -regex '.*\.ibd$\|.*\.MYI$\|.*\.MYD$\|.*ibdata1$' -type f -print0 | xargs -0 du --block-size=1 -c | awk 'END { print $1 }') + if my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -q -- "--compress";then + # QuickLZ has around 50% compression ratio + # When compression/compaction used, the progress is only an approximate. + payload=$(( payload*1/2 )) + fi + popd 1>/dev/null + pcmd+=" -s $payload" + adjust_progress +} + +adjust_progress() +{ + if [[ -n $progress && $progress != '1' ]];then + if [[ -e $progress ]];then + pcmd+=" 2>>$progress" + else + pcmd+=" 2>$progress" + fi + elif [[ -z $progress && -n $rlimit ]];then + # When rlimit is non-zero + pcmd="pv -q" + fi + + if [[ -n $rlimit && "$WSREP_SST_OPT_ROLE" == "donor" ]];then + wsrep_log_info "Rate-limiting SST to $rlimit" + pcmd+=" -L \$rlimit" + fi +} + +read_cnf() +{ + sfmt=$(parse_cnf sst streamfmt "tar") + tfmt=$(parse_cnf sst transferfmt "socat") + tcert=$(parse_cnf sst tca "") + tpem=$(parse_cnf sst tcert "") + encrypt=$(parse_cnf sst encrypt 0) + sockopt=$(parse_cnf sst sockopt "") + progress=$(parse_cnf sst progress "") + rebuild=$(parse_cnf sst rebuild 0) + ttime=$(parse_cnf sst time 0) + incremental=$(parse_cnf sst incremental 0) + ealgo=$(parse_cnf xtrabackup encrypt "") + ekey=$(parse_cnf xtrabackup encrypt-key "") + ekeyfile=$(parse_cnf xtrabackup encrypt-key-file "") + + # Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html + if [[ -z $ealgo ]];then + ealgo=$(parse_cnf sst encrypt-algo "") + ekey=$(parse_cnf sst encrypt-key "") + ekeyfile=$(parse_cnf sst encrypt-key-file "") + fi + rlimit=$(parse_cnf sst rlimit "") + uextra=$(parse_cnf sst use_extra 0) +} + +get_stream() +{ + if [[ $sfmt == 'xbstream' ]];then + wsrep_log_info "Streaming with xbstream" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + strmcmd="xbstream -x" + else + strmcmd="xbstream -c \${INFO_FILE} \${IST_FILE}" + fi + else + sfmt="tar" + wsrep_log_info "Streaming with tar" + if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then + strmcmd="tar xfi - --recursive-unlink -h" + else + strmcmd="tar cf - \${INFO_FILE} \${IST_FILE}" + fi + + fi +} + +get_proc() +{ + set +e + nproc=$(grep -c processor /proc/cpuinfo) + [[ -z $nproc || $nproc -eq 0 ]] && nproc=1 + set -e +} + +sig_joiner_cleanup() +{ + wsrep_log_error "Removing $MAGIC_FILE file due to signal" + 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" + fi + if [ "${WSREP_SST_OPT_ROLE}" = "joiner" ];then + wsrep_log_info "Removing the sst_in_progress file" + wsrep_cleanup_progress_file + fi + if [[ -n $progress && -p $progress ]];then + wsrep_log_info "Cleaning up fifo file $progress" + rm $progress + fi +} + +check_pid() +{ + local pid_file="$1" + [ -r "$pid_file" ] && ps -p $(cat "$pid_file") >/dev/null 2>&1 +} + +cleanup_donor() +{ + # Since this is invoked just after exit NNN + local estatus=$? + if [[ $estatus -ne 0 ]];then + wsrep_log_error "Cleanup after exit with status:$estatus" + fi + + if [[ -n $XTRABACKUP_PID ]];then + if check_pid $XTRABACKUP_PID + then + wsrep_log_error "xtrabackup process is still running. Killing... " + kill_xtrabackup + fi + + rm -f $XTRABACKUP_PID + fi + rm -f ${DATA}/${IST_FILE} + + if [[ -n $progress && -p $progress ]];then + wsrep_log_info "Cleaning up fifo file $progress" + rm $progress + fi +} + +kill_xtrabackup() +{ + local PID=$(cat $XTRABACKUP_PID) + [ -n "$PID" -a "0" != "$PID" ] && kill $PID && (kill $PID && kill -9 $PID) || : + rm -f "$XTRABACKUP_PID" +} + +setup_ports() +{ + if [[ "$WSREP_SST_OPT_ROLE" == "donor" ]];then + SST_PORT=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $2 }') + REMOTEIP=$(echo $WSREP_SST_OPT_ADDR | awk -F ':' '{ print $1 }') + lsn=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $4 }') + else + SST_PORT=$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $2 }') + fi +} + +# waits ~10 seconds for 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 + ss -p state listening "( sport = :$PORT )" | grep -qE 'socat|nc' && break + sleep 0.2 + done + if [[ $incremental -eq 1 ]];then + echo "ready ${ADDR}/${MODULE}/$lsn" + else + echo "ready ${ADDR}/${MODULE}" + fi +} + +check_extra() +{ + local use_socket=1 + if [[ $uextra -eq 1 ]];then + if my_print_defaults -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--thread-handling=" | grep -q 'pool-of-threads';then + local eport=$(my_print_defaults -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--extra-port=" | cut -d= -f2) + if [[ -n $eport ]];then + # Xtrabackup works only locally. + # Hence, setting host to 127.0.0.1 unconditionally. + wsrep_log_info "SST through extra_port $eport" + INNOEXTRA+=" --host=127.0.0.1 --port=$eport " + use_socket=0 + else + wsrep_log_error "Extra port $eport null, failing" + exit 1 + fi + else + wsrep_log_info "Thread pool not set, ignore the option use_extra" + fi + fi + if [[ $use_socket -eq 1 ]] && [[ -n "${WSREP_SST_OPT_SOCKET}" ]];then + INNOEXTRA+=" --socket=${WSREP_SST_OPT_SOCKET}" + fi +} + +if [[ ! -x `which innobackupex` ]];then + wsrep_log_error "innobackupex not in path: $PATH" + exit 2 +fi + +rm -f "${MAGIC_FILE}" + +if [[ ! ${WSREP_SST_OPT_ROLE} == 'joiner' && ! ${WSREP_SST_OPT_ROLE} == 'donor' ]];then + wsrep_log_error "Invalid role ${WSREP_SST_OPT_ROLE}" + exit 22 +fi + +read_cnf +setup_ports +get_stream +get_transfer + +INNOEXTRA="" +INNOAPPLY="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} --apply-log \$rebuildcmd \${DATA} &>\${DATA}/innobackup.prepare.log" +INNOBACKUP="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} \$INNOEXTRA --galera-info --stream=\$sfmt \${TMPDIR} 2>\${DATA}/innobackup.backup.log" + +if [ "$WSREP_SST_OPT_ROLE" = "donor" ] +then + trap cleanup_donor EXIT + + if [ $WSREP_SST_OPT_BYPASS -eq 0 ] + then + TMPDIR="${TMPDIR:-/tmp}" + + if [ "${AUTH[0]}" != "(null)" ]; then + INNOEXTRA+=" --user=${AUTH[0]}" + fi + + if [ ${#AUTH[*]} -eq 2 ]; then + INNOEXTRA+=" --password=${AUTH[1]}" + elif [ "${AUTH[0]}" != "(null)" ]; then + # Empty password, used for testing, debugging etc. + INNOEXTRA+=" --password=" + fi + + get_keys + if [[ $encrypt -eq 1 ]];then + if [[ -n $ekey ]];then + INNOEXTRA+=" --encrypt=$ealgo --encrypt-key=$ekey " + else + INNOEXTRA+=" --encrypt=$ealgo --encrypt-key-file=$ekeyfile " + fi + fi + + if [[ -n $lsn ]];then + INNOEXTRA+=" --incremental --incremental-lsn=$lsn " + fi + + check_extra + + wsrep_log_info "Streaming the backup to joiner at ${REMOTEIP} ${SST_PORT}" + + if [[ -n $progress ]];then + get_footprint + tcmd="$pcmd | $tcmd" + elif [[ -n $rlimit ]];then + adjust_progress + tcmd="$pcmd | $tcmd" + fi + + set +e + timeit "Donor-Transfer" "$INNOBACKUP | $tcmd; RC=( "\${PIPESTATUS[@]}" )" + set -e + + if [ ${RC[0]} -ne 0 ]; then + wsrep_log_error "${INNOBACKUPEX_BIN} finished with error: ${RC[0]}. " \ + "Check ${DATA}/innobackup.backup.log" + exit 22 + elif [[ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]];then + wsrep_log_error "$tcmd finished with error: ${RC[1]}" + exit 22 + fi + + # innobackupex implicitly writes PID to fixed location in ${TMPDIR} + XTRABACKUP_PID="${TMPDIR}/xtrabackup_pid" + + + else # BYPASS FOR IST + + wsrep_log_info "Bypassing the SST for IST" + STATE="${WSREP_SST_OPT_GTID}" + echo "continue" # now server can resume updating data + echo "${STATE}" > "${MAGIC_FILE}" + echo "1" > "${DATA}/${IST_FILE}" + get_keys + pushd ${DATA} 1>/dev/null + set +e + if [[ $encrypt -eq 1 ]];then + tcmd=" $ecmd | $tcmd" + fi + timeit "Donor-IST-Unencrypted-transfer" "$strmcmd | $tcmd; RC=( "\${PIPESTATUS[@]}" )" + set -e + popd 1>/dev/null + + for ecode in "${RC[@]}";do + if [[ $ecode -ne 0 ]];then + wsrep_log_error "Error while streaming data to joiner node: " \ + "exit codes: ${RC[@]}" + exit 1 + fi + done + fi + + echo "done ${WSREP_SST_OPT_GTID}" + wsrep_log_info "Total time on donor: $totime seconds" + +elif [ "${WSREP_SST_OPT_ROLE}" = "joiner" ] +then + [[ -e $SST_PROGRESS_FILE ]] && wsrep_log_info "Stale sst_in_progress file: $SST_PROGRESS_FILE" + touch $SST_PROGRESS_FILE + + if [[ ! -e ${DATA}/ibdata1 ]];then + incremental=0 + fi + + if [[ $incremental -eq 1 ]];then + wsrep_log_info "Incremental SST enabled" + #lsn=$(/pxc/bin/mysqld --defaults-file=$WSREP_SST_OPT_CONF --basedir=/pxc --wsrep-recover 2>&1 | grep -o 'log sequence number .*' | cut -d " " -f 4 | head -1) + lsn=$(grep to_lsn xtrabackup_checkpoints | cut -d= -f2 | tr -d ' ') + wsrep_log_info "Recovered LSN: $lsn" + fi + + sencrypted=1 + nthreads=1 + + MODULE="xtrabackup_sst" + + # May need xtrabackup_checkpoints later on + rm -f ${DATA}/xtrabackup_binary ${DATA}/xtrabackup_galera_info ${DATA}/xtrabackup_logfile + + ADDR=${WSREP_SST_OPT_ADDR} + if [ -z "${SST_PORT}" ] + then + SST_PORT=4444 + ADDR="$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $1 }'):${SST_PORT}" + fi + + wait_for_listen ${SST_PORT} ${ADDR} ${MODULE} & + + trap sig_joiner_cleanup HUP PIPE INT TERM + trap cleanup_joiner EXIT + + if [[ -n $progress ]];then + adjust_progress + tcmd+=" | $pcmd" + fi + + if [[ $incremental -eq 1 ]];then + BDATA=$DATA + DATA=$(mktemp -d) + MAGIC_FILE="${DATA}/${INFO_FILE}" + fi + + get_keys + set +e + if [[ $encrypt -eq 1 && $sencrypted -eq 1 ]];then + strmcmd=" $ecmd | $strmcmd" + fi + + pushd ${DATA} 1>/dev/null + timeit "Joiner-Recv-Unencrypted" "$tcmd | $strmcmd; RC=( "\${PIPESTATUS[@]}" )" + popd 1>/dev/null + + set -e + + if [[ $sfmt == 'xbstream' ]];then + # Special handling till lp:1193240 is fixed" + if [[ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]];then + wsrep_log_error "Xbstream failed" + wsrep_log_error "Data directory ${DATA} may not be empty: lp:1193240" \ + "Manual intervention required in that case" + exit 32 + fi + fi + + wait %% # join for wait_for_listen thread + + for ecode in "${RC[@]}";do + if [[ $ecode -ne 0 ]];then + wsrep_log_error "Error while getting data from donor node: " \ + "exit codes: ${RC[@]}" + exit 32 + fi + done + + if [ ! -r "${MAGIC_FILE}" ] + then + # this message should cause joiner to abort + wsrep_log_error "xtrabackup process ended without creating '${MAGIC_FILE}'" + wsrep_log_info "Contents of datadir" + wsrep_log_info "$(ls -l ${DATA}/**/*)" + exit 32 + fi + + if ! ps -p ${WSREP_SST_OPT_PARENT} &>/dev/null + then + wsrep_log_error "Parent mysqld process (PID:${WSREP_SST_OPT_PARENT}) terminated unexpectedly." + exit 32 + fi + + if [ ! -r "${DATA}/${IST_FILE}" ] + then + wsrep_log_info "Proceeding with SST" + wsrep_log_info "Removing existing ib_logfile files" + if [[ $incremental -ne 1 ]];then + rm -f ${DATA}/ib_logfile* + else + rm -f ${BDATA}/ib_logfile* + fi + + get_proc + + # Rebuild indexes for compact backups + if grep -q 'compact = 1' ${DATA}/xtrabackup_checkpoints;then + wsrep_log_info "Index compaction detected" + rebuild=1 + fi + + if [[ $rebuild -eq 1 ]];then + nthreads=$(parse_cnf xtrabackup rebuild-threads $nproc) + wsrep_log_info "Rebuilding during prepare with $nthreads threads" + rebuildcmd="--rebuild-indexes --rebuild-threads=$nthreads" + fi + + if test -n "$(find ${DATA} -maxdepth 1 -type f -name '*.qp' -print -quit)";then + + wsrep_log_info "Compressed qpress files found" + + if [[ ! -x `which qpress` ]];then + wsrep_log_error "qpress not found in path: $PATH" + exit 22 + fi + + if [[ -n $progress ]] && pv --help | grep -q 'line-mode';then + count=$(find ${DATA} -type f -name '*.qp' | wc -l) + count=$(( count*2 )) + if pv --help | grep -q FORMAT;then + pvopts="-f -s $count -l -N Decompression -F '%N => Rate:%r Elapsed:%t %e Progress: [%b/$count]'" + else + pvopts="-f -s $count -l -N Decompression" + fi + pcmd="pv $pvopts" + adjust_progress + dcmd="$pcmd | xargs -n 2 qpress -T${nproc}d" + else + dcmd="xargs -n 2 qpress -T${nproc}d" + fi + + wsrep_log_info "Removing existing ibdata1 file" + rm -f ${DATA}/ibdata1 + + # Decompress the qpress files + wsrep_log_info "Decompression with $nproc threads" + timeit "Decompression" "find ${DATA} -type f -name '*.qp' -printf '%p\n%h\n' | $dcmd" + extcode=$? + + if [[ $extcode -eq 0 ]];then + wsrep_log_info "Removing qpress files after decompression" + find ${DATA} -type f -name '*.qp' -delete + if [[ $? -ne 0 ]];then + wsrep_log_error "Something went wrong with deletion of qpress files. Investigate" + fi + else + wsrep_log_error "Decompression failed. Exit code: $extcode" + exit 22 + fi + fi + + if [[ $incremental -eq 1 ]];then + # Added --ibbackup=xtrabackup_55 because it fails otherwise citing connection issues. + INNOAPPLY="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} \ + --ibbackup=xtrabackup_55 --apply-log $rebuildcmd --redo-only $BDATA --incremental-dir=${DATA} &>>${BDATA}/innobackup.prepare.log" + fi + + wsrep_log_info "Preparing the backup at ${DATA}" + timeit "Xtrabackup prepare stage" "$INNOAPPLY" + + if [[ $incremental -eq 1 ]];then + wsrep_log_info "Cleaning up ${DATA} after incremental SST" + [[ -d ${DATA} ]] && rm -rf ${DATA} + DATA=$BDATA + fi + + if [ $? -ne 0 ]; + then + wsrep_log_error "${INNOBACKUPEX_BIN} finished with errors. Check ${DATA}/innobackup.prepare.log" + exit 22 + fi + else + 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" + exit 2 + fi + + cat "${MAGIC_FILE}" # output UUID:seqno + wsrep_log_info "Total time on joiner: $totime seconds" +fi + +exit 0 diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 1eb8dc7cdd6..803e14988d2 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -13,6 +13,25 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +IF(WITH_WSREP AND NOT EMBEDDED_LIBRARY) + BUILD_WITH_WSREP() + SET(WSREP_INCLUDES ${CMAKE_SOURCE_DIR}/wsrep) + SET(WSREP_SOURCES + wsrep_check_opts.cc + wsrep_hton.cc + wsrep_mysqld.cc + wsrep_notify.cc + wsrep_sst.cc + wsrep_utils.cc + wsrep_var.cc + wsrep_binlog.cc + wsrep_applier.cc + wsrep_thd.cc + ) + SET(WSREP_LIB wsrep) +ENDIF() + INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/sql @@ -20,6 +39,7 @@ ${PCRE_INCLUDES} ${ZLIB_INCLUDE_DIR} ${SSL_INCLUDE_DIRS} ${CMAKE_BINARY_DIR}/sql +${WSREP_INCLUDES} ) SET(GEN_SOURCES @@ -91,6 +111,7 @@ SET (SQL_SOURCE ../sql-common/mysql_async.c my_apc.cc my_apc.h rpl_gtid.cc rpl_parallel.cc + ${WSREP_SOURCES} table_cache.cc ${CMAKE_CURRENT_BINARY_DIR}/sql_builtin.cc ${GEN_SOURCES} @@ -112,6 +133,7 @@ DTRACE_INSTRUMENT(sql) TARGET_LINK_LIBRARIES(sql ${MYSQLD_STATIC_PLUGIN_LIBS} mysys mysys_ssl dbug strings vio pcre ${LIBJEMALLOC} ${LIBWRAP} ${LIBCRYPT} ${LIBDL} ${CMAKE_THREAD_LIBS_INIT} + ${WSREP_LIB} ${SSL_LIBRARIES}) IF(WIN32) diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc index d65180a60be..26d2e1ef985 100644 --- a/sql/event_data_objects.cc +++ b/sql/event_data_objects.cc @@ -1472,8 +1472,25 @@ end: bool save_tx_read_only= thd->tx_read_only; thd->tx_read_only= false; +#ifdef WITH_WSREP + if (WSREP(thd)) + { + // sql_print_information("sizeof(LEX) = %d", sizeof(struct LEX)); + // sizeof(LEX) = 4512, so it's relatively safe to allocate it on stack. + LEX lex; + LEX* saved = thd->lex; + lex.sql_command = SQLCOM_DROP_EVENT; + thd->lex = &lex; + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); + thd->lex = saved; + } +#endif + ret= Events::drop_event(thd, dbname, name, FALSE); + WSREP_TO_ISOLATION_END; + + error: thd->tx_read_only= save_tx_read_only; thd->security_ctx->master_access= saved_master_access; } diff --git a/sql/events.cc b/sql/events.cc index 63627b21777..725a7613e69 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -1128,7 +1128,20 @@ Events::load_events_from_db(THD *thd) delete et; goto end; } - +#ifdef WITH_WSREP + // when SST from master node who initials event, the event status is ENABLED + // this is problematic because there are two nodes with same events and both enabled. + if (WSREP(thd) && et->originator != thd->variables.server_id) + { + store_record(table, record[1]); + table->field[ET_FIELD_STATUS]-> + store((longlong) Event_parse_data::SLAVESIDE_DISABLED, + TRUE); + (void) table->file->ha_update_row(table->record[1], table->record[0]); + delete et; + continue; + } +#endif /** Since the Event_queue_element object could be deleted inside Event_queue::create_event we should save the value of dropped flag @@ -1174,6 +1187,47 @@ end: DBUG_RETURN(ret); } +#ifdef WITH_WSREP +int wsrep_create_event_query(THD *thd, uchar** buf, size_t* buf_len) +{ + char buffer[1024]; + String log_query(buffer, sizeof(buffer), &my_charset_bin); + + if (create_query_string(thd, &log_query)) + { + WSREP_WARN("events create string failed: %s", thd->query()); + return 1; + } + return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(), buf, buf_len); +} +static int +wsrep_alter_query_string(THD *thd, String *buf) +{ + /* Append the "ALTER" part of the query */ + if (buf->append(STRING_WITH_LEN("ALTER "))) + return 1; + /* Append definer */ + append_definer(thd, buf, &(thd->lex->definer->user), &(thd->lex->definer->host)); + /* Append the left part of thd->query after event name part */ + if (buf->append(thd->lex->stmt_definition_begin, + thd->lex->stmt_definition_end - + thd->lex->stmt_definition_begin)) + return 1; + + return 0; +} +int wsrep_alter_event_query(THD *thd, uchar** buf, size_t* buf_len) +{ + String log_query; + + if (wsrep_alter_query_string(thd, &log_query)) + { + WSREP_WARN("events alter string failed: %s", thd->query()); + return 1; + } + return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(), buf, buf_len); +} +#endif /* WITH_WSREP */ /** @} (End of group Event_Scheduler) */ diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index f503b2f54e5..23af3825756 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -388,6 +388,15 @@ const char *ha_partition::table_type() const } +#if defined(WITH_WSREP) && !defined(EMBEDDED_LIBRARY) +int ha_partition::wsrep_db_type() const +{ + // we can do this since we only support a single engine type + return partition_ht()->db_type; +} +#endif /* WITH_WSREP && !EMBEDDED_LIBRARY */ + + /* Destructor method diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 71ae84b06a0..c3c72394374 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -1282,7 +1282,9 @@ public: DBUG_ASSERT(h == m_file[i]->ht); return h; } - +#if defined(WITH_WSREP) && !defined(EMBEDDED_LIBRARY) + virtual int wsrep_db_type() const; +#endif /* WITH_WSREP && !EMBEDDED_LIBRARY */ friend int cmp_key_rowid_part_id(void *ptr, uchar *ref1, uchar *ref2); }; diff --git a/sql/handler.cc b/sql/handler.cc index 56e7da6430d..63ddb9c6d6e 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -50,6 +50,9 @@ #include "../storage/maria/ha_maria.h" #endif +#include "wsrep_mysqld.h" +#include "wsrep.h" + /* While we have legacy_db_type, we have this array to check for dups and to find handlerton from legacy_db_type. @@ -1165,10 +1168,25 @@ int ha_prepare(THD *thd) { if ((err= ht->prepare(ht, thd, all))) { - my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); - ha_rollback_trans(thd, all); - error=1; - break; +#ifdef WITH_WSREP + if (ht == wsrep_hton) + { + error= 1; + /* avoid sending error, if we need to replay */ + if (thd->wsrep_conflict_state!= MUST_REPLAY) + { + my_error(ER_LOCK_DEADLOCK, MYF(0), err); + } + } + else +#endif + { + /* not wsrep hton, bail to native mysql behavior */ + my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); + ha_rollback_trans(thd, all); + error=1; + break; + } } } else @@ -1366,8 +1384,9 @@ int ha_commit_trans(THD *thd, bool all) mdl_request.init(MDL_key::COMMIT, "", "", MDL_INTENTION_EXCLUSIVE, MDL_EXPLICIT); - if (thd->mdl_context.acquire_lock(&mdl_request, - thd->variables.lock_wait_timeout)) + if (IF_WSREP(!WSREP(thd),1) && + thd->mdl_context.acquire_lock(&mdl_request, + thd->variables.lock_wait_timeout)) { ha_rollback_trans(thd, all); thd->wakeup_subsequent_commits(1); @@ -1414,8 +1433,28 @@ int ha_commit_trans(THD *thd, bool all) err= ht->prepare(ht, thd, all); status_var_increment(thd->status_var.ha_prepare_count); if (err) - my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); - + { +#ifdef WITH_WSREP + if (ht == wsrep_hton) + { + switch (err) { + case WSREP_TRX_SIZE_EXCEEDED: + /* give user size exeeded error from wsrep_api.h */ + my_error(ER_ERROR_DURING_COMMIT, MYF(0), WSREP_SIZE_EXCEEDED); + break; + case WSREP_TRX_CERT_FAIL: + case WSREP_TRX_ERROR: + /* avoid sending error, if we need to replay */ + if (thd->wsrep_conflict_state!= MUST_REPLAY) + { + my_error(ER_LOCK_DEADLOCK, MYF(0), err); + } + } + goto err; + } +#endif /* WITH_WSREP */ + my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); + } if (err) goto err; @@ -1425,6 +1464,14 @@ int ha_commit_trans(THD *thd, bool all) DEBUG_SYNC(thd, "ha_commit_trans_after_prepare"); DBUG_EXECUTE_IF("crash_commit_after_prepare", DBUG_SUICIDE();); +#ifdef WITH_WSREP + if (!error && WSREP_ON && wsrep_is_wsrep_xid(&thd->transaction.xid_state.xid)) + { + // xid was rewritten by wsrep + xid= wsrep_xid_seqno(&thd->transaction.xid_state.xid); + } +#endif // WITH_WSREP + if (!is_real_trans) { error= commit_one_phase_2(thd, all, trans, is_real_trans); @@ -1801,7 +1848,10 @@ static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin, got, hton_name(hton)->str); for (int i=0; i < got; i ++) { - my_xid x=info->list[i].get_my_xid(); + my_xid x= IF_WSREP(WSREP_ON && wsrep_is_wsrep_xid(&info->list[i]) ? + wsrep_xid_seqno(&info->list[i]) : + info->list[i].get_my_xid(), + info->list[i].get_my_xid()); if (!x) // not "mine" - that is generated by external TM { #ifndef DBUG_OFF @@ -3086,10 +3136,12 @@ int handler::update_auto_increment() variables->auto_increment_increment); auto_inc_intervals_count++; /* Row-based replication does not need to store intervals in binlog */ - if (mysql_bin_log.is_open() && !thd->is_current_stmt_binlog_format_row()) - thd->auto_inc_intervals_in_cur_stmt_for_binlog.append(auto_inc_interval_for_cur_row.minimum(), - auto_inc_interval_for_cur_row.values(), - variables->auto_increment_increment); + if (IF_WSREP(((WSREP(thd) && wsrep_emulate_bin_log ) || mysql_bin_log.is_open()), mysql_bin_log.is_open()) + && !thd->is_current_stmt_binlog_format_row()) + thd->auto_inc_intervals_in_cur_stmt_for_binlog. + append(auto_inc_interval_for_cur_row.minimum(), + auto_inc_interval_for_cur_row.values(), + variables->auto_increment_increment); } /* @@ -5707,7 +5759,10 @@ static bool check_table_binlog_row_based(THD *thd, TABLE *table) return (thd->is_current_stmt_binlog_format_row() && table->s->cached_row_logging_check && (thd->variables.option_bits & OPTION_BIN_LOG) && - mysql_bin_log.is_open()); + /* applier and replayer should not binlog */ + (IF_WSREP((WSREP_EMULATE_BINLOG(thd) && + (thd->wsrep_exec_mode != REPL_RECV)) || + mysql_bin_log.is_open(), mysql_bin_log.is_open()))); } @@ -5807,6 +5862,12 @@ static int binlog_log_row(TABLE* table, bool error= 0; THD *const thd= table->in_use; +#ifdef WITH_WSREP + /* only InnoDB tables will be replicated through binlog emulation */ + if (WSREP_EMULATE_BINLOG(thd) && + table->file->partition_ht()->db_type != DB_TYPE_INNODB) + return 0; +#endif /* WITH_WSREP */ if (check_table_binlog_row_based(thd, table)) { MY_BITMAP cols; @@ -6136,6 +6197,76 @@ void handler::set_lock_type(enum thr_lock_type lock) table->reginfo.lock_type= lock; } +#ifdef WITH_WSREP +/** + @details + This function makes the storage engine to force the victim transaction + to abort. Currently, only innodb has this functionality, but any SE + implementing the wsrep API should provide this service to support + multi-master operation. + + @param bf_thd brute force THD asking for the abort + @param victim_thd victim THD to be aborted + + @return + always 0 +*/ + +int ha_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal) +{ + DBUG_ENTER("ha_abort_transaction"); + if (!WSREP(bf_thd) && + !(wsrep_OSU_method_options == WSREP_OSU_RSU && + bf_thd->wsrep_exec_mode == TOTAL_ORDER)) { + DBUG_RETURN(0); + } + + THD_TRANS *trans= &victim_thd->transaction.all; + Ha_trx_info *ha_info= trans->ha_list, *ha_info_next; + + for (; ha_info; ha_info= ha_info_next) + { + handlerton *hton= ha_info->ht(); + if (!hton->abort_transaction) + { + WSREP_WARN("cannot abort transaction"); + } + else + hton->abort_transaction(hton, bf_thd, victim_thd, signal); + ha_info_next= ha_info->next(); + ha_info->reset(); /* keep it conveniently zero-filled */ + } + DBUG_RETURN(0); +} + +void ha_fake_trx_id(THD *thd) +{ + DBUG_ENTER("ha_fake_trx_id"); + if (!WSREP(thd)) + { + DBUG_VOID_RETURN; + } + + THD_TRANS *trans= &thd->transaction.all; + Ha_trx_info *ha_info= trans->ha_list, *ha_info_next; + + for (; ha_info; ha_info= ha_info_next) + { + handlerton *hton= ha_info->ht(); + if (!hton->fake_trx_id) + { + WSREP_WARN("cannot get fake InnoDB transaction ID"); + } + else + hton->fake_trx_id(hton, thd); + ha_info_next= ha_info->next(); + ha_info->reset(); /* keep it conveniently zero-filled */ + } + DBUG_VOID_RETURN; +} +#endif /* WITH_WSREP */ + + #ifdef TRANS_LOG_MGM_EXAMPLE_CODE /* Example of transaction log management functions based on assumption that logs diff --git a/sql/handler.h b/sql/handler.h index 1e4fe5557b6..169ed209403 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1230,6 +1230,11 @@ struct handlerton enum handler_create_iterator_result (*create_iterator)(handlerton *hton, enum handler_iterator_type type, struct handler_iterator *fill_this_in); + int (*abort_transaction)(handlerton *hton, THD *bf_thd, + THD *victim_thd, my_bool signal); + int (*set_checkpoint)(handlerton *hton, const XID* xid); + int (*get_checkpoint)(handlerton *hton, XID* xid); + void (*fake_trx_id)(handlerton *hton, THD *thd); /* Optional clauses in the CREATE/ALTER TABLE */ @@ -3962,6 +3967,9 @@ bool key_uses_partial_cols(TABLE_SHARE *table, uint keyno); extern const char *ha_row_type[]; extern MYSQL_PLUGIN_IMPORT const char *tx_isolation_names[]; extern MYSQL_PLUGIN_IMPORT const char *binlog_format_names[]; +#ifdef WITH_WSREP +extern MYSQL_PLUGIN_IMPORT const char *wsrep_binlog_format_names[]; +#endif /* WITH_WSREP */ extern TYPELIB tx_isolation_typelib; extern const char *myisam_stats_method_names[]; extern ulong total_ha, total_ha_2pc; @@ -4080,6 +4088,10 @@ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv); bool ha_rollback_to_savepoint_can_release_mdl(THD *thd); int ha_savepoint(THD *thd, SAVEPOINT *sv); int ha_release_savepoint(THD *thd, SAVEPOINT *sv); +#ifdef WITH_WSREP +int ha_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal); +void ha_fake_trx_id(THD *thd); +#endif /* WITH_WSREP */ /* these are called by storage engines */ void trans_register_ha(THD *thd, bool all, handlerton *ht); @@ -4110,6 +4122,9 @@ int ha_binlog_end(THD *thd); #define ha_binlog_wait(a) do {} while (0) #define ha_binlog_end(a) do {} while (0) #endif +#ifdef WITH_WSREP +void wsrep_brute_force_aborts(); +#endif const char *get_canonical_filename(handler *file, const char *path, char *tmp_path); diff --git a/sql/item_func.cc b/sql/item_func.cc index ccb7ec56021..13803cff2d6 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2769,7 +2769,19 @@ void Item_func_rand::seed_random(Item *arg) TODO: do not do reinit 'rand' for every execute of PS/SP if args[0] is a constant. */ - uint32 tmp= (uint32) arg->val_int(); + uint32 tmp; +#ifdef WITH_WSREP + if (WSREP(current_thd)) + { + if (current_thd->wsrep_exec_mode==REPL_RECV) + tmp= current_thd->wsrep_rand; + else + tmp= current_thd->wsrep_rand= (uint32) arg->val_int(); + } + else +#endif /* WITH_WSREP */ + tmp= (uint32) arg->val_int(); + my_rnd_init(rand, (uint32) (tmp*0x10001L+55555555L), (uint32) (tmp*0x10000001L)); } diff --git a/sql/lock.cc b/sql/lock.cc index 54c7720e750..a74a12c41c3 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -83,6 +83,7 @@ #include "sql_acl.h" // SUPER_ACL #include #include +#include "wsrep_mysqld.h" /** @defgroup Locking Locking @@ -314,6 +315,7 @@ bool mysql_lock_tables(THD *thd, MYSQL_LOCK *sql_lock, uint flags) /* Copy the lock data array. thr_multi_lock() reorders its contents. */ memmove(sql_lock->locks + sql_lock->lock_count, sql_lock->locks, sql_lock->lock_count * sizeof(*sql_lock->locks)); + /* Lock on the copied half of the lock data array. */ rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks + sql_lock->lock_count, @@ -329,7 +331,10 @@ end: { thd->send_kill_message(); if (!rc) + { mysql_unlock_tables(thd, sql_lock, 0); + THD_STAGE_INFO(thd, stage_after_table_lock); + } rc= 1; } else if (rc > 1) @@ -380,6 +385,8 @@ static int lock_external(THD *thd, TABLE **tables, uint count) void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock) { DBUG_ENTER("mysql_unlock_tables"); + THD_STAGE_INFO(thd, stage_unlocking_tables); + if (sql_lock->table_count) unlock_external(thd, sql_lock->table, sql_lock->table_count); if (sql_lock->lock_count) @@ -1052,6 +1059,13 @@ void Global_read_lock::unlock_global_read_lock(THD *thd) { thd->mdl_context.release_lock(m_mdl_blocks_commits_lock); m_mdl_blocks_commits_lock= NULL; +#ifdef WITH_WSREP + if (WSREP_ON) + { + wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED; + wsrep->resume(wsrep); + } +#endif /* WITH_WSREP */ } thd->mdl_context.release_lock(m_mdl_global_shared_lock); m_mdl_global_shared_lock= NULL; @@ -1084,9 +1098,22 @@ bool Global_read_lock::make_global_read_lock_block_commit(THD *thd) If we didn't succeed lock_global_read_lock(), or if we already suceeded make_global_read_lock_block_commit(), do nothing. */ + if (m_state != GRL_ACQUIRED) DBUG_RETURN(0); +#ifdef WITH_WSREP + if (WSREP_ON && m_mdl_blocks_commits_lock) + { + WSREP_DEBUG("GRL was in block commit mode when entering " + "make_global_read_lock_block_commit"); + thd->mdl_context.release_lock(m_mdl_blocks_commits_lock); + m_mdl_blocks_commits_lock= NULL; + wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED; + wsrep->resume(wsrep); + } +#endif /* WITH_WSREP */ + mdl_request.init(MDL_key::COMMIT, "", "", MDL_SHARED, MDL_EXPLICIT); if (thd->mdl_context.acquire_lock(&mdl_request, @@ -1096,6 +1123,25 @@ bool Global_read_lock::make_global_read_lock_block_commit(THD *thd) m_mdl_blocks_commits_lock= mdl_request.ticket; m_state= GRL_ACQUIRED_AND_BLOCKS_COMMIT; +#ifdef WITH_WSREP + if (WSREP_ON) + { + long long ret = wsrep->pause(wsrep); + if (ret >= 0) + { + wsrep_locked_seqno= ret; + } + else if (ret != -ENOSYS) /* -ENOSYS - no provider */ + { + WSREP_ERROR("Failed to pause provider: %lld (%s)", -ret, strerror(-ret)); + + DBUG_ASSERT(m_mdl_blocks_commits_lock == NULL); + wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED; + my_error(ER_LOCK_DEADLOCK, MYF(0)); + DBUG_RETURN(TRUE); + } + } +#endif /* WITH_WSREP */ DBUG_RETURN(FALSE); } diff --git a/sql/log.cc b/sql/log.cc index 75a895e25f8..371f9c06cce 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -52,9 +52,11 @@ #include "sql_plugin.h" #include "rpl_handler.h" +#include "wsrep_mysqld.h" #include "debug_sync.h" #include "sql_show.h" #include "my_pthread.h" +#include "wsrep_mysqld.h" /* max size of the log message */ #define MAX_LOG_BUFFER_SIZE 1024 @@ -63,6 +65,7 @@ #define FLAGSTR(V,F) ((V)&(F)?#F" ":"") +handlerton *binlog_hton; LOGGER logger; MYSQL_BIN_LOG mysql_bin_log(&sync_binlog_period); @@ -511,8 +514,6 @@ private: binlog_cache_mngr(const binlog_cache_mngr& info); }; -handlerton *binlog_hton; - bool LOGGER::is_log_table_enabled(uint log_table_type) { switch (log_table_type) { @@ -526,7 +527,6 @@ bool LOGGER::is_log_table_enabled(uint log_table_type) } } - /** Check if a given table is opened log table @@ -1577,7 +1577,8 @@ binlog_trans_log_savepos(THD *thd, my_off_t *pos) DBUG_ENTER("binlog_trans_log_savepos"); DBUG_ASSERT(pos != NULL); binlog_cache_mngr *const cache_mngr= thd->binlog_setup_trx_data(); - DBUG_ASSERT(mysql_bin_log.is_open()); + DBUG_ASSERT_IF_WSREP(((WSREP(thd) && wsrep_emulate_bin_log)) || mysql_bin_log.is_open()); + DBUG_ASSERT(IF_WSREP(1, mysql_bin_log.is_open())); *pos= cache_mngr->trx_cache.get_byte_position(); DBUG_PRINT("return", ("*pos: %lu", (ulong) *pos)); DBUG_VOID_RETURN; @@ -1625,7 +1626,8 @@ binlog_trans_log_truncate(THD *thd, my_off_t pos) int binlog_init(void *p) { binlog_hton= (handlerton *)p; - binlog_hton->state=opt_bin_log ? SHOW_OPTION_YES : SHOW_OPTION_NO; + binlog_hton->state=IF_WSREP(WSREP_ON || opt_bin_log, opt_bin_log) ? + SHOW_OPTION_YES : SHOW_OPTION_NO; binlog_hton->db_type=DB_TYPE_BINLOG; binlog_hton->savepoint_offset= sizeof(my_off_t); binlog_hton->close_connection= binlog_close_connection; @@ -1745,6 +1747,16 @@ binlog_commit_flush_stmt_cache(THD *thd, bool all, binlog_cache_mngr *cache_mngr) { DBUG_ENTER("binlog_commit_flush_stmt_cache"); +#ifdef WITH_WSREP + if (thd->wsrep_mysql_replicated > 0) + { + DBUG_ASSERT(WSREP_ON); + WSREP_DEBUG("avoiding binlog_commit_flush_trx_cache: %d", + thd->wsrep_mysql_replicated); + return 0; + } +#endif + Query_log_event end_evt(thd, STRING_WITH_LEN("COMMIT"), FALSE, TRUE, TRUE, 0); DBUG_RETURN(binlog_flush_cache(thd, cache_mngr, &end_evt, all, TRUE, FALSE)); @@ -1900,12 +1912,12 @@ static bool trans_cannot_safely_rollback(THD *thd, bool all) return ((thd->variables.option_bits & OPTION_KEEP_LOG) || (trans_has_updated_non_trans_table(thd) && - thd->variables.binlog_format == BINLOG_FORMAT_STMT) || + WSREP_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_STMT) || (cache_mngr->trx_cache.changes_to_non_trans_temp_table() && - thd->variables.binlog_format == BINLOG_FORMAT_MIXED) || + WSREP_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_MIXED) || (trans_has_updated_non_trans_table(thd) && ending_single_stmt_trans(thd,all) && - thd->variables.binlog_format == BINLOG_FORMAT_MIXED)); + WSREP_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_MIXED)); } @@ -1927,6 +1939,13 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all) DBUG_ENTER("binlog_commit"); binlog_cache_mngr *const cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); +#ifdef WITH_WSREP + if (!cache_mngr) + { + DBUG_ASSERT(WSREP(thd)); + DBUG_RETURN(0); + } +#endif /* WITH_WSREP */ DBUG_PRINT("debug", ("all: %d, in_transaction: %s, all.modified_non_trans_table: %s, stmt.modified_non_trans_table: %s", @@ -1983,6 +2002,14 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) int error= 0; binlog_cache_mngr *const cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); +#ifdef WITH_WSREP + if (!cache_mngr) + { + DBUG_ASSERT(WSREP(thd)); + DBUG_RETURN(0); + } + +#endif /* WITH_WSREP */ DBUG_PRINT("debug", ("all: %s, all.modified_non_trans_table: %s, stmt.modified_non_trans_table: %s", YESNO(all), @@ -2011,8 +2038,8 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) cache_mngr->reset(false, true); DBUG_RETURN(error); } - - if (mysql_bin_log.check_write_error(thd)) + if (IF_WSREP(!wsrep_emulate_bin_log,1) && + mysql_bin_log.check_write_error(thd)) { /* "all == true" means that a "rollback statement" triggered the error and @@ -2043,9 +2070,9 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) else if (ending_trans(thd, all) || (!(thd->variables.option_bits & OPTION_KEEP_LOG) && (!stmt_has_updated_non_trans_table(thd) || - thd->variables.binlog_format != BINLOG_FORMAT_STMT) && + WSREP_FORMAT(thd->variables.binlog_format) != BINLOG_FORMAT_STMT) && (!cache_mngr->trx_cache.changes_to_non_trans_temp_table() || - thd->variables.binlog_format != BINLOG_FORMAT_MIXED))) + WSREP_FORMAT(thd->variables.binlog_format) != BINLOG_FORMAT_MIXED))) error= binlog_truncate_trx_cache(thd, cache_mngr, all); } @@ -2150,8 +2177,13 @@ bool MYSQL_BIN_LOG::check_write_error(THD *thd) static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv) { - DBUG_ENTER("binlog_savepoint_set"); int error= 1; + DBUG_ENTER("binlog_savepoint_set"); + +#ifdef WITH_WSREP + if (wsrep_emulate_bin_log) + DBUG_RETURN(0); +#endif /* WITH_WSREP */ char buf[1024]; String log_query(buf, sizeof(buf), &my_charset_bin); @@ -2190,7 +2222,8 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) non-transactional table. Otherwise, truncate the binlog cache starting from the SAVEPOINT command. */ - if (unlikely(trans_has_updated_non_trans_table(thd) || + if (IF_WSREP(!wsrep_emulate_bin_log, 1) && + unlikely(trans_has_updated_non_trans_table(thd) || (thd->variables.option_bits & OPTION_KEEP_LOG))) { char buf[1024]; @@ -2204,7 +2237,10 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) TRUE, FALSE, TRUE, errcode); DBUG_RETURN(mysql_bin_log.write(&qinfo)); } - binlog_trans_log_truncate(thd, *(my_off_t*)sv); + + if (IF_WSREP(!wsrep_emulate_bin_log, 1)) + binlog_trans_log_truncate(thd, *(my_off_t*)sv); + DBUG_RETURN(0); } @@ -5332,7 +5368,8 @@ int THD::binlog_write_table_map(TABLE *table, bool is_transactional, is_transactional= 1; /* Pre-conditions */ - DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open()); + DBUG_ASSERT(is_current_stmt_binlog_format_row()); + DBUG_ASSERT(IF_WSREP(WSREP_EMULATE_BINLOG(this), 0) || mysql_bin_log.is_open()); DBUG_ASSERT(table->s->table_map_id != ULONG_MAX); Table_map_log_event @@ -5465,7 +5502,7 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd, bool is_transactional) { DBUG_ENTER("MYSQL_BIN_LOG::flush_and_set_pending_rows_event(event)"); - DBUG_ASSERT(mysql_bin_log.is_open()); + DBUG_ASSERT(IF_WSREP(WSREP_EMULATE_BINLOG(thd),0) || mysql_bin_log.is_open()); DBUG_PRINT("enter", ("event: 0x%lx", (long) event)); int error= 0; @@ -5791,7 +5828,8 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate) mostly called if is_open() *was* true a few instructions before, but it could have changed since. */ - if (likely(is_open())) + /* applier and replayer can skip writing binlog events */ + if (IF_WSREP((WSREP_EMULATE_BINLOG(thd) && (thd->wsrep_exec_mode != REPL_RECV)) || is_open(), likely(is_open()))) { my_off_t UNINIT_VAR(my_org_b_tell); #ifdef HAVE_REPLICATION @@ -6130,6 +6168,17 @@ int MYSQL_BIN_LOG::rotate(bool force_rotate, bool* check_purge) int error= 0; DBUG_ENTER("MYSQL_BIN_LOG::rotate"); +#ifdef WITH_WSREP + if (wsrep_to_isolation) + { + DBUG_ASSERT(WSREP_ON); + *check_purge= false; + WSREP_DEBUG("avoiding binlog rotate due to TO isolation: %d", + wsrep_to_isolation); + DBUG_RETURN(0); + } +#endif + //todo: fix the macro def and restore safe_mutex_assert_owner(&LOCK_log); *check_purge= false; @@ -6675,6 +6724,11 @@ MYSQL_BIN_LOG::write_transaction_to_binlog(THD *thd, Ha_trx_info *ha_info; DBUG_ENTER("MYSQL_BIN_LOG::write_transaction_to_binlog"); +#ifdef WITH_WSREP + if (wsrep_emulate_bin_log) + DBUG_RETURN(0); +#endif /* WITH_WSREP */ + entry.thd= thd; entry.cache_mngr= cache_mngr; entry.error= 0; @@ -6683,6 +6737,7 @@ MYSQL_BIN_LOG::write_transaction_to_binlog(THD *thd, entry.using_trx_cache= using_trx_cache; entry.need_unlog= false; ha_info= all ? thd->transaction.all.ha_list : thd->transaction.stmt.ha_list; + for (; ha_info; ha_info= ha_info->next()) { if (ha_info->is_started() && ha_info->ht() != binlog_hton && @@ -8819,7 +8874,10 @@ TC_LOG_BINLOG::log_and_order(THD *thd, my_xid xid, bool all, binlog_cache_mngr *cache_mngr= thd->binlog_setup_trx_data(); if (!cache_mngr) + { + WSREP_DEBUG("Skipping empty log_xid: %s", thd->query()); DBUG_RETURN(0); + } cache_mngr->using_xa= TRUE; cache_mngr->xa_xid= xid; @@ -9649,3 +9707,50 @@ maria_declare_plugin(binlog) MariaDB_PLUGIN_MATURITY_STABLE /* maturity */ } maria_declare_plugin_end; + +#ifdef WITH_WSREP +IO_CACHE * get_trans_log(THD * thd) +{ + binlog_cache_mngr *cache_mngr = (binlog_cache_mngr*) + thd_get_ha_data(thd, binlog_hton); + if (cache_mngr) + return cache_mngr->get_binlog_cache_log(true); + + WSREP_DEBUG("binlog cache not initialized, conn :%ld", thd->thread_id); + return NULL; +} + + +bool wsrep_trans_cache_is_empty(THD *thd) +{ + binlog_cache_mngr *const cache_mngr= + (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); + return (!cache_mngr || cache_mngr->trx_cache.empty()); +} + + +void thd_binlog_trx_reset(THD * thd) +{ + /* + todo: fix autocommit select to not call the caller + */ + if (thd_get_ha_data(thd, binlog_hton) != NULL) + { + binlog_cache_mngr *const cache_mngr= + (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); + if (cache_mngr) + cache_mngr->reset(false, true); + } + thd->clear_binlog_table_maps(); +} + + +void thd_binlog_rollback_stmt(THD * thd) +{ + WSREP_DEBUG("thd_binlog_rollback_stmt :%ld", thd->thread_id); + binlog_cache_mngr *const cache_mngr= + (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); + if (cache_mngr) + cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF); +} +#endif /* WITH_WSREP */ diff --git a/sql/log.h b/sql/log.h index 67fcf068ec4..3e9a11b8b94 100644 --- a/sql/log.h +++ b/sql/log.h @@ -19,6 +19,8 @@ #include "unireg.h" // REQUIRED: for other includes #include "handler.h" /* my_xid */ +#include "wsrep.h" +#include "wsrep_mysqld.h" class Relay_log_info; @@ -106,7 +108,11 @@ public: int log_and_order(THD *thd, my_xid xid, bool all, bool need_prepare_ordered, bool need_commit_ordered) { - DBUG_ASSERT(0 /* Internal error - TC_LOG_DUMMY::log_and_order() called */); + /* + If we are not using WSREP this is an Internal error + - TC_LOG_DUMMY::log_and_order() called + */ + DBUG_ASSERT(IF_WSREP(1,0)); return 1; } int unlog(ulong cookie, my_xid xid) { return 0; } diff --git a/sql/log_event.cc b/sql/log_event.cc index 6a85893803e..8e5f7a1f23e 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -44,7 +44,7 @@ #include #include #include "compat56.h" - +#include "wsrep_mysqld.h" #endif /* MYSQL_CLIENT */ #include @@ -3092,6 +3092,15 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, { time_t end_time; +#ifdef WITH_WSREP + /* + If Query_log_event will contain non trans keyword (not BEGIN, COMMIT, + SAVEPOINT or ROLLBACK) we disable PA for this transaction. + */ + if (WSREP_ON && !is_trans_keyword()) + thd->wsrep_PA_safe= false; +#endif /* WITH_WSREP */ + memset(&user, 0, sizeof(user)); memset(&host, 0, sizeof(host)); @@ -4519,6 +4528,22 @@ Query_log_event::do_shall_skip(rpl_group_info *rgi) DBUG_RETURN(Log_event::EVENT_SKIP_COUNT); } } +#ifdef WITH_WSREP + else if (WSREP_ON && wsrep_mysql_replication_bundle && opt_slave_domain_parallel_threads == 0 && + thd->wsrep_mysql_replicated > 0 && + (is_begin() || is_commit())) + { + if (++thd->wsrep_mysql_replicated < (int)wsrep_mysql_replication_bundle) + { + WSREP_DEBUG("skipping wsrep commit %d", thd->wsrep_mysql_replicated); + DBUG_RETURN(Log_event::EVENT_SKIP_IGNORE); + } + else + { + thd->wsrep_mysql_replicated = 0; + } + } +#endif DBUG_RETURN(Log_event::do_shall_skip(rgi)); } @@ -7348,6 +7373,21 @@ Xid_log_event::do_shall_skip(rpl_group_info *rgi) thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_GTID_BEGIN); DBUG_RETURN(Log_event::EVENT_SKIP_COUNT); } +#ifdef WITH_WSREP + else if (wsrep_mysql_replication_bundle && WSREP_ON && + opt_slave_domain_parallel_threads == 0) + { + if (++thd->wsrep_mysql_replicated < (int)wsrep_mysql_replication_bundle) + { + WSREP_DEBUG("skipping wsrep commit %d", thd->wsrep_mysql_replicated); + DBUG_RETURN(Log_event::EVENT_SKIP_IGNORE); + } + else + { + thd->wsrep_mysql_replicated = 0; + } + } +#endif DBUG_RETURN(Log_event::do_shall_skip(rgi)); } #endif /* !MYSQL_CLIENT */ @@ -9625,6 +9665,18 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi) if (open_and_lock_tables(thd, rgi->tables_to_lock, FALSE, 0)) { uint actual_error= thd->get_stmt_da()->sql_errno(); +#ifdef WITH_WSREP + if (WSREP(thd)) + { + WSREP_WARN("BF applier failed to open_and_lock_tables: %u, fatal: %d " + "wsrep = (exec_mode: %d conflict_state: %d seqno: %lld)", + thd->get_stmt_da()->sql_errno(), + thd->is_fatal_error, + thd->wsrep_exec_mode, + thd->wsrep_conflict_state, + (long long)wsrep_thd_trx_seqno(thd)); + } +#endif if (thd->is_slave_error || thd->is_fatal_error) { /* @@ -10771,8 +10823,8 @@ check_table_map(rpl_group_info *rgi, RPL_TABLE_LIST *table_list) DBUG_ENTER("check_table_map"); enum_tbl_map_status res= OK_TO_PROCESS; Relay_log_info *rli= rgi->rli; - - if (rgi->thd->slave_thread /* filtering is for slave only */ && + if ((rgi->thd->slave_thread /* filtering is for slave only */ || + IF_WSREP((WSREP(rgi->thd) && rgi->thd->wsrep_applier), 0)) && (!rli->mi->rpl_filter->db_ok(table_list->db) || (rli->mi->rpl_filter->is_on() && !rli->mi->rpl_filter->tables_ok("", table_list)))) res= FILTERED_OUT; @@ -11520,7 +11572,19 @@ int Write_rows_log_event::do_exec_row(rpl_group_info *rgi) { DBUG_ASSERT(m_table != NULL); + const char *tmp= thd->get_proc_info(); + const char *message= "Write_rows_log_event::write_row()"; + +#ifdef WSREP_PROC_INFO + my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, + "Write_rows_log_event::write_row(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); + message= thd->wsrep_info; +#endif /* WSREP_PROC_INFO */ + + thd_proc_info(thd, message); int error= write_row(rgi, slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT); + thd_proc_info(thd, tmp); if (error && !thd->is_error()) { @@ -12198,15 +12262,34 @@ Delete_rows_log_event::do_after_row_operations(const Slave_reporting_capability int Delete_rows_log_event::do_exec_row(rpl_group_info *rgi) { int error; + const char *tmp= thd->get_proc_info(); + const char *message= "Delete_rows_log_event::find_row()"; const bool invoke_triggers= slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers; DBUG_ASSERT(m_table != NULL); +#ifdef WSREP_PROC_INFO + my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, + "Delete_rows_log_event::find_row(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); + message= thd->wsrep_info; +#endif /* WSREP_PROC_INFO */ + + thd_proc_info(thd, message); if (!(error= find_row(rgi))) { /* Delete the record found, located in record[0] */ + message= "Delete_rows_log_event::ha_delete_row()"; +#ifdef WSREP_PROC_INFO + snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, + "Delete_rows_log_event::ha_delete_row(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); + message= thd->wsrep_info; +#endif + thd_proc_info(thd, message); + if (invoke_triggers && process_triggers(TRG_EVENT_DELETE, TRG_ACTION_BEFORE, FALSE)) error= HA_ERR_GENERIC; // in case if error is not set yet @@ -12217,6 +12300,7 @@ int Delete_rows_log_event::do_exec_row(rpl_group_info *rgi) error= HA_ERR_GENERIC; // in case if error is not set yet m_table->file->ha_index_or_rnd_end(); } + thd_proc_info(thd, tmp); return error; } @@ -12344,8 +12428,18 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) { const bool invoke_triggers= slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers; + const char *tmp= thd->get_proc_info(); + const char *message= "Update_rows_log_event::find_row()"; DBUG_ASSERT(m_table != NULL); +#ifdef WSREP_PROC_INFO + my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, + "Update_rows_log_event::find_row(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); + message= thd->wsrep_info; +#endif /* WSREP_PROC_INFO */ + + thd_proc_info(thd, message); int error= find_row(rgi); if (error) { @@ -12355,6 +12449,7 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) */ m_curr_row= m_curr_row_end; unpack_current_row(rgi); + thd_proc_info(thd, tmp); return error; } @@ -12372,7 +12467,16 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) store_record(m_table,record[1]); m_curr_row= m_curr_row_end; + message= "Update_rows_log_event::unpack_current_row()"; +#ifdef WSREP_PROC_INFO + my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, + "Update_rows_log_event::unpack_current_row(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); + message= thd->wsrep_info; +#endif /* WSREP_PROC_INFO */ + /* this also updates m_curr_row_end */ + thd_proc_info(thd, message); if ((error= unpack_current_row(rgi))) goto err; @@ -12390,6 +12494,15 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) DBUG_DUMP("new values", m_table->record[0], m_table->s->reclength); #endif + message= "Update_rows_log_event::ha_update_row()"; +#ifdef WSREP_PROC_INFO + my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, + "Update_rows_log_event::ha_update_row(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); + message= thd->wsrep_info; +#endif /* WSREP_PROC_INFO */ + + thd_proc_info(thd, message); if (invoke_triggers && process_triggers(TRG_EVENT_UPDATE, TRG_ACTION_BEFORE, TRUE)) { @@ -12405,6 +12518,8 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) process_triggers(TRG_EVENT_UPDATE, TRG_ACTION_AFTER, TRUE)) error= HA_ERR_GENERIC; // in case if error is not set yet + thd_proc_info(thd, tmp); + err: m_table->file->ha_index_or_rnd_end(); return error; @@ -12494,6 +12609,49 @@ void Incident_log_event::pack_info(THD *thd, Protocol *protocol) m_incident, description(), m_message.str); protocol->store(buf, bytes, &my_charset_bin); } +#endif /* MYSQL_CLIENT */ + + +#if WITH_WSREP && !defined(MYSQL_CLIENT) +Format_description_log_event *wsrep_format_desc; // TODO: free them at the end +/* + read the first event from (*buf). The size of the (*buf) is (*buf_len). + At the end (*buf) is shitfed to point to the following event or NULL and + (*buf_len) will be changed to account just being read bytes of the 1st event. +*/ +#define WSREP_MAX_ALLOWED_PACKET 1024*1024*1024 // current protocol max + +Log_event* wsrep_read_log_event( + char **arg_buf, size_t *arg_buf_len, + const Format_description_log_event *description_event) +{ + char *head= (*arg_buf); + uint data_len = uint4korr(head + EVENT_LEN_OFFSET); + char *buf= (*arg_buf); + const char *error= 0; + Log_event *res= 0; + DBUG_ENTER("wsrep_read_log_event"); + + if (data_len > WSREP_MAX_ALLOWED_PACKET) + { + error = "Event too big"; + goto err; + } + + res= Log_event::read_log_event(buf, data_len, &error, description_event, false); + +err: + if (!res) + { + DBUG_ASSERT(error != 0); + sql_print_error("Error in Log_event::read_log_event(): " + "'%s', data_len: %d, event_type: %d", + error,data_len,head[EVENT_TYPE_OFFSET]); + } + (*arg_buf)+= data_len; + (*arg_buf_len)-= data_len; + DBUG_RETURN(res); +} #endif diff --git a/sql/log_event.h b/sql/log_event.h index 2091d968558..212215d97b6 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -1340,7 +1340,11 @@ public: */ int apply_event(rpl_group_info *rgi) { - return do_apply_event(rgi); + int res; + THD_STAGE_INFO(thd, stage_apply_event); + res= do_apply_event(rgi); + THD_STAGE_INFO(thd, stage_after_apply_event); + return res; } diff --git a/sql/mdl.cc b/sql/mdl.cc index 2c2d64e96b2..07130b4d002 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -22,6 +22,8 @@ #include #include #include +#include "wsrep_mysqld.h" +#include "wsrep_thd.h" #ifdef HAVE_PSI_INTERFACE static PSI_mutex_key key_MDL_map_mutex; @@ -1497,11 +1499,53 @@ void MDL_lock::Ticket_list::add_ticket(MDL_ticket *ticket) called by other threads. */ DBUG_ASSERT(ticket->get_lock()); - /* - Add ticket to the *back* of the queue to ensure fairness - among requests with the same priority. - */ - m_list.push_back(ticket); +#ifdef WITH_WSREP + if ((this == &(ticket->get_lock()->m_waiting)) && + wsrep_thd_is_BF((void *)(ticket->get_ctx()->get_thd()), false)) + { + Ticket_iterator itw(ticket->get_lock()->m_waiting); + Ticket_iterator itg(ticket->get_lock()->m_granted); + + DBUG_ASSERT(WSREP_ON); + MDL_ticket *waiting, *granted; + MDL_ticket *prev=NULL; + bool added= false; + + while ((waiting= itw++) && !added) + { + if (!wsrep_thd_is_BF((void *)(waiting->get_ctx()->get_thd()), true)) + { + WSREP_DEBUG("MDL add_ticket inserted before: %lu %s", + wsrep_thd_thread_id(waiting->get_ctx()->get_thd()), + wsrep_thd_query(waiting->get_ctx()->get_thd())); + m_list.insert_after(prev, ticket); + added= true; + } + prev= waiting; + } + if (!added) m_list.push_back(ticket); + + while ((granted= itg++)) + { + if (granted->get_ctx() != ticket->get_ctx() && + granted->is_incompatible_when_granted(ticket->get_type())) + { + if (!wsrep_grant_mdl_exception(ticket->get_ctx(), granted)) + { + WSREP_DEBUG("MDL victim killed at add_ticket"); + } + } + } + } + else +#endif /* WITH_WSREP */ + { + /* + Add ticket to the *back* of the queue to ensure fairness + among requests with the same priority. + */ + m_list.push_back(ticket); + } m_bitmap|= MDL_BIT(ticket->get_type()); } @@ -1842,6 +1886,7 @@ MDL_lock::can_grant_lock(enum_mdl_type type_arg, bool can_grant= FALSE; bitmap_t waiting_incompat_map= incompatible_waiting_types_bitmap()[type_arg]; bitmap_t granted_incompat_map= incompatible_granted_types_bitmap()[type_arg]; + bool wsrep_can_grant= TRUE; /* New lock request can be satisfied iff: @@ -1864,12 +1909,53 @@ MDL_lock::can_grant_lock(enum_mdl_type type_arg, { if (ticket->get_ctx() != requestor_ctx && ticket->is_incompatible_when_granted(type_arg)) + { +#ifdef WITH_WSREP + if (wsrep_thd_is_BF((void *)(requestor_ctx->get_thd()),false) && + key.mdl_namespace() == MDL_key::GLOBAL) + { + WSREP_DEBUG("global lock granted for BF: %lu %s", + wsrep_thd_thread_id(requestor_ctx->get_thd()), + wsrep_thd_query(requestor_ctx->get_thd())); + can_grant = true; + } + else if (!wsrep_grant_mdl_exception(requestor_ctx, ticket)) + { + wsrep_can_grant= FALSE; + if (wsrep_log_conflicts) + { + MDL_lock * lock = ticket->get_lock(); + WSREP_INFO( + "MDL conflict db=%s table=%s ticket=%d solved by %s", + lock->key.db_name(), lock->key.name(), ticket->get_type(), + "abort" ); + } + } + else + can_grant= TRUE; + /* Continue loop */ +#else break; +#endif /* WITH_WSREP */ + } } - if (ticket == NULL) /* Incompatible locks are our own. */ - can_grant= TRUE; + if ((ticket == NULL) && IF_WSREP(wsrep_can_grant, 1)) + can_grant= TRUE; /* Incompatible locks are our own. */ } } +#ifdef WITH_WSREP + else + { + if (wsrep_thd_is_BF((void *)(requestor_ctx->get_thd()), false) && + key.mdl_namespace() == MDL_key::GLOBAL) + { + WSREP_DEBUG("global lock granted for BF (waiting queue): %lu %s", + wsrep_thd_thread_id(requestor_ctx->get_thd()), + wsrep_thd_query(requestor_ctx->get_thd())); + can_grant = true; + } + } +#endif /* WITH_WSREP */ return can_grant; } @@ -3222,3 +3308,44 @@ void MDL_context::set_transaction_duration_for_all_locks() ticket->m_duration= MDL_TRANSACTION; #endif } + + +#ifdef WITH_WSREP + +void MDL_context::release_explicit_locks() +{ + release_locks_stored_before(MDL_EXPLICIT, NULL); +} + + +void MDL_ticket::wsrep_report(bool debug) +{ + if (debug) + { + const PSI_stage_info *psi_stage = m_lock->key.get_wait_state_name(); + + WSREP_DEBUG("MDL ticket: type: %s space: %s db: %s name: %s (%s)", + (get_type() == MDL_INTENTION_EXCLUSIVE) ? "intention exclusive" : + ((get_type() == MDL_SHARED) ? "shared" : + ((get_type() == MDL_SHARED_HIGH_PRIO ? "shared high prio" : + ((get_type() == MDL_SHARED_READ) ? "shared read" : + ((get_type() == MDL_SHARED_WRITE) ? "shared write" : + ((get_type() == MDL_SHARED_NO_WRITE) ? "shared no write" : + ((get_type() == MDL_SHARED_NO_READ_WRITE) ? "shared no read write" : + ((get_type() == MDL_EXCLUSIVE) ? "exclusive" : + "UNKNOWN")))))))), + (m_lock->key.mdl_namespace() == MDL_key::GLOBAL) ? "GLOBAL" : + ((m_lock->key.mdl_namespace() == MDL_key::SCHEMA) ? "SCHEMA" : + ((m_lock->key.mdl_namespace() == MDL_key::TABLE) ? "TABLE" : + ((m_lock->key.mdl_namespace() == MDL_key::TABLE) ? "FUNCTION" : + ((m_lock->key.mdl_namespace() == MDL_key::TABLE) ? "PROCEDURE" : + ((m_lock->key.mdl_namespace() == MDL_key::TABLE) ? "TRIGGER" : + ((m_lock->key.mdl_namespace() == MDL_key::TABLE) ? "EVENT" : + ((m_lock->key.mdl_namespace() == MDL_key::COMMIT) ? "COMMIT" : + (char *)"UNKNOWN"))))))), + m_lock->key.db_name(), + m_lock->key.name(), + psi_stage->m_name); + } +} +#endif /* WITH_WSREP */ diff --git a/sql/mdl.h b/sql/mdl.h index 47c587eb3be..231f95d7419 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -586,6 +586,9 @@ public: MDL_ticket *next_in_lock; MDL_ticket **prev_in_lock; public: +#ifdef WITH_WSREP + void wsrep_report(bool debug); +#endif /* WITH_WSREP */ bool has_pending_conflicting_lock() const; MDL_context *get_ctx() const { return m_ctx; } @@ -773,6 +776,10 @@ public: m_tickets[MDL_TRANSACTION].is_empty() && m_tickets[MDL_EXPLICIT].is_empty()); } + inline bool has_transactional_locks() const + { + return !m_tickets[MDL_TRANSACTION].is_empty(); + } MDL_savepoint mdl_savepoint() { @@ -786,6 +793,9 @@ public: void release_statement_locks(); void release_transactional_locks(); +#ifdef WITH_WSREP + void release_explicit_locks(); +#endif void rollback_to_savepoint(const MDL_savepoint &mdl_savepoint); MDL_context_owner *get_owner() { return m_owner; } @@ -910,7 +920,6 @@ private: */ MDL_wait_for_subgraph *m_waiting_for; private: - THD *get_thd() const { return m_owner->get_thd(); } MDL_ticket *find_ticket(MDL_request *mdl_req, enum_mdl_duration *duration); void release_locks_stored_before(enum_mdl_duration duration, MDL_ticket *sentinel); @@ -919,6 +928,7 @@ private: MDL_ticket **out_ticket); public: + THD *get_thd() const { return m_owner->get_thd(); } void find_deadlock(); ulong get_thread_id() const { return thd_get_thread_id(get_thd()); } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 066dae224eb..97e9cff3b79 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -71,6 +71,11 @@ #include "scheduler.h" #include #include "debug_sync.h" +#include "wsrep_mysqld.h" +#include "wsrep_var.h" +#include "wsrep_thd.h" +#include "wsrep_sst.h" + #include "sql_callback.h" #include "threadpool.h" @@ -352,7 +357,8 @@ static bool volatile select_thread_in_use, signal_thread_in_use; static volatile bool ready_to_exit; static my_bool opt_debugging= 0, opt_external_locking= 0, opt_console= 0; static my_bool opt_short_log_format= 0; -static uint kill_cached_threads, wake_thread; +uint kill_cached_threads; +static uint wake_thread; ulong max_used_connections; static volatile ulong cached_thread_count= 0; static char *mysqld_user, *mysqld_chroot; @@ -360,14 +366,15 @@ static char *default_character_set_name; static char *character_set_filesystem_name; static char *lc_messages; static char *lc_time_names_name; -static char *my_bind_addr_str; +char *my_bind_addr_str; static char *default_collation_name; char *default_storage_engine, *default_tmp_storage_engine; static char compiled_default_collation_name[]= MYSQL_DEFAULT_COLLATION_NAME; static I_List thread_cache; static bool binlog_format_used= false; LEX_STRING opt_init_connect, opt_init_slave; -static mysql_cond_t COND_thread_cache, COND_flush_thread_cache; +mysql_cond_t COND_thread_cache; +static mysql_cond_t COND_flush_thread_cache; static DYNAMIC_ARRAY all_options; /* Global variables */ @@ -731,6 +738,27 @@ mysql_cond_t COND_server_started; int mysqld_server_started=0, mysqld_server_initialized= 0; File_parser_dummy_hook file_parser_dummy_hook; +#ifdef WITH_WSREP +mysql_mutex_t LOCK_wsrep_ready; +mysql_cond_t COND_wsrep_ready; +mysql_mutex_t LOCK_wsrep_sst; +mysql_cond_t COND_wsrep_sst; +mysql_mutex_t LOCK_wsrep_sst_init; +mysql_cond_t COND_wsrep_sst_init; +mysql_mutex_t LOCK_wsrep_rollback; +mysql_cond_t COND_wsrep_rollback; +wsrep_aborting_thd_t wsrep_aborting_thd= NULL; +mysql_mutex_t LOCK_wsrep_replaying; +mysql_cond_t COND_wsrep_replaying; +mysql_mutex_t LOCK_wsrep_slave_threads; +mysql_mutex_t LOCK_wsrep_desync; +int wsrep_replaying= 0; +ulong wsrep_running_threads = 0; // # of currently running wsrep threads +ulong my_bind_addr; +const char *wsrep_binlog_format_names[]= + {"MIXED", "STATEMENT", "ROW", "NONE", NullS}; +#endif /* WITH_WSREP */ + /* replication parameters, if master_host is not NULL, we are a slave */ uint report_port= 0; ulong master_retry_count=0; @@ -868,6 +896,12 @@ PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list, key_LOCK_error_messages, key_LOG_INFO_lock, key_LOCK_thread_count, key_LOCK_thread_cache, key_PARTITION_LOCK_auto_inc; +#ifdef WITH_WSREP +PSI_mutex_key key_LOCK_wsrep_rollback, key_LOCK_wsrep_thd, + key_LOCK_wsrep_replaying, key_LOCK_wsrep_ready, key_LOCK_wsrep_sst, + key_LOCK_wsrep_sst_thread, key_LOCK_wsrep_sst_init, + key_LOCK_wsrep_slave_threads, key_LOCK_wsrep_desync; +#endif PSI_mutex_key key_RELAYLOG_LOCK_index; PSI_mutex_key key_LOCK_slave_state, key_LOCK_binlog_state, key_LOCK_rpl_thread, key_LOCK_rpl_thread_pool, key_LOCK_parallel_entry; @@ -942,6 +976,18 @@ static PSI_mutex_info all_server_mutexes[]= { &key_LOCK_prepare_ordered, "LOCK_prepare_ordered", PSI_FLAG_GLOBAL}, { &key_LOCK_commit_ordered, "LOCK_commit_ordered", PSI_FLAG_GLOBAL}, { &key_LOG_INFO_lock, "LOG_INFO::lock", 0}, +#ifdef WITH_WSREP + { &key_LOCK_wsrep_ready, "LOCK_wsrep_ready", PSI_FLAG_GLOBAL}, + { &key_LOCK_wsrep_sst, "LOCK_wsrep_sst", PSI_FLAG_GLOBAL}, + { &key_LOCK_wsrep_sst_thread, "wsrep_sst_thread", 0}, + { &key_LOCK_wsrep_sst_init, "LOCK_wsrep_sst_init", PSI_FLAG_GLOBAL}, + { &key_LOCK_wsrep_sst, "LOCK_wsrep_sst", PSI_FLAG_GLOBAL}, + { &key_LOCK_wsrep_rollback, "LOCK_wsrep_rollback", PSI_FLAG_GLOBAL}, + { &key_LOCK_wsrep_thd, "THD::LOCK_wsrep_thd", 0}, + { &key_LOCK_wsrep_replaying, "LOCK_wsrep_replaying", PSI_FLAG_GLOBAL}, + { &key_LOCK_wsrep_slave_threads, "LOCK_wsrep_slave_threads", PSI_FLAG_GLOBAL}, + { &key_LOCK_wsrep_desync, "LOCK_wsrep_desync", PSI_FLAG_GLOBAL}, +#endif { &key_LOCK_thread_count, "LOCK_thread_count", PSI_FLAG_GLOBAL}, { &key_LOCK_thread_cache, "LOCK_thread_cache", PSI_FLAG_GLOBAL}, { &key_PARTITION_LOCK_auto_inc, "HA_DATA_PARTITION::LOCK_auto_inc", 0}, @@ -988,6 +1034,11 @@ PSI_cond_key key_BINLOG_COND_xid_list, key_BINLOG_update_cond, key_TABLE_SHARE_cond, key_user_level_lock_cond, key_COND_thread_count, key_COND_thread_cache, key_COND_flush_thread_cache, key_BINLOG_COND_queue_busy; +#ifdef WITH_WSREP +PSI_cond_key key_COND_wsrep_rollback, key_COND_wsrep_thd, + key_COND_wsrep_replaying, key_COND_wsrep_ready, key_COND_wsrep_sst, + key_COND_wsrep_sst_init, key_COND_wsrep_sst_thread; +#endif /* WITH_WSREP */ PSI_cond_key key_RELAYLOG_update_cond, key_COND_wakeup_ready, key_COND_wait_commit; PSI_cond_key key_RELAYLOG_COND_queue_busy; @@ -1037,6 +1088,15 @@ static PSI_cond_info all_server_conds[]= { &key_user_level_lock_cond, "User_level_lock::cond", 0}, { &key_COND_thread_count, "COND_thread_count", PSI_FLAG_GLOBAL}, { &key_COND_thread_cache, "COND_thread_cache", PSI_FLAG_GLOBAL}, +#ifdef WITH_WSREP + { &key_COND_wsrep_ready, "COND_wsrep_ready", PSI_FLAG_GLOBAL}, + { &key_COND_wsrep_sst, "COND_wsrep_sst", PSI_FLAG_GLOBAL}, + { &key_COND_wsrep_sst_init, "COND_wsrep_sst_init", PSI_FLAG_GLOBAL}, + { &key_COND_wsrep_sst_thread, "wsrep_sst_thread", 0}, + { &key_COND_wsrep_rollback, "COND_wsrep_rollback", PSI_FLAG_GLOBAL}, + { &key_COND_wsrep_thd, "THD::COND_wsrep_thd", 0}, + { &key_COND_wsrep_replaying, "COND_wsrep_replaying", PSI_FLAG_GLOBAL}, +#endif { &key_COND_flush_thread_cache, "COND_flush_thread_cache", PSI_FLAG_GLOBAL}, { &key_COND_rpl_thread, "COND_rpl_thread", 0}, { &key_COND_rpl_thread_queue, "COND_rpl_thread_queue", 0}, @@ -1398,7 +1458,7 @@ bool mysqld_embedded=0; bool mysqld_embedded=1; #endif -static my_bool plugins_are_initialized= FALSE; +my_bool plugins_are_initialized= FALSE; #ifndef DBUG_OFF static const char* default_dbug_option; @@ -1622,6 +1682,11 @@ static void close_connections(void) if (tmp->slave_thread) continue; +#ifdef WITH_WSREP + /* skip wsrep system threads as well */ + if (WSREP(tmp) && (tmp->wsrep_exec_mode==REPL_RECV || tmp->wsrep_applier)) + continue; +#endif tmp->killed= KILL_SERVER_HARD; MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (tmp)); mysql_mutex_lock(&tmp->LOCK_thd_data); @@ -1697,6 +1762,34 @@ static void close_connections(void) tmp->main_security_ctx.user : "")); close_connection(tmp,ER_SERVER_SHUTDOWN); } +#endif +#ifdef WITH_WSREP + /* + * WSREP_TODO: + * this code block may turn out redundant. wsrep->disconnect() + * should terminate slave threads gracefully, and we don't need + * to signal them here. + * The code here makes sure mysqld will not hang during shutdown + * even if wsrep provider has problems in shutting down. + */ + if (WSREP(tmp) && tmp->wsrep_exec_mode==REPL_RECV) + { + sql_print_information("closing wsrep system thread"); + tmp->killed= KILL_CONNECTION; + MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (tmp)); + if (tmp->mysys_var) + { + tmp->mysys_var->abort=1; + mysql_mutex_lock(&tmp->mysys_var->mutex); + if (tmp->mysys_var->current_cond) + { + mysql_mutex_lock(tmp->mysys_var->current_mutex); + mysql_cond_broadcast(tmp->mysys_var->current_cond); + mysql_mutex_unlock(tmp->mysys_var->current_mutex); + } + mysql_mutex_unlock(&tmp->mysys_var->mutex); + } + } #endif DBUG_PRINT("quit",("Unlocking LOCK_thread_count")); mysql_mutex_unlock(&LOCK_thread_count); @@ -1852,7 +1945,18 @@ static void __cdecl kill_server(int sig_ptr) } #endif +#ifdef WITH_WSREP + if (WSREP_ON) + wsrep_stop_replication(NULL); +#endif + close_connections(); + +#ifdef WITH_WSREP + if (wsrep_inited == 1) + wsrep_deinit(true); +#endif + if (sig != MYSQL_KILL_SIGNAL && sig != 0) unireg_abort(1); /* purecov: inspected */ @@ -1947,6 +2051,30 @@ extern "C" void unireg_abort(int exit_code) usage(); if (exit_code) sql_print_error("Aborting\n"); + +#ifdef WITH_WSREP + /* Check if wsrep class is used. If yes, then cleanup wsrep */ + if (wsrep) + { + /* + This is an abort situation, we cannot expect to gracefully close all + wsrep threads here, we can only diconnect from service + */ + wsrep_close_client_connections(FALSE); + shutdown_in_progress= 1; + THD *thd(0); + wsrep->disconnect(wsrep); + WSREP_INFO("Service disconnected."); + wsrep_close_threads(thd); /* this won't close all threads */ + sleep(1); /* so give some time to exit for those which can */ + WSREP_INFO("Some threads may fail to exit."); + + /* In bootstrap mode we deinitialize wsrep here. */ + if (opt_bootstrap && wsrep_inited) + wsrep_deinit(true); + } +#endif // WITH_WSREP + clean_up(!opt_abort && (exit_code || !opt_bootstrap)); /* purecov: inspected */ DBUG_PRINT("quit",("done with cleanup in unireg_abort")); mysqld_exit(exit_code); @@ -2166,6 +2294,20 @@ static void clean_up_mutexes() mysql_cond_destroy(&COND_thread_count); mysql_cond_destroy(&COND_thread_cache); mysql_cond_destroy(&COND_flush_thread_cache); +#ifdef WITH_WSREP + (void) mysql_mutex_destroy(&LOCK_wsrep_ready); + (void) mysql_cond_destroy(&COND_wsrep_ready); + (void) mysql_mutex_destroy(&LOCK_wsrep_sst); + (void) mysql_cond_destroy(&COND_wsrep_sst); + (void) mysql_mutex_destroy(&LOCK_wsrep_sst_init); + (void) mysql_cond_destroy(&COND_wsrep_sst_init); + (void) mysql_mutex_destroy(&LOCK_wsrep_rollback); + (void) mysql_cond_destroy(&COND_wsrep_rollback); + (void) mysql_mutex_destroy(&LOCK_wsrep_replaying); + (void) mysql_cond_destroy(&COND_wsrep_replaying); + (void) mysql_mutex_destroy(&LOCK_wsrep_slave_threads); + (void) mysql_mutex_destroy(&LOCK_wsrep_desync); +#endif mysql_mutex_destroy(&LOCK_server_started); mysql_cond_destroy(&COND_server_started); mysql_mutex_destroy(&LOCK_prepare_ordered); @@ -2481,6 +2623,11 @@ static MYSQL_SOCKET activate_tcp_port(uint port) socket_errno); unireg_abort(1); } +#if defined(WITH_WSREP) && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) + if (WSREP_ON) + (void) fcntl(mysql_socket_getfd(ip_sock), F_SETFD, FD_CLOEXEC); +#endif /* WITH_WSREP */ + DBUG_RETURN(ip_sock); } @@ -2607,6 +2754,10 @@ static void network_init(void) if (mysql_socket_listen(unix_sock,(int) back_log) < 0) sql_print_warning("listen() on Unix socket failed with error %d", socket_errno); +#if defined(WITH_WSREP) && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) + if (WSREP_ON) + (void) fcntl(mysql_socket_getfd(unix_sock), F_SETFD, FD_CLOEXEC); +#endif /* WITH_WSREP */ } #endif DBUG_PRINT("info",("server started")); @@ -2681,6 +2832,16 @@ void thd_cleanup(THD *thd) void dec_connection_count(THD *thd) { +#ifdef WITH_WSREP + /* + Do not decrement when its wsrep system thread. wsrep_applier is set for + applier as well as rollbacker threads. + */ + if (thd->wsrep_applier) + return; +#endif /* WITH_WSREP */ + + DBUG_ASSERT(*thd->scheduler->connection_count > 0); mysql_mutex_lock(&LOCK_connection_count); (*thd->scheduler->connection_count)--; mysql_mutex_unlock(&LOCK_connection_count); @@ -2851,10 +3012,15 @@ static bool cache_thread() bool one_thread_per_connection_end(THD *thd, bool put_in_cache) { DBUG_ENTER("one_thread_per_connection_end"); +#ifdef WITH_WSREP + const bool wsrep_applier(thd->wsrep_applier); +#endif + unlink_thd(thd); /* Mark that current_thd is not valid anymore */ set_current_thd(0); - if (put_in_cache && cache_thread()) + + if (put_in_cache && cache_thread() && IF_WSREP(!wsrep_applier, 1)) DBUG_RETURN(0); // Thread is reused /* @@ -3976,6 +4142,14 @@ static int init_common_variables() else opt_log_basename= glob_hostname; +#ifdef WITH_WSREP + if (0 == wsrep_node_name || 0 == wsrep_node_name[0]) + { + my_free((void *)wsrep_node_name); + wsrep_node_name= my_strdup(glob_hostname, MYF(MY_WME)); + } +#endif /* WITH_WSREP */ + if (!*pidfile_name) { strmake(pidfile_name, opt_log_basename, sizeof(pidfile_name)-5); @@ -4036,6 +4210,15 @@ static int init_common_variables() SQLCOM_END + 8); #endif +#ifdef WITH_WSREP + /* + This is a protection against mutually incompatible option values. + Note WSREP_ON == global_system_variables.wsrep_on + */ + if (WSREP_ON && wsrep_check_opts (remaining_argc, remaining_argv)) + global_system_variables.wsrep_on= 0; +#endif /* WITH_WSREP */ + if (get_options(&remaining_argc, &remaining_argv)) return 1; set_server_version(); @@ -4430,6 +4613,28 @@ static int init_thread_environment() rpl_init_gtid_waiting(); #endif +#ifdef WITH_WSREP + mysql_mutex_init(key_LOCK_wsrep_ready, + &LOCK_wsrep_ready, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_wsrep_ready, &COND_wsrep_ready, NULL); + mysql_mutex_init(key_LOCK_wsrep_sst, + &LOCK_wsrep_sst, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_wsrep_sst, &COND_wsrep_sst, NULL); + mysql_mutex_init(key_LOCK_wsrep_sst_init, + &LOCK_wsrep_sst_init, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_wsrep_sst_init, &COND_wsrep_sst_init, NULL); + mysql_mutex_init(key_LOCK_wsrep_rollback, + &LOCK_wsrep_rollback, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_wsrep_rollback, &COND_wsrep_rollback, NULL); + mysql_mutex_init(key_LOCK_wsrep_replaying, + &LOCK_wsrep_replaying, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_wsrep_replaying, &COND_wsrep_replaying, NULL); + mysql_mutex_init(key_LOCK_wsrep_slave_threads, + &LOCK_wsrep_slave_threads, MY_MUTEX_INIT_FAST); + mysql_mutex_init(key_LOCK_wsrep_desync, + &LOCK_wsrep_desync, MY_MUTEX_INIT_FAST); +#endif + DBUG_RETURN(0); } @@ -4727,10 +4932,10 @@ static int init_server_components() /* need to configure logging before initializing storage engines */ if (!opt_bin_log_used) { - if (opt_log_slave_updates) + if (IF_WSREP(!WSREP_ON,1) && opt_log_slave_updates) sql_print_warning("You need to use --log-bin to make " "--log-slave-updates work."); - if (binlog_format_used) + if (IF_WSREP(!WSREP_ON, 1) && binlog_format_used) sql_print_warning("You need to use --log-bin to make " "--binlog-format work."); } @@ -4805,10 +5010,67 @@ a file name for --log-bin-index option", opt_binlog_index_name); { opt_bin_logname= my_once_strdup(buf, MYF(MY_WME)); } +#ifdef WITH_WSREP /* WSREP BEFORE SE */ + /* + Wsrep initialization must happen at this point, because: + - opt_bin_logname must be known when starting replication + since SST may need it + - SST may modify binlog index file, so it must be opened + after SST has happened + */ + } + if (WSREP_ON && !wsrep_recovery) + { + if (opt_bootstrap) // bootsrap option given - disable wsrep functionality + { + wsrep_provider_init(WSREP_NONE); + if (wsrep_init()) unireg_abort(1); + } + else // full wsrep initialization + { + // add basedir/bin to PATH to resolve wsrep script names + char* const tmp_path((char*)alloca(strlen(mysql_home) + + strlen("/bin") + 1)); + if (tmp_path) + { + strcpy(tmp_path, mysql_home); + strcat(tmp_path, "/bin"); + wsrep_prepend_PATH(tmp_path); + } + else + { + WSREP_ERROR("Could not append %s/bin to PATH", mysql_home); + } + + if (wsrep_before_SE()) + { + set_ports(); // this is also called in network_init() later but we need + // to know mysqld_port now - lp:1071882 + wsrep_init_startup(true); + } + } + } + if (opt_bin_log) + { + /* + Variable ln is not defined at this scope. We use opt_bin_logname instead. + It should be the same as ln since + - mysql_bin_log.generate_name() returns first argument if new log name + is not generated + - if new log name is generated, return value is assigned to ln and copied + to opt_bin_logname above + */ + if (mysql_bin_log.open_index_file(opt_binlog_index_name, opt_bin_logname, + TRUE)) + { + unireg_abort(1); + } +#else if (mysql_bin_log.open_index_file(opt_binlog_index_name, ln, TRUE)) { unireg_abort(1); } +#endif /* WITH_WSREP */ } /* call ha_init_key_cache() on all key caches to init them */ @@ -4930,10 +5192,40 @@ a file name for --log-bin-index option", opt_binlog_index_name); internal_tmp_table_max_key_segments= myisam_max_key_segments(); #endif +#ifdef WITH_WSREP + if (WSREP_ON && !opt_bin_log) + { + wsrep_emulate_bin_log= 1; + } +#endif + + /* if total_ha_2pc <= 1 + tc_log = tc_log_dummy + else + if opt_bin_log == true + tc_log = mysql_bin_log + else + if WITH_WSREP + if WSREP_ON + tc_log = tc_log_dummy + else + tc_log = tc_log_mmap + else + tc_log=tc_log_mmap + */ tc_log= (total_ha_2pc > 1 ? (opt_bin_log ? (TC_LOG *) &mysql_bin_log : - (TC_LOG *) &tc_log_mmap) : - (TC_LOG *) &tc_log_dummy); + IF_WSREP((WSREP_ON ? (TC_LOG *) &tc_log_dummy : + (TC_LOG *) &tc_log_mmap), (TC_LOG *) &tc_log_mmap)) : + (TC_LOG *) &tc_log_dummy); + +#ifdef WITH_WSREP + WSREP_DEBUG("Initial TC log open: %s", + (tc_log == &mysql_bin_log) ? "binlog" : + (tc_log == &tc_log_mmap) ? "mmap" : + (tc_log == &tc_log_dummy) ? "dummy" : "unknown" + ); +#endif if (tc_log->open(opt_bin_log ? opt_bin_logname : opt_tc_log_file)) { @@ -5192,6 +5484,10 @@ int mysqld_main(int argc, char **argv) return 1; } #endif +#ifdef WITH_WSREP + if (WSREP_ON) + wsrep_filter_new_cluster (&argc, argv); +#endif /* WITH_WSREP */ orig_argc= argc; orig_argv= argv; @@ -5408,6 +5704,15 @@ int mysqld_main(int argc, char **argv) } #endif +#ifdef WITH_WSREP /* WSREP AFTER SE */ + if (WSREP_ON && wsrep_recovery) + { + select_thread_in_use= 0; + wsrep_recover(); + unireg_abort(0); + } +#endif /* WITH_WSREP */ + /* init signals & alarm After this we can't quit by a simple unireg_abort @@ -5464,7 +5769,35 @@ int mysqld_main(int argc, char **argv) if (Events::init(opt_noacl || opt_bootstrap)) unireg_abort(1); - if (opt_bootstrap) +#ifdef WITH_WSREP /* WSREP AFTER SE */ + if (WSREP_ON) + { + if (opt_bootstrap) + { + /*! bootstrap wsrep init was taken care of above */ + } + else + { + wsrep_SE_initialized(); + + if (wsrep_before_SE()) + { + /*! in case of no SST wsrep waits in view handler callback */ + wsrep_SE_init_grab(); + wsrep_SE_init_done(); + /*! in case of SST wsrep waits for wsrep->sst_received */ + wsrep_sst_continue(); + } + else + { + wsrep_init_startup (false); + } + + wsrep_create_appliers(wsrep_slave_threads - 1); + } + } +#endif /* WITH_WSREP */ + if (opt_bootstrap) { select_thread_in_use= 0; // Allow 'kill' to work bootstrap(mysql_stdin); @@ -5532,6 +5865,7 @@ int mysqld_main(int argc, char **argv) #ifdef EXTRA_DEBUG2 sql_print_error("Before Lock_thread_count"); #endif + WSREP_DEBUG("Before Lock_thread_count"); mysql_mutex_lock(&LOCK_thread_count); DBUG_PRINT("quit", ("Got thread_count mutex")); select_thread_in_use=0; // For close_connections @@ -5797,6 +6131,9 @@ static void bootstrap(MYSQL_FILE *file) DBUG_ENTER("bootstrap"); THD *thd= new THD; +#ifdef WITH_WSREP + thd->variables.wsrep_on= 0; +#endif thd->bootstrap=1; my_net_init(&thd->net,(st_vio*) 0, MYF(0)); thd->max_client_packet_length= thd->net.max_packet; @@ -6198,6 +6535,9 @@ void handle_connections_sockets() sleep(1); // Give other threads some time continue; } +#if defined(WITH_WSREP) && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) + (void) fcntl(mysql_socket_getfd(new_sock), F_SETFD, FD_CLOEXEC); +#endif /* WITH_WSREP */ #ifdef HAVE_LIBWRAP { @@ -7970,6 +8310,21 @@ SHOW_VAR status_vars[]= { {"Uptime", (char*) &show_starttime, SHOW_SIMPLE_FUNC}, #ifdef ENABLED_PROFILING {"Uptime_since_flush_status",(char*) &show_flushstatustime, SHOW_SIMPLE_FUNC}, +#endif +#ifdef WITH_WSREP + {"wsrep_connected", (char*) &wsrep_connected, SHOW_BOOL}, + {"wsrep_ready", (char*) &wsrep_ready, SHOW_BOOL}, + {"wsrep_cluster_state_uuid", (char*) &wsrep_cluster_state_uuid,SHOW_CHAR_PTR}, + {"wsrep_cluster_conf_id", (char*) &wsrep_cluster_conf_id, SHOW_LONGLONG}, + {"wsrep_cluster_status", (char*) &wsrep_cluster_status, SHOW_CHAR_PTR}, + {"wsrep_cluster_size", (char*) &wsrep_cluster_size, SHOW_LONG_NOFLUSH}, + {"wsrep_local_index", (char*) &wsrep_local_index, SHOW_LONG_NOFLUSH}, + {"wsrep_local_bf_aborts", (char*) &wsrep_show_bf_aborts, SHOW_SIMPLE_FUNC}, + {"wsrep_provider_name", (char*) &wsrep_provider_name, SHOW_CHAR_PTR}, + {"wsrep_provider_version", (char*) &wsrep_provider_version, SHOW_CHAR_PTR}, + {"wsrep_provider_vendor", (char*) &wsrep_provider_vendor, SHOW_CHAR_PTR}, + {"wsrep_thread_count", (char*) &wsrep_running_threads, SHOW_LONG_NOFLUSH}, + {"wsrep", (char*) &wsrep_show_status, SHOW_FUNC}, #endif {NullS, NullS, SHOW_LONG} }; @@ -8313,6 +8668,10 @@ static int mysql_init_variables(void) if (!(tmpenv = getenv("MY_BASEDIR_VERSION"))) tmpenv = DEFAULT_MYSQL_HOME; strmake_buf(mysql_home, tmpenv); +#endif +#ifdef WITH_WSREP + if (WSREP_ON && wsrep_init_vars()) + return 1; #endif return 0; } @@ -8561,6 +8920,14 @@ mysqld_get_one_option(int optid, case OPT_LOWER_CASE_TABLE_NAMES: lower_case_table_names_used= 1; break; +#ifdef WITH_WSREP + case OPT_WSREP_START_POSITION: + wsrep_start_position_init (argument); + break; + case OPT_WSREP_SST_AUTH: + wsrep_sst_auth_init (argument); + break; +#endif #if defined(ENABLED_DEBUG_SYNC) case OPT_DEBUG_SYNC_TIMEOUT: /* @@ -9029,6 +9396,9 @@ void set_server_version(void) #ifdef EMBEDDED_LIBRARY end= strmov(end, "-embedded"); #endif +#ifdef WITH_WSREP + end= strmov(end, "-wsrep"); +#endif #ifndef DBUG_OFF if (!strstr(MYSQL_SERVER_SUFFIX_STR, "-debug")) end= strmov(end, "-debug"); @@ -9321,6 +9691,10 @@ void refresh_status(THD *thd) /* Reset some global variables */ reset_status_vars(); +#ifdef WITH_WSREP + if (WSREP_ON) + wsrep->stats_reset(wsrep); +#endif /* WITH_WSREP */ /* Reset the counters of all key caches (default and named). */ process_key_caches(reset_key_cache_counters, 0); @@ -9372,6 +9746,7 @@ static PSI_file_info all_server_files[]= }; #endif /* HAVE_PSI_INTERFACE */ +PSI_stage_info stage_after_apply_event= { 0, "after apply log event", 0}; PSI_stage_info stage_after_create= { 0, "After create", 0}; PSI_stage_info stage_after_opening_tables= { 0, "After opening tables", 0}; PSI_stage_info stage_after_table_lock= { 0, "After table lock", 0}; @@ -9379,6 +9754,7 @@ PSI_stage_info stage_allocating_local_table= { 0, "allocating local table", 0}; PSI_stage_info stage_alter_inplace_prepare= { 0, "preparing for alter table", 0}; PSI_stage_info stage_alter_inplace= { 0, "altering table", 0}; PSI_stage_info stage_alter_inplace_commit= { 0, "committing alter table to storage engine", 0}; +PSI_stage_info stage_apply_event= { 0, "apply log event", 0}; PSI_stage_info stage_changing_master= { 0, "Changing master", 0}; PSI_stage_info stage_checking_master_version= { 0, "Checking master version", 0}; PSI_stage_info stage_checking_permissions= { 0, "checking permissions", 0}; @@ -9452,6 +9828,7 @@ PSI_stage_info stage_sql_thd_waiting_until_delay= { 0, "Waiting until MASTER_DEL PSI_stage_info stage_storing_result_in_query_cache= { 0, "storing result in query cache", 0}; PSI_stage_info stage_storing_row_into_queue= { 0, "storing row into queue", 0}; PSI_stage_info stage_system_lock= { 0, "System lock", 0}; +PSI_stage_info stage_unlocking_tables= { 0, "Unlocking tables", 0}; PSI_stage_info stage_update= { 0, "update", 0}; PSI_stage_info stage_updating= { 0, "updating", 0}; PSI_stage_info stage_updating_main_table= { 0, "updating main table", 0}; @@ -9496,6 +9873,7 @@ PSI_stage_info stage_gtid_wait_other_connection= { 0, "Waiting for other master PSI_stage_info *all_server_stages[]= { + & stage_after_apply_event, & stage_after_create, & stage_after_opening_tables, & stage_after_table_lock, @@ -9503,6 +9881,7 @@ PSI_stage_info *all_server_stages[]= & stage_alter_inplace, & stage_alter_inplace_commit, & stage_alter_inplace_prepare, + & stage_apply_event, & stage_binlog_processing_checkpoint_notify, & stage_binlog_stopping_background_thread, & stage_binlog_waiting_background_tasks, @@ -9584,6 +9963,7 @@ PSI_stage_info *all_server_stages[]= & stage_storing_result_in_query_cache, & stage_storing_row_into_queue, & stage_system_lock, + & stage_unlocking_tables, & stage_update, & stage_updating, & stage_updating_main_table, diff --git a/sql/mysqld.h b/sql/mysqld.h index a1656a49047..8a6794cc30c 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -25,6 +25,7 @@ #include "sql_list.h" /* I_List */ #include "sql_cmd.h" #include +#include "my_pthread.h" class THD; struct handlerton; @@ -241,6 +242,11 @@ extern PSI_mutex_key key_PAGE_lock, key_LOCK_sync, key_LOCK_active, key_LOCK_pool, key_LOCK_pending_checkpoint; #endif /* HAVE_MMAP */ +#ifdef WITH_WSREP +extern PSI_mutex_key key_LOCK_wsrep_thd; +extern PSI_cond_key key_COND_wsrep_thd; +#endif /* WITH_WSREP */ + #ifdef HAVE_OPENSSL extern PSI_mutex_key key_LOCK_des_key_file; #endif @@ -328,6 +334,7 @@ void init_server_psi_keys(); MAINTAINER: Please keep this list in order, to limit merge collisions. Hint: grep PSI_stage_info | sort -u */ +extern PSI_stage_info stage_apply_event; extern PSI_stage_info stage_after_create; extern PSI_stage_info stage_after_opening_tables; extern PSI_stage_info stage_after_table_lock; @@ -335,6 +342,7 @@ extern PSI_stage_info stage_allocating_local_table; extern PSI_stage_info stage_alter_inplace_prepare; extern PSI_stage_info stage_alter_inplace; extern PSI_stage_info stage_alter_inplace_commit; +extern PSI_stage_info stage_after_apply_event; extern PSI_stage_info stage_changing_master; extern PSI_stage_info stage_checking_master_version; extern PSI_stage_info stage_checking_permissions; @@ -408,6 +416,7 @@ extern PSI_stage_info stage_statistics; extern PSI_stage_info stage_storing_result_in_query_cache; extern PSI_stage_info stage_storing_row_into_queue; extern PSI_stage_info stage_system_lock; +extern PSI_stage_info stage_unlocking_tables; extern PSI_stage_info stage_update; extern PSI_stage_info stage_updating; extern PSI_stage_info stage_updating_main_table; @@ -595,6 +604,15 @@ enum options_mysqld OPT_WANT_CORE, OPT_MYSQL_COMPATIBILITY, OPT_MYSQL_TO_BE_IMPLEMENTED, +#ifdef WITH_WSREP + OPT_WSREP_PROVIDER, + OPT_WSREP_PROVIDER_OPTIONS, + OPT_WSREP_CLUSTER_ADDRESS, + OPT_WSREP_START_POSITION, + OPT_WSREP_SST_AUTH, + OPT_WSREP_RECOVER, +#endif /* WITH_WSREP */ + OPT_which_is_always_the_last }; #endif diff --git a/sql/protocol.cc b/sql/protocol.cc index 2400dadfadc..caa00dd80e3 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -488,6 +488,8 @@ static uchar *net_store_length_fast(uchar *packet, uint length) void Protocol::end_statement() { + /* sanity check*/ + DBUG_ASSERT_IF_WSREP(!(WSREP_ON && WSREP(thd) && thd->wsrep_conflict_state == REPLAYING)); DBUG_ENTER("Protocol::end_statement"); DBUG_ASSERT(! thd->get_stmt_da()->is_sent()); bool error= FALSE; diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index a6d93d10f11..29a1b9728e5 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -305,9 +305,8 @@ unpack_row(rpl_group_info *rgi, normal unpack operation. */ uint16 const metadata= tabledef->field_metadata(i); -#ifndef DBUG_OFF uchar const *const old_pack_ptr= pack_ptr; -#endif + pack_ptr= f->unpack(f->ptr, pack_ptr, row_end, metadata); DBUG_PRINT("debug", ("field: %s; metadata: 0x%x;" " pack_ptr: 0x%lx; pack_ptr': 0x%lx; bytes: %d", @@ -316,6 +315,24 @@ unpack_row(rpl_group_info *rgi, (int) (pack_ptr - old_pack_ptr))); if (!pack_ptr) { +#ifdef WITH_WSREP + if (WSREP_ON) + { + /* + Debug message to troubleshoot bug: + https://mariadb.atlassian.net/browse/MDEV-4404 + Galera Node throws "Could not read field" error and drops out of cluster + */ + WSREP_WARN("ROW event unpack field: %s metadata: 0x%x;" + " pack_ptr: 0x%lx; conv_table %p conv_field %p table %s" + " row_end: 0x%lx", + f->field_name, metadata, + (ulong) old_pack_ptr, conv_table, conv_field, + (table_found) ? "found" : "not found", (ulong)row_end + ); + } +#endif /* WITH_WSREP */ + rgi->rli->report(ERROR_LEVEL, ER_SLAVE_CORRUPT_EVENT, "Could not read field '%s' of table '%s.%s'", f->field_name, table->s->db.str, diff --git a/sql/set_var.cc b/sql/set_var.cc index 5c1e00af33e..7ad5dc31f6e 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -556,7 +556,11 @@ int mysql_del_sys_var_chain(sys_var *first) static int show_cmp(SHOW_VAR *a, SHOW_VAR *b) { +#ifdef WITH_WSREP + return my_strcasecmp(system_charset_info, a->name, b->name); +#else return strcmp(a->name, b->name); +#endif /* WITH_WSREP */ } diff --git a/sql/set_var.h b/sql/set_var.h index bb92e555aa7..e72a8af6210 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -249,6 +249,9 @@ public: int check(THD *thd); int update(THD *thd); int light_check(THD *thd); +#ifdef WITH_WSREP + int wsrep_store_variable(THD *thd); +#endif }; @@ -355,6 +358,9 @@ extern sys_var *Sys_autocommit_ptr; CHARSET_INFO *get_old_charset_by_name(const char *old_name); +#ifdef WITH_WSREP +int sql_set_wsrep_variables(THD *thd, List *var_list); +#endif int sys_var_init(); int sys_var_add_options(DYNAMIC_ARRAY *long_options, int parse_flags); void sys_var_end(void); diff --git a/sql/slave.cc b/sql/slave.cc index f7d019a6c39..746b1d48458 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -52,6 +52,7 @@ #include "log_event.h" // Rotate_log_event, // Create_file_log_event, // Format_description_log_event +#include "wsrep_mysqld.h" #ifdef HAVE_REPLICATION @@ -4367,6 +4368,7 @@ pthread_handler_t handle_slave_sql(void *arg) my_off_t saved_skip= 0; Master_info *mi= ((Master_info*)arg); Relay_log_info* rli = &mi->rli; + my_bool wsrep_node_dropped= FALSE; const char *errmsg; rpl_group_info *serial_rgi; rpl_sql_thread_info sql_info(mi->rpl_filter); @@ -4375,6 +4377,8 @@ pthread_handler_t handle_slave_sql(void *arg) my_thread_init(); DBUG_ENTER("handle_slave_sql"); + wsrep_restart_point: + LINT_INIT(saved_master_log_pos); LINT_INIT(saved_log_pos); @@ -4503,6 +4507,12 @@ pthread_handler_t handle_slave_sql(void *arg) } #endif +#ifdef WITH_WSREP + thd->wsrep_exec_mode= LOCAL_STATE; + /* synchronize with wsrep replication */ + if (WSREP_ON) + wsrep_ready_wait(); +#endif DBUG_PRINT("master_info",("log_file_name: %s position: %s", rli->group_master_log_name, llstr(rli->group_master_log_pos,llbuff))); @@ -4603,13 +4613,21 @@ log '%s' at position %s, relay log '%s' position: %s%s", RPL_LOG_NAME, rli->group_master_log_name, (ulong) rli->group_master_log_pos); saved_skip= 0; } - + if (exec_relay_log_event(thd, rli, serial_rgi)) { DBUG_PRINT("info", ("exec_relay_log_event() failed")); // do not scare the user if SQL thread was simply killed or stopped if (!sql_slave_killed(serial_rgi)) + { slave_output_error_info(rli, thd); +#ifdef WITH_WSREP + if (WSREP_ON && rli->last_error().number == ER_UNKNOWN_COM_ERROR) + { + wsrep_node_dropped= TRUE; + } +#endif /* WITH_WSREP */ + } goto err; } } @@ -4694,6 +4712,27 @@ err_during_init: delete serial_rgi; delete thd; mysql_mutex_unlock(&LOCK_thread_count); +#ifdef WITH_WSREP + /* if slave stopped due to node going non primary, we set global flag to + trigger automatic restart of slave when node joins back to cluster + */ + if (WSREP_ON && wsrep_node_dropped && wsrep_restart_slave) + { + if (wsrep_ready) + { + WSREP_INFO("Slave error due to node temporarily non-primary" + "SQL slave will continue"); + wsrep_node_dropped= FALSE; + mysql_mutex_unlock(&rli->run_lock); + goto wsrep_restart_point; + } else { + WSREP_INFO("Slave error due to node going non-primary"); + WSREP_INFO("wsrep_restart_slave was set and therefore slave will be " + "automatically restarted when node joins back to cluster"); + wsrep_restart_slave_activated= TRUE; + } + } +#endif /* WITH_WSREP */ /* Note: the order of the broadcast and unlock calls below (first broadcast, then unlock) is important. Otherwise a killer_thread can execute between the calls and diff --git a/sql/sp.cc b/sql/sp.cc index 188b311ae86..261299464c5 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -32,7 +32,7 @@ #include -static bool +bool create_string(THD *thd, String *buf, stored_procedure_type sp_type, const char *db, ulong dblen, @@ -924,7 +924,7 @@ end: } -static void +void sp_returns_type(THD *thd, String &result, sp_head *sp) { TABLE table; @@ -2126,7 +2126,7 @@ int sp_cache_routine(THD *thd, enum stored_procedure_type type, sp_name *name, @return Returns TRUE on success, FALSE on (alloc) failure. */ -static bool +bool create_string(THD *thd, String *buf, stored_procedure_type type, const char *db, ulong dblen, @@ -2271,3 +2271,4 @@ sp_load_for_information_schema(THD *thd, TABLE *proc_table, String *db, thd->lex= old_lex; return sp; } + diff --git a/sql/sp.h b/sql/sp.h index 3353132346b..de32b5454f8 100644 --- a/sql/sp.h +++ b/sql/sp.h @@ -214,4 +214,19 @@ bool load_collation(MEM_ROOT *mem_root, CHARSET_INFO *dflt_cl, CHARSET_INFO **cl); +void sp_returns_type(THD *thd, + String &result, + sp_head *sp); + +bool create_string(THD *thd, String *buf, + stored_procedure_type type, + const char *db, ulong dblen, + const char *name, ulong namelen, + const char *params, ulong paramslen, + const char *returns, ulong returnslen, + const char *body, ulong bodylen, + st_sp_chistics *chistics, + const LEX_STRING *definer_user, + const LEX_STRING *definer_host, + ulonglong sql_mode); #endif /* _SP_H_ */ diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 106036e1e83..e67a019d1f7 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2559,7 +2559,9 @@ int check_alter_user(THD *thd, const char *host, const char *user) my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables"); goto end; } - if (!thd->slave_thread && !thd->security_ctx->priv_user[0]) + + if (IF_WSREP((!WSREP(thd) || !thd->wsrep_applier), 1) && + !thd->slave_thread && !thd->security_ctx->priv_user[0]) { my_message(ER_PASSWORD_ANONYMOUS_USER, ER(ER_PASSWORD_ANONYMOUS_USER), MYF(0)); @@ -2570,7 +2572,9 @@ int check_alter_user(THD *thd, const char *host, const char *user) my_error(ER_PASSWORD_NO_MATCH, MYF(0)); goto end; } + if (!thd->slave_thread && + IF_WSREP((!WSREP(thd) || !thd->wsrep_applier),1) && (strcmp(thd->security_ctx->priv_user, user) || my_strcasecmp(system_charset_info, host, thd->security_ctx->priv_host))) @@ -2635,10 +2639,12 @@ bool change_password(THD *thd, const char *host, const char *user, TABLE_LIST tables[TABLES_MAX]; /* Buffer should be extended when password length is extended. */ char buff[512]; - ulong query_length; + ulong query_length=0; enum_binlog_format save_binlog_format; uint new_password_len= (uint) strlen(new_password); - int result; + int result=0; + const CSET_STRING query_save = thd->query_string; + DBUG_ENTER("change_password"); DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'", host,user,new_password)); @@ -2647,6 +2653,19 @@ bool change_password(THD *thd, const char *host, const char *user, if (check_change_password(thd, host, user, new_password, new_password_len)) DBUG_RETURN(1); +#ifdef WITH_WSREP + if (WSREP(thd) && !thd->wsrep_applier) + { + query_length= sprintf(buff, "SET PASSWORD FOR '%-.120s'@'%-.120s'='%-.120s'", + user ? user : "", + host ? host : "", + new_password); + thd->set_query_inner(buff, query_length, system_charset_info); + + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, (char*)"user", NULL); + } +#endif /* WITH_WSREP */ + if ((result= open_grant_tables(thd, tables, TL_WRITE, Table_user))) DBUG_RETURN(result != 1); @@ -2708,9 +2727,23 @@ bool change_password(THD *thd, const char *host, const char *user, } end: close_mysql_tables(thd); +#ifdef WITH_WSREP + if (WSREP(thd) && !thd->wsrep_applier) + { + WSREP_TO_ISOLATION_END; + + thd->query_string = query_save; + thd->wsrep_exec_mode = LOCAL_STATE; + } +#endif /* WITH_WSREP */ thd->restore_stmt_binlog_format(save_binlog_format); DBUG_RETURN(result); + +error: + WSREP_ERROR("Repliation of SET PASSWORD failed: %s", buff); + DBUG_RETURN(result); + } int acl_check_set_default_role(THD *thd, const char *host, const char *user) @@ -2727,8 +2760,9 @@ int acl_set_default_role(THD *thd, const char *host, const char *user, int result= 1; int error; bool clear_role= FALSE; + char buff[512]; enum_binlog_format save_binlog_format; - + const CSET_STRING query_save = thd->query_string; DBUG_ENTER("acl_set_default_role"); DBUG_PRINT("enter",("host: '%s' user: '%s' rolename: '%s'", @@ -2823,7 +2857,6 @@ int acl_set_default_role(THD *thd, const char *host, const char *user, result= 0; if (mysql_bin_log.is_open()) { - char buff[512]; int query_length= sprintf(buff,"SET DEFAULT ROLE '%-.120s' FOR '%-.120s'@'%-.120s'", safe_str(acl_user->default_rolename.str), @@ -2835,6 +2868,17 @@ int acl_set_default_role(THD *thd, const char *host, const char *user, } end: close_mysql_tables(thd); + +#ifdef WITH_WSREP + if (WSREP(thd) && !thd->wsrep_applier) + { + WSREP_TO_ISOLATION_END; + + thd->query_string = query_save; + thd->wsrep_exec_mode = LOCAL_STATE; + } +#endif /* WITH_WSREP */ + thd->restore_stmt_binlog_format(save_binlog_format); DBUG_RETURN(result); diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index 34a076cc327..0b610718cd0 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -1143,6 +1143,8 @@ bool Sql_cmd_analyze_table::execute(THD *thd) FALSE, UINT_MAX, FALSE)) goto error; thd->enable_slow_log= opt_log_slow_admin_statements; + WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL); + res= mysql_admin_table(thd, first_table, &m_lex->check_opt, "analyze", lock_type, 1, 0, 0, 0, &handler::ha_analyze, 0); @@ -1197,6 +1199,7 @@ bool Sql_cmd_optimize_table::execute(THD *thd) if (check_table_access(thd, SELECT_ACL | INSERT_ACL, first_table, FALSE, UINT_MAX, FALSE)) goto error; /* purecov: inspected */ + WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL) thd->enable_slow_log= opt_log_slow_admin_statements; res= (specialflag & SPECIAL_NO_NEW_FUNC) ? mysql_recreate_table(thd, first_table, true) : @@ -1230,6 +1233,7 @@ bool Sql_cmd_repair_table::execute(THD *thd) FALSE, UINT_MAX, FALSE)) goto error; /* purecov: inspected */ thd->enable_slow_log= opt_log_slow_admin_statements; + WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL) res= mysql_admin_table(thd, first_table, &m_lex->check_opt, "repair", TL_WRITE, 1, MY_TEST(m_lex->check_opt.sql_flags & TT_USEFRM), diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc index 97b9c127c22..cfe360217c2 100644 --- a/sql/sql_alter.cc +++ b/sql/sql_alter.cc @@ -18,6 +18,7 @@ // mysql_exchange_partition #include "sql_base.h" // open_temporary_tables #include "sql_alter.h" +#include "wsrep_mysqld.h" Alter_info::Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root) :drop_list(rhs.drop_list, mem_root), @@ -303,6 +304,22 @@ bool Sql_cmd_alter_table::execute(THD *thd) thd->enable_slow_log= opt_log_slow_admin_statements; +#ifdef WITH_WSREP + TABLE *find_temporary_table(THD *thd, const TABLE_LIST *tl); + + if (WSREP(thd) && + (!thd->is_current_stmt_binlog_format_row() || + !find_temporary_table(thd, first_table)) && + wsrep_to_isolation_begin(thd, + lex->name.str ? select_lex->db : NULL, + lex->name.str ? lex->name.str : NULL, + first_table)) + { + WSREP_WARN("ALTER TABLE isolation failure"); + DBUG_RETURN(TRUE); + } +#endif /* WITH_WSREP */ + result= mysql_alter_table(thd, select_lex->db, lex->name.str, &create_info, first_table, diff --git a/sql/sql_base.cc b/sql/sql_base.cc index d60506dcad7..68f325e20ab 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -61,7 +61,8 @@ #ifdef __WIN__ #include #endif - +#include "wsrep_mysqld.h" +#include "wsrep_thd.h" bool No_such_table_error_handler::handle_condition(THD *, @@ -3557,7 +3558,7 @@ thr_lock_type read_lock_type_for_table(THD *thd, */ bool log_on= mysql_bin_log.is_open() && thd->variables.sql_log_bin; ulong binlog_format= thd->variables.binlog_format; - if ((log_on == FALSE) || (binlog_format == BINLOG_FORMAT_ROW) || + if ((log_on == FALSE) || (WSREP_FORMAT(binlog_format) == BINLOG_FORMAT_ROW) || (table_list->table->s->table_category == TABLE_CATEGORY_LOG) || (table_list->table->s->table_category == TABLE_CATEGORY_PERFORMANCE) || !(is_update_query(prelocking_ctx->sql_command) || @@ -4585,8 +4586,29 @@ restart: } } +#ifdef WITH_WSREP + if (WSREP_ON && + (thd->lex->sql_command== SQLCOM_INSERT || + thd->lex->sql_command== SQLCOM_INSERT_SELECT || + thd->lex->sql_command== SQLCOM_REPLACE || + thd->lex->sql_command== SQLCOM_REPLACE_SELECT || + thd->lex->sql_command== SQLCOM_UPDATE || + thd->lex->sql_command== SQLCOM_UPDATE_MULTI || + thd->lex->sql_command== SQLCOM_LOAD || + thd->lex->sql_command== SQLCOM_DELETE) && + wsrep_replicate_myisam && + (*start) && + (*start)->table && (*start)->table->file->ht->db_type == DB_TYPE_MYISAM) + { + WSREP_TO_ISOLATION_BEGIN(NULL, NULL, (*start)); + } + error: +#endif + err: THD_STAGE_INFO(thd, stage_after_opening_tables); + thd_proc_info(thd, 0); + free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block if (error && *table_to_open) @@ -5040,6 +5062,8 @@ end: close_thread_tables(thd); } THD_STAGE_INFO(thd, stage_after_opening_tables); + + thd_proc_info(thd, 0); DBUG_RETURN(table); } @@ -5303,7 +5327,7 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count, We can solve these problems in mixed mode by switching to binlogging if at least one updated table is used by sub-statement */ - if (thd->variables.binlog_format != BINLOG_FORMAT_ROW && tables && + if (WSREP_FORMAT(thd->variables.binlog_format) != BINLOG_FORMAT_ROW && tables && has_write_table_with_auto_increment(thd->lex->first_not_own_table())) thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_AUTOINC_COLUMNS); } @@ -8993,7 +9017,17 @@ bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use, (e.g. see partitioning code). */ if (!thd_table->needs_reopen()) - signalled|= mysql_lock_abort_for_thread(thd, thd_table); + { + signalled|= mysql_lock_abort_for_thread(thd, thd_table); +#ifdef WITH_WSREP + if (thd && WSREP(thd) && wsrep_thd_is_BF((void *)thd, true)) + { + WSREP_DEBUG("remove_table_from_cache: %llu", + (unsigned long long) thd->real_id); + wsrep_abort_thd((void *)thd, (void *)in_use, FALSE); + } +#endif + } } mysql_mutex_unlock(&in_use->LOCK_thd_data); } diff --git a/sql/sql_builtin.cc.in b/sql/sql_builtin.cc.in index 63850650ac9..2de475b0a76 100644 --- a/sql/sql_builtin.cc.in +++ b/sql/sql_builtin.cc.in @@ -25,7 +25,11 @@ extern #endif builtin_maria_plugin @mysql_mandatory_plugins@ @mysql_optional_plugins@ - builtin_maria_binlog_plugin, builtin_maria_mysql_password_plugin; + builtin_maria_binlog_plugin, +#ifdef WITH_WSREP + builtin_wsrep_plugin@mysql_plugin_defs@, +#endif /* WITH_WSREP */ + builtin_maria_mysql_password_plugin; struct st_maria_plugin *mysql_optional_plugins[]= { @@ -35,5 +39,8 @@ struct st_maria_plugin *mysql_optional_plugins[]= struct st_maria_plugin *mysql_mandatory_plugins[]= { builtin_maria_binlog_plugin, builtin_maria_mysql_password_plugin, +#ifdef WITH_WSREP + builtin_wsrep_plugin@mysql_plugin_defs@, +#endif /* WITH_WSREP */ @mysql_mandatory_plugins@ 0 }; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 8d6ddc0bb08..443da8557ad 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -64,6 +64,8 @@ #include "sql_parse.h" // is_update_query #include "sql_callback.h" #include "lock.h" +#include "wsrep_mysqld.h" +#include "wsrep_thd.h" #include "sql_connect.h" /* @@ -859,7 +861,7 @@ bool Drop_table_error_handler::handle_condition(THD *thd, } -THD::THD() +THD::THD(bool is_applier) :Statement(&main_lex, &main_mem_root, STMT_CONVENTIONAL_EXECUTION, /* statement id */ 0), rli_fake(0), rgi_fake(0), rgi_slave(NULL), @@ -889,6 +891,16 @@ THD::THD() bootstrap(0), derived_tables_processing(FALSE), spcont(NULL), +#ifdef WITH_WSREP + wsrep_applier(is_applier), + wsrep_applier_closing(false), + wsrep_client_thread(false), + wsrep_po_handle(WSREP_PO_INITIALIZER), + wsrep_po_cnt(0), +// wsrep_po_in_trans(false), + wsrep_apply_format(0), + wsrep_apply_toi(false), +#endif m_parser_state(NULL), #if defined(ENABLED_DEBUG_SYNC) debug_sync_control(0), @@ -1004,6 +1016,22 @@ THD::THD() m_command=COM_CONNECT; *scramble= '\0'; +#ifdef WITH_WSREP + mysql_mutex_init(key_LOCK_wsrep_thd, &LOCK_wsrep_thd, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_wsrep_thd, &COND_wsrep_thd, NULL); + wsrep_ws_handle.trx_id = WSREP_UNDEFINED_TRX_ID; + wsrep_ws_handle.opaque = NULL; + wsrep_retry_counter = 0; + wsrep_PA_safe = true; + wsrep_retry_query = NULL; + wsrep_retry_query_len = 0; + wsrep_retry_command = COM_CONNECT; + wsrep_consistency_check = NO_CONSISTENCY_CHECK; + wsrep_status_vars = 0; + wsrep_mysql_replicated = 0; + wsrep_TOI_pre_query = NULL; + wsrep_TOI_pre_query_len = 0; +#endif /* Call to init() below requires fully initialized Open_tables_state. */ reset_open_tables_state(this); @@ -1043,6 +1071,9 @@ THD::THD() my_rnd_init(&rand, tmp + (ulong) &rand, tmp + (ulong) ::global_query_id); substitute_null_with_insert_id = FALSE; thr_lock_info_init(&lock_info); /* safety: will be reset after start */ + lock_info.mysql_thd= (void *)this; + + wsrep_info[sizeof(wsrep_info) - 1] = '\0'; /* make sure it is 0-terminated */ m_internal_handler= NULL; m_binlog_invoker= INVOKER_NONE; @@ -1387,7 +1418,24 @@ void THD::init(void) bzero((char *) &org_status_var, sizeof(org_status_var)); start_bytes_received= 0; last_commit_gtid.seq_no= 0; +#ifdef WITH_WSREP + wsrep_exec_mode= wsrep_applier ? REPL_RECV : LOCAL_STATE; + wsrep_conflict_state= NO_CONFLICT; + wsrep_query_state= QUERY_IDLE; + wsrep_last_query_id= 0; + wsrep_trx_meta.gtid= WSREP_GTID_UNDEFINED; + wsrep_trx_meta.depends_on= WSREP_SEQNO_UNDEFINED; + wsrep_converted_lock_session= false; + wsrep_retry_counter= 0; + wsrep_rli= NULL; + wsrep_rgi= NULL; + wsrep_PA_safe= true; + wsrep_consistency_check = NO_CONSISTENCY_CHECK; + wsrep_mysql_replicated = 0; + wsrep_TOI_pre_query = NULL; + wsrep_TOI_pre_query_len = 0; +#endif if (variables.sql_log_bin) variables.option_bits|= OPTION_BIN_LOG; else @@ -1582,6 +1630,14 @@ THD::~THD() mysql_mutex_lock(&LOCK_thd_data); mysql_mutex_unlock(&LOCK_thd_data); +#ifdef WITH_WSREP + mysql_mutex_lock(&LOCK_wsrep_thd); + mysql_mutex_unlock(&LOCK_wsrep_thd); + mysql_mutex_destroy(&LOCK_wsrep_thd); + if (wsrep_rli) delete wsrep_rli; + if (wsrep_rgi) delete wsrep_rgi; + if (wsrep_status_vars) wsrep->stats_free(wsrep, wsrep_status_vars); +#endif /* Close connection */ #ifndef EMBEDDED_LIBRARY if (net.vio) @@ -1892,7 +1948,17 @@ bool THD::notify_shared_lock(MDL_context_owner *ctx_in_use, (e.g. see partitioning code). */ if (!thd_table->needs_reopen()) + { signalled|= mysql_lock_abort_for_thread(this, thd_table); +#if WITH_WSREP + if (this && WSREP(this) && wsrep_thd_is_BF((void *)this, FALSE)) + { + WSREP_DEBUG("remove_table_from_cache: %llu", + (unsigned long long) this->real_id); + wsrep_abort_thd((void *)this, (void *)in_use, FALSE); + } +#endif /* WITH_WSREP */ + } } mysql_mutex_unlock(&in_use->LOCK_thd_data); } @@ -2074,6 +2140,12 @@ void THD::cleanup_after_query() /* reset table map for multi-table update */ table_map_for_update= 0; m_binlog_invoker= INVOKER_NONE; +#ifdef WITH_WSREP + if (TOTAL_ORDER == wsrep_exec_mode) + { + wsrep_exec_mode = LOCAL_STATE; + } +#endif /* WITH_WSREP */ #ifndef EMBEDDED_LIBRARY if (rgi_slave) @@ -2496,6 +2568,13 @@ bool sql_exchange::escaped_given(void) bool select_send::send_result_set_metadata(List &list, uint flags) { bool res; +#ifdef WITH_WSREP + if (WSREP(thd) && thd->wsrep_retry_query) + { + WSREP_DEBUG("skipping select metadata"); + return FALSE; + } +#endif /* WITH_WSREP */ if (!(res= thd->protocol->send_result_set_metadata(&list, flags))) is_result_set_started= 1; return res; @@ -4241,8 +4320,10 @@ extern "C" int thd_non_transactional_update(const MYSQL_THD thd) extern "C" int thd_binlog_format(const MYSQL_THD thd) { - if (mysql_bin_log.is_open() && (thd->variables.option_bits & OPTION_BIN_LOG)) - return (int) thd->variables.binlog_format; + if (IF_WSREP(((WSREP(thd) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()), + mysql_bin_log.is_open()) && + thd->variables.option_bits & OPTION_BIN_LOG) + return (int) WSREP_FORMAT(thd->variables.binlog_format); else return BINLOG_FORMAT_UNSPEC; } @@ -4972,7 +5053,7 @@ int THD::decide_logging_format(TABLE_LIST *tables) binlog by filtering rules. */ if (mysql_bin_log.is_open() && (variables.option_bits & OPTION_BIN_LOG) && - !(variables.binlog_format == BINLOG_FORMAT_STMT && + !(WSREP_FORMAT(variables.binlog_format) == BINLOG_FORMAT_STMT && !binlog_filter->db_ok(db))) { /* @@ -5182,7 +5263,7 @@ int THD::decide_logging_format(TABLE_LIST *tables) */ my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE), MYF(0)); } - else if (variables.binlog_format == BINLOG_FORMAT_ROW && + else if (WSREP_FORMAT(variables.binlog_format) == BINLOG_FORMAT_ROW && sqlcom_can_generate_row_events(this)) { /* @@ -5211,7 +5292,7 @@ int THD::decide_logging_format(TABLE_LIST *tables) else { /* binlog_format = STATEMENT */ - if (variables.binlog_format == BINLOG_FORMAT_STMT) + if (WSREP_FORMAT(variables.binlog_format) == BINLOG_FORMAT_STMT) { if (lex->is_stmt_row_injection()) { @@ -5228,7 +5309,10 @@ int THD::decide_logging_format(TABLE_LIST *tables) 5. Error: Cannot modify table that uses a storage engine limited to row-logging when binlog_format = STATEMENT */ - my_error((error= ER_BINLOG_STMT_MODE_AND_ROW_ENGINE), MYF(0), ""); + if (IF_WSREP((!WSREP(this) || wsrep_exec_mode == LOCAL_STATE),1)) + { + my_error((error= ER_BINLOG_STMT_MODE_AND_ROW_ENGINE), MYF(0), ""); + } } else if (is_write && (unsafe_flags= lex->get_stmt_unsafe_flags()) != 0) { @@ -5340,7 +5424,7 @@ int THD::decide_logging_format(TABLE_LIST *tables) "and binlog_filter->db_ok(db) = %d", mysql_bin_log.is_open(), (variables.option_bits & OPTION_BIN_LOG), - variables.binlog_format, + WSREP_FORMAT(variables.binlog_format), binlog_filter->db_ok(db))); #endif @@ -5576,9 +5660,11 @@ CPP_UNNAMED_NS_END int THD::binlog_write_row(TABLE* table, bool is_trans, MY_BITMAP const* cols, size_t colcnt, uchar const *record) -{ - DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open()); +{ + DBUG_ASSERT(is_current_stmt_binlog_format_row() && + IF_WSREP(((WSREP(this) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()), + mysql_bin_log.is_open())); /* Pack records into format for transfer. We are allocating more memory than needed, but that doesn't matter. @@ -5610,8 +5696,10 @@ int THD::binlog_update_row(TABLE* table, bool is_trans, MY_BITMAP const* cols, size_t colcnt, const uchar *before_record, const uchar *after_record) -{ - DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open()); +{ + DBUG_ASSERT(is_current_stmt_binlog_format_row() && + IF_WSREP(((WSREP(this) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()), + mysql_bin_log.is_open())); size_t const before_maxlen = max_row_length(table, before_record); size_t const after_maxlen = max_row_length(table, after_record); @@ -5659,8 +5747,10 @@ int THD::binlog_update_row(TABLE* table, bool is_trans, int THD::binlog_delete_row(TABLE* table, bool is_trans, MY_BITMAP const* cols, size_t colcnt, uchar const *record) -{ - DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open()); +{ + DBUG_ASSERT(is_current_stmt_binlog_format_row() && + IF_WSREP(((WSREP(this) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()), + mysql_bin_log.is_open())); /* Pack records into format for transfer. We are allocating more @@ -5695,7 +5785,8 @@ int THD::binlog_remove_pending_rows_event(bool clear_maps, { DBUG_ENTER("THD::binlog_remove_pending_rows_event"); - if (!mysql_bin_log.is_open()) + IF_WSREP(!(WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open()), + !mysql_bin_log.is_open()); DBUG_RETURN(0); /* Ensure that all events in a GTID group are in the same cache */ @@ -5718,7 +5809,8 @@ int THD::binlog_flush_pending_rows_event(bool stmt_end, bool is_transactional) mode: it might be the case that we left row-based mode before flushing anything (e.g., if we have explicitly locked tables). */ - if (!mysql_bin_log.is_open()) + if(IF_WSREP(!(WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open()), + !mysql_bin_log.is_open())) DBUG_RETURN(0); /* Ensure that all events in a GTID group are in the same cache */ @@ -5970,7 +6062,10 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg, DBUG_ENTER("THD::binlog_query"); DBUG_PRINT("enter", ("qtype: %s query: '%-.*s'", show_query_type(qtype), (int) query_len, query_arg)); - DBUG_ASSERT(query_arg && mysql_bin_log.is_open()); + + DBUG_ASSERT(query_arg && + IF_WSREP((WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open()), + mysql_bin_log.is_open())); /* If this is withing a BEGIN ... COMMIT group, don't log it */ if (variables.option_bits & OPTION_GTID_BEGIN) diff --git a/sql/sql_class.h b/sql/sql_class.h index f3537086132..d3b305d34f4 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -50,12 +50,13 @@ void set_thd_stage_info(void *thd, const char *calling_func, const char *calling_file, const unsigned int calling_line); - + #define THD_STAGE_INFO(thd, stage) \ (thd)->enter_stage(& stage, NULL, __func__, __FILE__, __LINE__) #include "my_apc.h" #include "rpl_gtid.h" +#include "wsrep_mysqld.h" class Reprepare_observer; class Relay_log_info; @@ -638,6 +639,12 @@ typedef struct system_variables ulong wt_timeout_short, wt_deadlock_search_depth_short; ulong wt_timeout_long, wt_deadlock_search_depth_long; +#ifdef WITH_WSREP + my_bool wsrep_on; + my_bool wsrep_causal_reads; + uint wsrep_sync_wait; + ulong wsrep_retry_autocommit; +#endif double long_query_time_double; my_bool pseudo_slave_mode; @@ -2072,7 +2079,7 @@ public: int is_current_stmt_binlog_format_row() const { DBUG_ASSERT(current_stmt_binlog_format == BINLOG_FORMAT_STMT || current_stmt_binlog_format == BINLOG_FORMAT_ROW); - return current_stmt_binlog_format == BINLOG_FORMAT_ROW; + return (WSREP_FORMAT((ulong)current_stmt_binlog_format) == BINLOG_FORMAT_ROW); } enum binlog_filter_state @@ -2725,6 +2732,45 @@ public: query_id_t first_query_id; } binlog_evt_union; +#ifdef WITH_WSREP + const bool wsrep_applier; /* dedicated slave applier thread */ + bool wsrep_applier_closing; /* applier marked to close */ + bool wsrep_client_thread; /* to identify client threads*/ + bool wsrep_PA_safe; + bool wsrep_converted_lock_session; + bool wsrep_apply_toi; /* applier processing in TOI */ + enum wsrep_exec_mode wsrep_exec_mode; + query_id_t wsrep_last_query_id; + enum wsrep_query_state wsrep_query_state; + enum wsrep_conflict_state wsrep_conflict_state; + mysql_mutex_t LOCK_wsrep_thd; + mysql_cond_t COND_wsrep_thd; + // changed from wsrep_seqno_t to wsrep_trx_meta_t in wsrep API rev 75 + // wsrep_seqno_t wsrep_trx_seqno; + wsrep_trx_meta_t wsrep_trx_meta; + uint32 wsrep_rand; + Relay_log_info* wsrep_rli; + rpl_group_info* wsrep_rgi; + wsrep_ws_handle_t wsrep_ws_handle; + ulong wsrep_retry_counter; // of autocommit + char* wsrep_retry_query; + size_t wsrep_retry_query_len; + enum enum_server_command wsrep_retry_command; + enum wsrep_consistency_check_mode + wsrep_consistency_check; + wsrep_stats_var* wsrep_status_vars; + int wsrep_mysql_replicated; + const char* wsrep_TOI_pre_query; /* a query to apply before + the actual TOI query */ + size_t wsrep_TOI_pre_query_len; + wsrep_po_handle_t wsrep_po_handle; + size_t wsrep_po_cnt; +#ifdef GTID_SUPPORT + rpl_sid wsrep_po_sid; +#endif /* GTID_SUPPORT */ + void* wsrep_apply_format; +#endif /* WITH_WSREP */ + char wsrep_info[128]; /* string for dynamic proc info */ /** Internal parser state. Note that since the parser is not re-entrant, we keep only one parser @@ -2756,7 +2802,8 @@ public: /* Debug Sync facility. See debug_sync.cc. */ struct st_debug_sync_control *debug_sync_control; #endif /* defined(ENABLED_DEBUG_SYNC) */ - THD(); + THD(bool is_applier= false); + ~THD(); void init(void); @@ -3270,7 +3317,7 @@ public: tests fail and so force them to propagate the lex->binlog_row_based_if_mixed upwards to the caller. */ - if ((variables.binlog_format == BINLOG_FORMAT_MIXED) && + if ((WSREP_FORMAT(variables.binlog_format) == BINLOG_FORMAT_MIXED) && (in_sub_stmt == 0)) set_current_stmt_binlog_format_row(); @@ -3322,7 +3369,7 @@ public: show_system_thread(system_thread))); if (in_sub_stmt == 0) { - if (variables.binlog_format == BINLOG_FORMAT_ROW) + if (WSREP_FORMAT(variables.binlog_format) == BINLOG_FORMAT_ROW) set_current_stmt_binlog_format_row(); else if (temporary_tables == NULL) set_current_stmt_binlog_format_stmt(); diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 433f3303ad7..0065edcc14d 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -37,6 +37,7 @@ // reset_host_errors #include "sql_acl.h" // acl_getroot, NO_ACCESS, SUPER_ACL #include "sql_callback.h" +#include "wsrep_mysqld.h" HASH global_user_stats, global_client_stats, global_table_stats; HASH global_index_stats; @@ -1172,6 +1173,17 @@ bool login_connection(THD *thd) void end_connection(THD *thd) { NET *net= &thd->net; +#ifdef WITH_WSREP + if (WSREP(thd)) + { + wsrep_status_t rcode= wsrep->free_connection(wsrep, thd->thread_id); + if (rcode) { + WSREP_WARN("wsrep failed to free connection context: %lu, code: %d", + thd->thread_id, rcode); + } + } + thd->wsrep_client_thread= 0; +#endif plugin_thdvar_cleanup(thd); if (thd->user_connect) @@ -1307,6 +1319,9 @@ bool thd_prepare_connection(THD *thd) (char *) thd->security_ctx->host_or_ip); prepare_new_connection_state(thd); +#ifdef WITH_WSREP + thd->wsrep_client_thread= 1; +#endif /* WITH_WSREP */ return FALSE; } @@ -1380,7 +1395,15 @@ void do_handle_one_connection(THD *thd_arg) break; } end_connection(thd); - + +#ifdef WITH_WSREP + if (WSREP(thd)) + { + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + thd->wsrep_query_state= QUERY_EXITING; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } +#endif end_thread: close_connection(thd); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 38fb897c4f8..5eb4c405c4b 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -642,18 +642,19 @@ cleanup: if (!transactional_table && deleted > 0) thd->transaction.stmt.modified_non_trans_table= thd->transaction.all.modified_non_trans_table= TRUE; - + /* See similar binlogging code in sql_update.cc, for comments */ if ((error < 0) || thd->transaction.stmt.modified_non_trans_table) { - if (mysql_bin_log.is_open()) + if(IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), + mysql_bin_log.is_open())) { int errcode= 0; if (error < 0) thd->clear_error(); else errcode= query_error_code(thd, killed_status == NOT_KILLED); - + /* [binlog]: If 'handler::delete_all_rows()' was called and the storage engine does not inject the rows itself, we replicate @@ -1107,13 +1108,14 @@ void multi_delete::abort_result_set() DBUG_ASSERT(error_handled); DBUG_VOID_RETURN; } - + if (thd->transaction.stmt.modified_non_trans_table) { - /* + /* there is only side effects; to binlog with the error */ - if (mysql_bin_log.is_open()) + if (IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), + mysql_bin_log.is_open())) { int errcode= query_error_code(thd, thd->killed == NOT_KILLED); /* possible error of writing binary log is ignored deliberately */ @@ -1289,7 +1291,8 @@ bool multi_delete::send_eof() } if ((local_error == 0) || thd->transaction.stmt.modified_non_trans_table) { - if (mysql_bin_log.is_open()) + if(IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), + mysql_bin_log.is_open())) { int errcode= 0; if (local_error == 0) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index d61af758ced..f90e9cd2439 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1014,7 +1014,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, thd->transaction.stmt.modified_non_trans_table || was_insert_delayed) { - if (mysql_bin_log.is_open()) + if(IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), + mysql_bin_log.is_open())) { int errcode= 0; if (error <= 0) @@ -3195,6 +3196,13 @@ bool Delayed_insert::handle_inserts(void) mysql_cond_broadcast(&cond_client); // If waiting clients } } + +#ifdef WITH_WSREP + if (WSREP((&thd))) + thd_proc_info(&thd, "insert done"); + else +#endif /* WITH_WSREP */ + thd_proc_info(&thd, 0); mysql_mutex_unlock(&mutex); /* @@ -3647,8 +3655,11 @@ bool select_insert::send_eof() DBUG_PRINT("enter", ("trans_table=%d, table_type='%s'", trans_table, table->file->table_type())); - error= (thd->locked_tables_mode <= LTM_LOCK_TABLES ? - table->file->ha_end_bulk_insert() : 0); + error = IF_WSREP((thd->wsrep_conflict_state == MUST_ABORT || + thd->wsrep_conflict_state == CERT_FAILURE) ? -1 :, ) + (thd->locked_tables_mode <= LTM_LOCK_TABLES ? + table->file->ha_end_bulk_insert() : 0); + if (!error && thd->is_error()) error= thd->get_stmt_da()->sql_errno(); @@ -3676,8 +3687,9 @@ bool select_insert::send_eof() events are in the transaction cache and will be written when ha_autocommit_or_rollback() is issued below. */ - if (mysql_bin_log.is_open() && - (!error || thd->transaction.stmt.modified_non_trans_table)) + if(IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), + mysql_bin_log.is_open()) && + (!error || thd->transaction.stmt.modified_non_trans_table)) { int errcode= 0; if (!error) @@ -3761,7 +3773,8 @@ void select_insert::abort_result_set() { if (!can_rollback_data()) thd->transaction.all.modified_non_trans_table= TRUE; - if (mysql_bin_log.is_open()) + if(IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), + mysql_bin_log.is_open())) { int errcode= query_error_code(thd, thd->killed == NOT_KILLED); /* error of writing binary log is ignored */ @@ -4169,7 +4182,8 @@ select_create::binlog_show_create_table(TABLE **tables, uint count) create_info->table_was_deleted); DBUG_ASSERT(result == 0); /* store_create_info() always return 0 */ - if (mysql_bin_log.is_open()) + if(IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), + mysql_bin_log.is_open())) { int errcode= query_error_code(thd, thd->killed == NOT_KILLED); result= thd->binlog_query(THD::STMT_QUERY_TYPE, @@ -4179,6 +4193,9 @@ select_create::binlog_show_create_table(TABLE **tables, uint count) /* suppress_use */ FALSE, errcode); } + + IF_WSREP(ha_fake_trx_id(thd), ); + return result; } @@ -4208,6 +4225,21 @@ bool select_create::send_eof() trans_commit_stmt(thd); if (!(thd->variables.option_bits & OPTION_GTID_BEGIN)) trans_commit_implicit(thd); +#ifdef WITH_WSREP + if (WSREP_ON) + { + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + if (thd->wsrep_conflict_state != NO_CONFLICT) + { + WSREP_DEBUG("select_create commit failed, thd: %lu err: %d %s", + thd->thread_id, thd->wsrep_conflict_state, thd->query()); + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + abort_result_set(); + return TRUE; + } + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } +#endif /* WITH_WSREP */ } else if (!thd->is_current_stmt_binlog_format_row()) table->s->table_creation_was_logged= 1; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index cd9f9238f71..926aa7d5e5a 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2009, 2013, Monty Program Ab. + Copyright (c) 2009, 2014, Monty Program Ab. 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 @@ -1579,6 +1579,17 @@ int lex_one_token(void *arg, THD *thd) } else { +#ifdef WITH_WSREP + if (WSREP(thd) && version == 99997 && thd->wsrep_exec_mode == LOCAL_STATE) + { + WSREP_DEBUG("consistency check: %s", thd->query()); + thd->wsrep_consistency_check= CONSISTENCY_CHECK_DECLARED; + lip->yySkipn(5); + lip->set_echo(TRUE); + state=MY_LEX_START; + break; /* Do not treat contents as a comment. */ + } +#endif /* WITH_WSREP */ /* Patch and skip the conditional comment to avoid it being propagated infinitely (eg. to a slave). diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 019fd55e3d8..066acfb015a 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2008, 2013, Monty Program Ab + Copyright (c) 2008, 2014, Monty Program Ab 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 @@ -103,6 +103,14 @@ #include "../storage/maria/ha_maria.h" #endif +#include "wsrep_mysqld.h" +#include "wsrep_thd.h" + +#ifdef WITH_WSREP +static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length, + Parser_state *parser_state); +#endif /* WITH_WSREP */ + /** @defgroup Runtime_Environment Runtime Environment @{ @@ -890,6 +898,19 @@ bool do_command(THD *thd) enum enum_server_command command; DBUG_ENTER("do_command"); +#ifdef WITH_WSREP + if (WSREP(thd)) + { + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + thd->wsrep_query_state= QUERY_IDLE; + if (thd->wsrep_conflict_state==MUST_ABORT) + { + wsrep_client_rollback(thd); + } + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } +#endif /* WITH_WSREP */ + /* indicator of uninitialized lex => normal flow of errors handling (see my_message_sql) @@ -937,6 +958,29 @@ bool do_command(THD *thd) thd->m_server_idle= TRUE; packet_length= my_net_read(net); thd->m_server_idle= FALSE; +#ifdef WITH_WSREP + if (WSREP(thd)) { + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + + /* these THD's are aborted or are aborting during being idle */ + if (thd->wsrep_conflict_state == ABORTING) + { + while (thd->wsrep_conflict_state == ABORTING) { + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + my_sleep(1000); + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + } + thd->store_globals(); + } + else if (thd->wsrep_conflict_state == ABORTED) + { + thd->store_globals(); + } + + thd->wsrep_query_state= QUERY_EXEC; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } +#endif /* WITH_WSREP */ if (packet_length == packet_error) { @@ -944,6 +988,19 @@ bool do_command(THD *thd) net->error, vio_description(net->vio))); +#ifdef WITH_WSREP + if (WSREP(thd)) + { + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + if (thd->wsrep_conflict_state == MUST_ABORT) + { + DBUG_PRINT("wsrep",("aborted for wsrep rollback: %lu", thd->real_id)); + wsrep_client_rollback(thd); + } + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } +#endif /* WITH_WSREP */ + /* Instrument this broken statement as "statement/com/error" */ thd->m_statement_psi= MYSQL_REFINE_STATEMENT(thd->m_statement_psi, com_statement_info[COM_END]. @@ -998,12 +1055,71 @@ bool do_command(THD *thd) vio_description(net->vio), command, command_name[command].str)); +#ifdef WITH_WSREP + if (WSREP(thd)) + { + /* + * bail out if DB snapshot has not been installed. We however, + * allow queries "SET" and "SHOW", they are trapped later in execute_command + */ + if (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready && + command != COM_QUERY && + command != COM_PING && + command != COM_QUIT && + command != COM_PROCESS_INFO && + command != COM_PROCESS_KILL && + command != COM_SET_OPTION && + command != COM_SHUTDOWN && + command != COM_SLEEP && + command != COM_STATISTICS && + command != COM_TIME && + command != COM_END + ) { + my_message(ER_UNKNOWN_COM_ERROR, + "WSREP has not yet prepared node for application use", + MYF(0)); + thd->protocol->end_statement(); + return_value= FALSE; + goto out; + } + } +#endif /* WITH_WSREP */ /* Restore read timeout value */ my_net_set_read_timeout(net, thd->variables.net_read_timeout); DBUG_ASSERT(packet_length); DBUG_ASSERT(!thd->apc_target.is_enabled()); return_value= dispatch_command(command, thd, packet+1, (uint) (packet_length-1)); +#ifdef WITH_WSREP + if (WSREP(thd)) + { + while (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT) + { + WSREP_DEBUG("Retry autocommit for: %s\n", thd->wsrep_retry_query); + CHARSET_INFO *current_charset = thd->variables.character_set_client; + if (!is_supported_parser_charset(current_charset)) + { + /* Do not use non-supported parser character sets */ + WSREP_WARN("Current client character set is non-supported parser " + "character set: %s", current_charset->csname); + thd->variables.character_set_client = &my_charset_latin1; + WSREP_WARN("For retry temporally setting character set to : %s", + my_charset_latin1.csname); + } + return_value= dispatch_command(command, thd, thd->wsrep_retry_query, + thd->wsrep_retry_query_len); + thd->variables.character_set_client = current_charset; + } + + if (thd->wsrep_retry_query && thd->wsrep_conflict_state != REPLAYING) + { + my_free(thd->wsrep_retry_query); + thd->wsrep_retry_query = NULL; + thd->wsrep_retry_query_len = 0; + thd->wsrep_retry_command = COM_CONNECT; + } + } +#endif /* WITH_WSREP */ DBUG_ASSERT(!thd->apc_target.is_enabled()); out: @@ -1027,7 +1143,7 @@ out: @retval FALSE The statement isn't updating any relevant tables. */ -static my_bool deny_updates_if_read_only_option(THD *thd, +my_bool deny_updates_if_read_only_option(THD *thd, TABLE_LIST *all_tables) { DBUG_ENTER("deny_updates_if_read_only_option"); @@ -1081,6 +1197,7 @@ static my_bool deny_updates_if_read_only_option(THD *thd, DBUG_RETURN(FALSE); } + /** Perform one connection-level (COM_XXXX) command. @@ -1110,6 +1227,43 @@ bool dispatch_command(enum enum_server_command command, THD *thd, DBUG_ENTER("dispatch_command"); DBUG_PRINT("info", ("command: %d", command)); +#ifdef WITH_WSREP + if (WSREP(thd)) + { + if (!thd->in_multi_stmt_transaction_mode()) + { + thd->wsrep_PA_safe= true; + } + + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + thd->wsrep_query_state= QUERY_EXEC; + if (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT) + { + thd->wsrep_conflict_state= NO_CONFLICT; + } + if (thd->wsrep_conflict_state== MUST_ABORT) + { + wsrep_client_rollback(thd); + } + if (thd->wsrep_conflict_state== ABORTED) + { + my_error(ER_LOCK_DEADLOCK, MYF(0), "wsrep aborted transaction"); + WSREP_DEBUG("Deadlock error for: %s", thd->query()); + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + thd->killed = NOT_KILLED; + thd->mysys_var->abort = 0; + thd->wsrep_conflict_state = NO_CONFLICT; + thd->wsrep_retry_counter = 0; + /* + Increment threads running to compensate dec_thread_running() called + after dispatch_end label. + */ + inc_thread_running(); + goto dispatch_end; + } + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } +#endif /* WITH_WSREP */ #if defined(ENABLED_PROFILING) thd->profiling.start_new_query(); #endif @@ -1306,7 +1460,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (parser_state.init(thd, thd->query(), thd->query_length())) break; - mysql_parse(thd, thd->query(), thd->query_length(), &parser_state); +#ifdef WITH_WSREP + if (WSREP_ON) + wsrep_mysql_parse(thd, thd->query(), thd->query_length(), &parser_state); + else +#endif /* WITH_WSREP */ + mysql_parse(thd, thd->query(), thd->query_length(), &parser_state); while (!thd->killed && (parser_state.m_lip.found_semicolon != NULL) && ! thd->is_error()) @@ -1380,10 +1539,20 @@ bool dispatch_command(enum enum_server_command command, THD *thd, Count each statement from the client. */ statistic_increment(thd->status_var.questions, &LOCK_status); - thd->set_time(); /* Reset the query start time. */ + + if(IF_WSREP(!WSREP(thd), 1)) + thd->set_time(); /* Reset the query start time. */ + parser_state.reset(beginning_of_next_stmt, length); /* TODO: set thd->lex->sql_command to SQLCOM_END here */ - mysql_parse(thd, beginning_of_next_stmt, length, &parser_state); + +#ifdef WITH_WSREP + if (WSREP_ON) + wsrep_mysql_parse(thd, beginning_of_next_stmt, length, &parser_state); + else +#endif /* WITH_WSREP */ + mysql_parse(thd, beginning_of_next_stmt, length, &parser_state); + } DBUG_PRINT("info",("query ready")); @@ -1720,15 +1889,39 @@ bool dispatch_command(enum enum_server_command command, THD *thd, my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0)); break; } - DBUG_ASSERT(thd->derived_tables == NULL && - (thd->open_tables == NULL || +#ifdef WITH_WSREP + dispatch_end: + + if (WSREP(thd)) + { + /* wsrep BF abort in query exec phase */ + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + if ((thd->wsrep_conflict_state != REPLAYING) && + (thd->wsrep_conflict_state != RETRY_AUTOCOMMIT)) + { + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + thd->update_server_status(); + thd->protocol->end_statement(); + query_cache_end_of_result(thd); + } + else + { + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } + } + else +#endif /* WITH_WSREP */ + { + DBUG_ASSERT(thd->derived_tables == NULL && + (thd->open_tables == NULL || (thd->locked_tables_mode == LTM_LOCK_TABLES))); - thd_proc_info(thd, "updating status"); - /* Finalize server status flags after executing a command. */ - thd->update_server_status(); - thd->protocol->end_statement(); - query_cache_end_of_result(thd); + thd_proc_info(thd, "updating status"); + /* Finalize server status flags after executing a command. */ + thd->update_server_status(); + thd->protocol->end_statement(); + query_cache_end_of_result(thd); + } if (!thd->is_error() && !thd->killed_errno()) mysql_audit_general(thd, MYSQL_AUDIT_GENERAL_RESULT, 0, 0); @@ -2381,7 +2574,47 @@ mysql_execute_command(THD *thd) #ifdef HAVE_REPLICATION } /* endif unlikely slave */ #endif +#ifdef WITH_WSREP + if (WSREP(thd)) + { + /* + change LOCK TABLE WRITE to transaction + */ + if (lex->sql_command== SQLCOM_LOCK_TABLES && wsrep_convert_LOCK_to_trx) + { + for (TABLE_LIST *table= all_tables; table; table= table->next_global) + { + if (table->lock_type >= TL_WRITE_ALLOW_WRITE) + { + lex->sql_command= SQLCOM_BEGIN; + thd->wsrep_converted_lock_session= true; + break; + } + } + } + if (lex->sql_command== SQLCOM_UNLOCK_TABLES && + thd->wsrep_converted_lock_session) + { + thd->wsrep_converted_lock_session= false; + lex->sql_command= SQLCOM_COMMIT; + lex->tx_release= TVL_NO; + } + /* + * bail out if DB snapshot has not been installed. We however, + * allow SET and SHOW queries + */ + if (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready && + lex->sql_command != SQLCOM_SET_OPTION && + !wsrep_is_show_query(lex->sql_command)) + { + my_message(ER_UNKNOWN_COM_ERROR, + "WSREP has not yet prepared node for application use", + MYF(0)); + goto error; + } + } +#endif /* WITH_WSREP */ status_var_increment(thd->status_var.com_stat[lex->sql_command]); thd->progress.report_to_client= MY_TEST(sql_command_flags[lex->sql_command] & CF_REPORT_PROGRESS); @@ -2423,12 +2656,16 @@ mysql_execute_command(THD *thd) { /* Commit the normal transaction if one is active. */ if (trans_commit_implicit(thd)) + { + thd->mdl_context.release_transactional_locks(); + WSREP_DEBUG("implicit commit failed, MDL released: %lu", thd->thread_id); goto error; + } /* Release metadata locks acquired in this transaction. */ thd->mdl_context.release_transactional_locks(); } } - + #ifndef DBUG_OFF if (lex->sql_command != SQLCOM_SET_OPTION) DEBUG_SYNC(thd,"before_execute_sql_command"); @@ -2481,6 +2718,10 @@ mysql_execute_command(THD *thd) #endif case SQLCOM_SHOW_STATUS: { +#ifdef WITH_WSREP + if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) + goto error; +#endif /* WITH_WSREP */ execute_show_status(thd, all_tables); break; } @@ -2513,6 +2754,11 @@ mysql_execute_command(THD *thd) } case SQLCOM_SHOW_STATUS_PROC: case SQLCOM_SHOW_STATUS_FUNC: +#ifdef WITH_WSREP + if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) + goto error; +#endif /* WITH_WSREP */ + case SQLCOM_SHOW_DATABASES: case SQLCOM_SHOW_TABLES: case SQLCOM_SHOW_TRIGGERS: @@ -2521,16 +2767,27 @@ mysql_execute_command(THD *thd) case SQLCOM_SHOW_PLUGINS: case SQLCOM_SHOW_FIELDS: case SQLCOM_SHOW_KEYS: +#ifndef WITH_WSREP case SQLCOM_SHOW_VARIABLES: case SQLCOM_SHOW_CHARSETS: case SQLCOM_SHOW_COLLATIONS: case SQLCOM_SHOW_STORAGE_ENGINES: case SQLCOM_SHOW_PROFILE: +#endif /* WITH_WSREP */ case SQLCOM_SHOW_CLIENT_STATS: case SQLCOM_SHOW_USER_STATS: case SQLCOM_SHOW_TABLE_STATS: case SQLCOM_SHOW_INDEX_STATS: case SQLCOM_SELECT: +#ifdef WITH_WSREP + if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) + goto error; + case SQLCOM_SHOW_VARIABLES: + case SQLCOM_SHOW_CHARSETS: + case SQLCOM_SHOW_COLLATIONS: + case SQLCOM_SHOW_STORAGE_ENGINES: + case SQLCOM_SHOW_PROFILE: +#endif /* WITH_WSREP */ { thd->status_var.last_query_cost= 0.0; @@ -2554,7 +2811,7 @@ mysql_execute_command(THD *thd) res= execute_sqlcom_select(thd, all_tables); break; } -case SQLCOM_PREPARE: + case SQLCOM_PREPARE: { mysql_sql_stmt_prepare(thd); break; @@ -2888,7 +3145,7 @@ case SQLCOM_PREPARE: */ if(lex->ignore) lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_IGNORE_SELECT); - + if(lex->duplicates == DUP_REPLACE) lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_REPLACE_SELECT); @@ -2900,9 +3157,9 @@ case SQLCOM_PREPARE: raise a warning, as it may cause problems (see 'NAME_CONST issues' in 'Binary Logging of Stored Programs') */ - if (thd->query_name_consts && + if (thd->query_name_consts && mysql_bin_log.is_open() && - thd->variables.binlog_format == BINLOG_FORMAT_STMT && + WSREP_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_STMT && !mysql_bin_log.is_query_in_union(thd, thd->query_id)) { List_iterator_fast it(select_lex->item_list); @@ -3017,6 +3274,15 @@ case SQLCOM_PREPARE: } else { +#ifdef WITH_WSREP + /* in STATEMENT format, we probably have to replicate also temporary + tables, like mysql replication does + */ + if (WSREP_ON && (!thd->is_current_stmt_binlog_format_row() || + !(create_info.options & HA_LEX_CREATE_TMP_TABLE))) + WSREP_TO_ISOLATION_BEGIN(create_table->db, create_table->table_name, + NULL) +#endif /* WITH_WSREP */ /* Regular CREATE TABLE */ res= mysql_create_table(thd, create_table, &create_info, &alter_info); @@ -3055,6 +3321,7 @@ end_with_restore_list: DBUG_ASSERT(first_table == all_tables && first_table != 0); if (check_one_table_access(thd, INDEX_ACL, all_tables)) goto error; /* purecov: inspected */ + WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL) /* Currently CREATE INDEX or DROP INDEX cause a full table rebuild and thus classify as slow administrative statements just like @@ -3172,6 +3439,7 @@ end_with_restore_list: #endif /* HAVE_REPLICATION */ case SQLCOM_RENAME_TABLE: { + WSREP_TO_ISOLATION_BEGIN(0, 0, first_table) if (execute_rename_table(thd, first_table, all_tables)) goto error; break; @@ -3192,13 +3460,19 @@ end_with_restore_list: #endif #endif /* EMBEDDED_LIBRARY */ case SQLCOM_SHOW_CREATE: + { DBUG_ASSERT(first_table == all_tables && first_table != 0); #ifdef DONT_ALLOW_SHOW_COMMANDS my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */ goto error; #else - { + +#ifdef WITH_WSREP + if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) + goto error; +#endif /* WITH_WSREP */ + /* Access check: SHOW CREATE TABLE require any privileges on the table level (ie @@ -3256,11 +3530,16 @@ end_with_restore_list: /* Access is granted. Execute the command. */ res= mysqld_show_create(thd, first_table); break; - } #endif + } case SQLCOM_CHECKSUM: { DBUG_ASSERT(first_table == all_tables && first_table != 0); +#ifdef WITH_WSREP + if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) + goto error; +#endif /* WITH_WSREP */ + if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE)) goto error; /* purecov: inspected */ @@ -3272,6 +3551,12 @@ end_with_restore_list: { ha_rows found= 0, updated= 0; DBUG_ASSERT(first_table == all_tables && first_table != 0); +#ifdef WITH_WSREP + if (WSREP_CLIENT(thd) && + wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE)) + goto error; +#endif /* WITH_WSREP */ + if (update_precheck(thd, all_tables)) break; @@ -3308,6 +3593,11 @@ end_with_restore_list: /* if we switched from normal update, rights are checked */ if (up_result != 2) { +#ifdef WITH_WSREP + if (WSREP_CLIENT(thd) && + wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE)) + goto error; +#endif /* WITH_WSREP */ if ((res= multi_update_precheck(thd, all_tables))) break; } @@ -3377,6 +3667,12 @@ end_with_restore_list: break; } case SQLCOM_REPLACE: + { +#ifdef WITH_WSREP + if (WSREP_CLIENT(thd) && + wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE)) + goto error; +#endif /* WITH_WSREP */ #ifndef DBUG_OFF if (mysql_bin_log.is_open()) { @@ -3411,10 +3707,17 @@ end_with_restore_list: DBUG_PRINT("debug", ("Just after generate_incident()")); } #endif + } case SQLCOM_INSERT: { DBUG_ASSERT(first_table == all_tables && first_table != 0); +#ifdef WITH_WSREP + if (WSREP_CLIENT(thd) && + wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE)) + goto error; +#endif /* WITH_WSREP */ + /* Since INSERT DELAYED doesn't support temporary tables, we could not pre-open temporary tables for SQLCOM_INSERT / SQLCOM_REPLACE. @@ -3469,8 +3772,22 @@ end_with_restore_list: select_result *sel_result; bool explain= MY_TEST(lex->describe); DBUG_ASSERT(first_table == all_tables && first_table != 0); +#ifdef WITH_WSREP + if (WSREP_CLIENT(thd) && + wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE)) + goto error; +#endif /* WITH_WSREP */ + if ((res= insert_precheck(thd, all_tables))) break; +#ifdef WITH_WSREP + if (WSREP(thd) && thd->wsrep_consistency_check == CONSISTENCY_CHECK_DECLARED) + { + thd->wsrep_consistency_check = CONSISTENCY_CHECK_RUNNING; + WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL); + } +#endif /* WITH_WSREP */ + /* INSERT...SELECT...ON DUPLICATE KEY UPDATE/REPLACE SELECT/ INSERT...IGNORE...SELECT can be unsafe, unless ORDER BY PRIMARY KEY @@ -3561,6 +3878,12 @@ end_with_restore_list: { select_result *sel_result=lex->result; DBUG_ASSERT(first_table == all_tables && first_table != 0); +#ifdef WITH_WSREP + if (WSREP_CLIENT(thd) && + wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE)) + goto error; +#endif /* WITH_WSREP */ + if ((res= delete_precheck(thd, all_tables))) break; DBUG_ASSERT(select_lex->offset_limit == 0); @@ -3617,6 +3940,11 @@ end_with_restore_list: DBUG_ASSERT(first_table == all_tables && first_table != 0); TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first; multi_delete *result; +#ifdef WITH_WSREP + if (WSREP_CLIENT(thd) && + wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE)) + goto error; +#endif /* WITH_WSREP */ if ((res= multi_delete_precheck(thd, all_tables))) break; @@ -3687,6 +4015,21 @@ end_with_restore_list: /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */ thd->variables.option_bits|= OPTION_KEEP_LOG; } +#ifdef WITH_WSREP + if (WSREP(thd)) + { + for (TABLE_LIST *table= all_tables; table; table= table->next_global) + { + if (!lex->drop_temporary && + (!thd->is_current_stmt_binlog_format_row() || + !find_temporary_table(thd, table))) + { + WSREP_TO_ISOLATION_BEGIN(NULL, NULL, all_tables); + break; + } + } + } +#endif /* WITH_WSREP */ /* If we are a slave, we should add IF EXISTS if the query executed on the master without an error. This will help a slave to @@ -3700,8 +4043,8 @@ end_with_restore_list: /* DDL and binlog write order are protected by metadata locks. */ res= mysql_rm_table(thd, first_table, lex->check_exists, lex->drop_temporary); + break; } - break; case SQLCOM_SHOW_PROCESSLIST: if (!thd->security_ctx->priv_user[0] && check_global_access(thd,PROCESS_ACL)) @@ -3891,6 +4234,7 @@ end_with_restore_list: #endif if (check_access(thd, CREATE_ACL, lex->name.str, NULL, NULL, 1, 0)) break; + WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL) res= mysql_create_db(thd, lex->name.str, &create_info, 0); break; } @@ -3922,6 +4266,7 @@ end_with_restore_list: #endif if (check_access(thd, DROP_ACL, lex->name.str, NULL, NULL, 1, 0)) break; + WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL) res= mysql_rm_db(thd, lex->name.str, lex->check_exists, 0); break; } @@ -3953,6 +4298,7 @@ end_with_restore_list: res= 1; break; } + WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL) res= mysql_upgrade_db(thd, db); if (!res) my_ok(thd); @@ -3988,6 +4334,7 @@ end_with_restore_list: #endif if (check_access(thd, ALTER_ACL, db->str, NULL, NULL, 1, 0)) break; + WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL) res= mysql_alter_db(thd, db->str, &create_info); break; } @@ -4026,6 +4373,7 @@ end_with_restore_list: if (res) break; + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) switch (lex->sql_command) { case SQLCOM_CREATE_EVENT: { @@ -4060,6 +4408,7 @@ end_with_restore_list: lex->spname->m_name); break; case SQLCOM_DROP_EVENT: + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) if (!(res= Events::drop_event(thd, lex->spname->m_db, lex->spname->m_name, lex->check_exists))) @@ -4074,6 +4423,7 @@ end_with_restore_list: if (check_access(thd, INSERT_ACL, "mysql", NULL, NULL, 1, 0)) break; #ifdef HAVE_DLOPEN + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) if (!(res = mysql_create_function(thd, &lex->udf))) my_ok(thd); #else @@ -4089,6 +4439,7 @@ end_with_restore_list: if (check_access(thd, INSERT_ACL, "mysql", NULL, NULL, 1, 1) && check_global_access(thd,CREATE_USER_ACL)) break; + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) /* Conditionally writes to binlog */ if (!(res= mysql_create_user(thd, lex->users_list, lex->sql_command == SQLCOM_CREATE_ROLE))) @@ -4102,6 +4453,7 @@ end_with_restore_list: check_global_access(thd,CREATE_USER_ACL)) break; /* Conditionally writes to binlog */ + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) if (!(res= mysql_drop_user(thd, lex->users_list, lex->sql_command == SQLCOM_DROP_ROLE))) my_ok(thd); @@ -4113,6 +4465,7 @@ end_with_restore_list: check_global_access(thd,CREATE_USER_ACL)) break; /* Conditionally writes to binlog */ + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) if (!(res= mysql_rename_user(thd, lex->users_list))) my_ok(thd); break; @@ -4124,6 +4477,7 @@ end_with_restore_list: break; /* Conditionally writes to binlog */ + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) if (!(res = mysql_revoke_all(thd, lex->users_list))) my_ok(thd); break; @@ -4206,6 +4560,7 @@ end_with_restore_list: lex->type == TYPE_ENUM_PROCEDURE, 0)) goto error; /* Conditionally writes to binlog */ + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) res= mysql_routine_grant(thd, all_tables, lex->type == TYPE_ENUM_PROCEDURE, lex->users_list, grants, @@ -4219,6 +4574,7 @@ end_with_restore_list: all_tables, FALSE, UINT_MAX, FALSE)) goto error; /* Conditionally writes to binlog */ + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) res= mysql_table_grant(thd, all_tables, lex->users_list, lex->columns, lex->grant, lex->sql_command == SQLCOM_REVOKE); @@ -4234,6 +4590,7 @@ end_with_restore_list: } else { + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) /* Conditionally writes to binlog */ res= mysql_grant(thd, select_lex->db, lex->users_list, lex->grant, lex->sql_command == SQLCOM_REVOKE, @@ -4402,6 +4759,7 @@ end_with_restore_list: able to open it (with SQLCOM_HA_OPEN) in the first place. */ unit->set_limit(select_lex); + res= mysql_ha_read(thd, first_table, lex->ha_read_mode, lex->ident.str, lex->insert_list, lex->ha_rkey_mode, select_lex->where, unit->select_limit_cnt, unit->offset_limit_cnt); @@ -4410,7 +4768,11 @@ end_with_restore_list: case SQLCOM_BEGIN: DBUG_PRINT("info", ("Executing SQLCOM_BEGIN thd: %p", thd)); if (trans_begin(thd, lex->start_transaction_opt)) + { + thd->mdl_context.release_transactional_locks(); + WSREP_DEBUG("BEGIN failed, MDL released: %lu", thd->thread_id); goto error; + } my_ok(thd); break; case SQLCOM_COMMIT: @@ -4424,7 +4786,11 @@ end_with_restore_list: (thd->variables.completion_type == 2 && lex->tx_release != TVL_NO)); if (trans_commit(thd)) + { + thd->mdl_context.release_transactional_locks(); + WSREP_DEBUG("COMMIT failed, MDL released: %lu", thd->thread_id); goto error; + } thd->mdl_context.release_transactional_locks(); /* Begin transaction with the same isolation level. */ if (tx_chain) @@ -4444,7 +4810,17 @@ end_with_restore_list: thd->killed= KILL_CONNECTION; thd->print_aborted_warning(3, "RELEASE"); } - my_ok(thd); +#ifdef WITH_WSREP + if (WSREP(thd)) + { + if (thd->wsrep_conflict_state == NO_CONFLICT || + thd->wsrep_conflict_state == REPLAYING) + { + my_ok(thd); + } + } else +#endif /* WITH_WSREP */ + my_ok(thd); break; } case SQLCOM_ROLLBACK: @@ -4459,7 +4835,11 @@ end_with_restore_list: lex->tx_release != TVL_NO)); if (trans_rollback(thd)) + { + thd->mdl_context.release_transactional_locks(); + WSREP_DEBUG("rollback failed, MDL released: %lu", thd->thread_id); goto error; + } thd->mdl_context.release_transactional_locks(); /* Begin transaction with the same isolation level. */ if (tx_chain) @@ -4476,8 +4856,17 @@ end_with_restore_list: /* Disconnect the current client connection. */ if (tx_release) thd->killed= KILL_CONNECTION; - my_ok(thd); - break; +#ifdef WITH_WSREP + if (WSREP(thd)) + { + if (thd->wsrep_conflict_state == NO_CONFLICT) { + my_ok(thd); + } + } + else +#endif /* WITH_WSREP */ + my_ok(thd); + break; } case SQLCOM_RELEASE_SAVEPOINT: if (trans_release_savepoint(thd, lex->ident)) @@ -4545,6 +4934,7 @@ end_with_restore_list: if (sp_process_definer(thd)) goto create_sp_error; + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) res= (sp_result= sp_create_routine(thd, lex->sphead->m_type, lex->sphead)); switch (sp_result) { case SP_OK: { @@ -4826,6 +5216,7 @@ create_sp_error: if (check_routine_access(thd, ALTER_PROC_ACL, db, name, lex->sql_command == SQLCOM_DROP_PROCEDURE, 0)) goto error; + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) /* Conditionally writes to binlog */ sp_result= sp_drop_routine(thd, type, lex->spname); @@ -4943,6 +5334,7 @@ create_sp_error: Note: SQLCOM_CREATE_VIEW also handles 'ALTER VIEW' commands as specified through the thd->lex->create_view_mode flag. */ + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) res= mysql_create_view(thd, first_table, thd->lex->create_view_mode); break; } @@ -4951,12 +5343,14 @@ create_sp_error: if (check_table_access(thd, DROP_ACL, all_tables, FALSE, UINT_MAX, FALSE)) goto error; /* Conditionally writes to binlog. */ + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) res= mysql_drop_view(thd, first_table, thd->lex->drop_mode); break; } case SQLCOM_CREATE_TRIGGER: { /* Conditionally writes to binlog. */ + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) res= mysql_create_or_drop_trigger(thd, all_tables, 1); break; @@ -4964,6 +5358,7 @@ create_sp_error: case SQLCOM_DROP_TRIGGER: { /* Conditionally writes to binlog. */ + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) res= mysql_create_or_drop_trigger(thd, all_tables, 0); break; } @@ -4984,7 +5379,11 @@ create_sp_error: break; case SQLCOM_XA_COMMIT: if (trans_xa_commit(thd)) + { + thd->mdl_context.release_transactional_locks(); + WSREP_DEBUG("XA commit failed, MDL released: %lu", thd->thread_id); goto error; + } thd->mdl_context.release_transactional_locks(); /* We've just done a commit, reset transaction @@ -4996,7 +5395,11 @@ create_sp_error: break; case SQLCOM_XA_ROLLBACK: if (trans_xa_rollback(thd)) + { + thd->mdl_context.release_transactional_locks(); + WSREP_DEBUG("XA rollback failed, MDL released: %lu", thd->thread_id); goto error; + } thd->mdl_context.release_transactional_locks(); /* We've just done a rollback, reset transaction @@ -5016,11 +5419,13 @@ create_sp_error: my_ok(thd); break; case SQLCOM_INSTALL_PLUGIN: + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) if (! (res= mysql_install_plugin(thd, &thd->lex->comment, &thd->lex->ident))) my_ok(thd); break; case SQLCOM_UNINSTALL_PLUGIN: + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) if (! (res= mysql_uninstall_plugin(thd, &thd->lex->comment, &thd->lex->ident))) my_ok(thd); @@ -5169,6 +5574,9 @@ finish: /* Free tables */ close_thread_tables(thd); +#ifdef WITH_WSREP + thd->wsrep_consistency_check= NO_CONSISTENCY_CHECK; +#endif /* WITH_WSREP */ #ifndef DBUG_OFF if (lex->sql_command != SQLCOM_SET_OPTION && ! thd->in_sub_stmt) @@ -5222,6 +5630,22 @@ finish: { thd->mdl_context.release_statement_locks(); } + WSREP_TO_ISOLATION_END; + +#ifdef WITH_WSREP + /* + Force release of transactional locks if not in active MST and wsrep is on. + */ + if (WSREP(thd) && + ! thd->in_sub_stmt && + ! thd->in_active_multi_stmt_transaction() && + thd->mdl_context.has_transactional_locks()) + { + WSREP_DEBUG("Forcing release of transactional locks for thd %lu", + thd->thread_id); + thd->mdl_context.release_transactional_locks(); + } +#endif /* WITH_WSREP */ DBUG_RETURN(res || thd->is_error()); } @@ -5322,6 +5746,10 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables) status_var_increment(thd->status_var.empty_queries); else status_var_add(thd->status_var.rows_sent, thd->get_sent_row_count()); +#ifdef WITH_WSREP + if (WSREP_ON && lex->sql_command == SQLCOM_SHOW_STATUS) + wsrep_free_status(thd); +#endif /* WITH_WSREP */ return res; } @@ -6160,6 +6588,27 @@ void THD::reset_for_next_command() thd->auto_inc_intervals_in_cur_stmt_for_binlog.empty(); thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0; +#ifdef WITH_WSREP + /* + Autoinc variables should be adjusted only for locally executed + transactions. Appliers and replayers are either processing ROW + events or get autoinc variable values from Query_log_event. + */ + if (WSREP(thd) && thd->wsrep_exec_mode == LOCAL_STATE) + { + if (wsrep_auto_increment_control) + { + if (thd->variables.auto_increment_offset != + global_system_variables.auto_increment_offset) + thd->variables.auto_increment_offset= + global_system_variables.auto_increment_offset; + if (thd->variables.auto_increment_increment != + global_system_variables.auto_increment_increment) + thd->variables.auto_increment_increment= + global_system_variables.auto_increment_increment; + } + } +#endif /* WITH_WSREP */ thd->query_start_used= 0; thd->query_start_sec_part_used= 0; thd->is_fatal_error= thd->time_zone_used= 0; @@ -6363,6 +6812,109 @@ void mysql_init_multi_delete(LEX *lex) lex->query_tables_last= &lex->query_tables; } +#ifdef WITH_WSREP +static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length, + Parser_state *parser_state) +{ + bool is_autocommit= + !thd->in_multi_stmt_transaction_mode() && + thd->wsrep_conflict_state == NO_CONFLICT && + !thd->wsrep_applier && + wsrep_read_only_option(thd, thd->lex->query_tables); + + do + { + if (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT) + { + thd->wsrep_conflict_state= NO_CONFLICT; + /* Performance Schema Interface instrumentation, begin */ + thd->m_statement_psi= MYSQL_REFINE_STATEMENT(thd->m_statement_psi, + com_statement_info[thd->get_command()].m_key); + MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, thd->query(), + thd->query_length()); + } + mysql_parse(thd, rawbuf, length, parser_state); + + if (WSREP(thd)) { + /* wsrep BF abort in query exec phase */ + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + if (thd->wsrep_conflict_state == MUST_ABORT) { + wsrep_client_rollback(thd); + + WSREP_DEBUG("abort in exec query state, avoiding autocommit"); + } + + if (thd->wsrep_conflict_state== MUST_REPLAY) + { + wsrep_replay_transaction(thd); + } + + /* setting error code for BF aborted trxs */ + if (thd->wsrep_conflict_state == ABORTED || + thd->wsrep_conflict_state == CERT_FAILURE) + { + mysql_reset_thd_for_next_command(thd); + thd->killed= NOT_KILLED; + if (is_autocommit && + thd->lex->sql_command != SQLCOM_SELECT && + (thd->wsrep_retry_counter < thd->variables.wsrep_retry_autocommit)) + { + WSREP_DEBUG("wsrep retrying AC query: %s", + (thd->query()) ? thd->query() : "void"); + + /* Performance Schema Interface instrumentation, end */ + MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da()); + thd->m_statement_psi= NULL; + close_thread_tables(thd); + + thd->wsrep_conflict_state= RETRY_AUTOCOMMIT; + thd->wsrep_retry_counter++; // grow + wsrep_copy_query(thd); + thd->set_time(); + parser_state->reset(rawbuf, length); + } + else + { + WSREP_DEBUG("%s, thd: %lu is_AC: %d, retry: %lu - %lu SQL: %s", + (thd->wsrep_conflict_state == ABORTED) ? + "BF Aborted" : "cert failure", + thd->thread_id, is_autocommit, thd->wsrep_retry_counter, + thd->variables.wsrep_retry_autocommit, thd->query()); + my_error(ER_LOCK_DEADLOCK, MYF(0), "wsrep aborted transaction"); + thd->killed= NOT_KILLED; + thd->wsrep_conflict_state= NO_CONFLICT; + if (thd->wsrep_conflict_state != REPLAYING) + thd->wsrep_retry_counter= 0; // reset + } + } + else + { + set_if_smaller(thd->wsrep_retry_counter, 0); // reset; eventually ok + } + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } + + /* If retry is requested clean up explain structure */ + if (thd->wsrep_conflict_state == RETRY_AUTOCOMMIT && thd->lex->explain) + delete_explain_query(thd->lex); + + } while (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT); + + if (thd->wsrep_retry_query) + { + WSREP_DEBUG("releasing retry_query: conf %d sent %d kill %d errno %d SQL %s", + thd->wsrep_conflict_state, + thd->get_stmt_da()->is_sent(), + thd->killed, + thd->get_stmt_da()->is_error() ? thd->get_stmt_da()->sql_errno() : 0, + thd->wsrep_retry_query); + my_free(thd->wsrep_retry_query); + thd->wsrep_retry_query = NULL; + thd->wsrep_retry_query_len = 0; + thd->wsrep_retry_command = COM_CONNECT; + } +} +#endif /* WITH_WSREP */ /* When you modify mysql_parse(), you may need to mofify @@ -7392,8 +7944,9 @@ kill_one_thread(THD *thd, longlong id, killed_state kill_signal, killed_type typ faster and do a harder kill than KILL_SYSTEM_THREAD; */ - if ((thd->security_ctx->master_access & SUPER_ACL) || - thd->security_ctx->user_matches(tmp->security_ctx)) + if (((thd->security_ctx->master_access & SUPER_ACL) || + thd->security_ctx->user_matches(tmp->security_ctx)) && + IF_WSREP(!wsrep_thd_is_BF((void *)tmp, true), 1)) { tmp->awake(kill_signal); error=0; diff --git a/sql/sql_parse.h b/sql/sql_parse.h index 926a4d800ad..87f8854e050 100644 --- a/sql/sql_parse.h +++ b/sql/sql_parse.h @@ -203,5 +203,4 @@ inline bool is_supported_parser_charset(CHARSET_INFO *cs) return MY_TEST(cs->mbminlen == 1); } - #endif /* SQL_PARSE_INCLUDED */ diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc index 8c59febeb77..9db8b1c136a 100644 --- a/sql/sql_partition_admin.cc +++ b/sql/sql_partition_admin.cc @@ -1,4 +1,5 @@ /* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2014, SkySQL Ab. 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 @@ -763,6 +764,23 @@ bool Sql_cmd_alter_table_truncate_partition::execute(THD *thd) if (check_one_table_access(thd, DROP_ACL, first_table)) DBUG_RETURN(TRUE); +#ifdef WITH_WSREP + if (WSREP_ON) + { + TABLE *find_temporary_table(THD *thd, const TABLE_LIST *tl); + + if ((!thd->is_current_stmt_binlog_format_row() || + !find_temporary_table(thd, first_table)) && + wsrep_to_isolation_begin( + thd, first_table->db, first_table->table_name, NULL) + ) + { + WSREP_WARN("ALTER TABLE isolation failure"); + DBUG_RETURN(TRUE); + } + } +#endif /* WITH_WSREP */ + if (open_tables(thd, &first_table, &table_counter, 0)) DBUG_RETURN(true); diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index b2dd38ad720..ea9748c8cb2 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -3087,15 +3087,19 @@ void plugin_thdvar_init(THD *thd) thd->variables.dynamic_variables_size= 0; thd->variables.dynamic_variables_ptr= 0; - mysql_mutex_lock(&LOCK_plugin); - thd->variables.table_plugin= + if (IF_WSREP((!WSREP(thd) || !thd->wsrep_applier),1)) + { + mysql_mutex_lock(&LOCK_plugin); + thd->variables.table_plugin= intern_plugin_lock(NULL, global_system_variables.table_plugin); - if (global_system_variables.tmp_table_plugin) - thd->variables.tmp_table_plugin= + if (global_system_variables.tmp_table_plugin) + thd->variables.tmp_table_plugin= intern_plugin_lock(NULL, global_system_variables.tmp_table_plugin); - intern_plugin_unlock(NULL, old_table_plugin); - intern_plugin_unlock(NULL, old_tmp_table_plugin); - mysql_mutex_unlock(&LOCK_plugin); + intern_plugin_unlock(NULL, old_table_plugin); + intern_plugin_unlock(NULL, old_tmp_table_plugin); + mysql_mutex_unlock(&LOCK_plugin); + } + DBUG_VOID_RETURN; } diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index ebceae70ee5..d9365e14494 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2002, 2013, Oracle and/or its affiliates. - Copyright (c) 2008, 2013, Monty Program Ab + Copyright (c) 2008, 2014, Monty Program Ab 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 @@ -117,6 +117,7 @@ When one supplies long data for a placeholder: #include "lock.h" // MYSQL_OPEN_FORCE_SHARED_MDL #include "sql_handler.h" #include "transaction.h" // trans_rollback_implicit +#include "wsrep_mysqld.h" /** A result class used to send cursor rows using the binary protocol. @@ -3626,6 +3627,27 @@ reexecute: error= execute(expanded_query, open_cursor) || thd->is_error(); thd->m_reprepare_observer= NULL; +#ifdef WITH_WSREP + + if (WSREP_ON) + { + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + switch (thd->wsrep_conflict_state) + { + case CERT_FAILURE: + WSREP_DEBUG("PS execute fail for CERT_FAILURE: thd: %ld err: %d", + thd->thread_id, thd->get_stmt_da()->sql_errno() ); + thd->wsrep_conflict_state = NO_CONFLICT; + break; + + case MUST_REPLAY: + (void)wsrep_replay_transaction(thd); + default: + break; + } + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } +#endif /* WITH_WSREP */ if ((sql_command_flags[lex->sql_command] & CF_REEXECUTION_FRAGILE) && error && !thd->is_fatal_error && !thd->killed && diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc index bb3d5bb899a..f1f9ba9452f 100644 --- a/sql/sql_reload.cc +++ b/sql/sql_reload.cc @@ -253,7 +253,18 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options, } if (options & REFRESH_CHECKPOINT) disable_checkpoints(thd); - } +#ifdef WITH_WSREP + /* + We need to do it second time after wsrep appliers were blocked in + make_global_read_lock_block_commit(thd) above since they could have + modified the tables too. + */ + if (WSREP(thd) && + close_cached_tables(thd, tables, (options & REFRESH_FAST) ? + FALSE : TRUE, TRUE)) + result= 1; +#endif /* WITH_WSREP */ + } else { if (thd && thd->locked_tables_mode) diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index c7bd28259ae..d8db5c55c3b 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2008, 2013, Monty Program Ab + Copyright (c) 2008, 2014, Monty Program Ab 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 @@ -2946,6 +2946,7 @@ int start_slave(THD* thd , Master_info* mi, bool net_report) err: unlock_slave_threads(mi); + thd_proc_info(thd, 0); if (slave_errno) { diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 79c444ea442..bb8ae16189a 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2931,11 +2931,39 @@ static bool show_status_array(THD *thd, const char *wild, *prefix_end++= '_'; len=name_buffer + sizeof(name_buffer) - prefix_end; +#ifdef WITH_WSREP + bool is_wsrep_var= FALSE; + /* + This is a workaround for lp:1306875 (PBX) to skip switching of wsrep + status variable name's first letter to uppercase. This is an optimization + for status variables defined under wsrep plugin. + TODO: remove once lp:1306875 has been addressed. + */ + if (*prefix && !my_strcasecmp(system_charset_info, prefix, "wsrep")) + { + is_wsrep_var= TRUE; + } +#endif /* WITH_WSREP */ + for (; variables->name; variables++) { bool wild_checked; strnmov(prefix_end, variables->name, len); name_buffer[sizeof(name_buffer)-1]=0; /* Safety */ + +#ifdef WITH_WSREP + /* + If the prefix is NULL, that means we are looking into the status variables + defined directly under mysqld.cc. Do not capitalize wsrep status variable + names until lp:1306875 has been fixed. + TODO: remove once lp:1306875 has been addressed. + */ + if (!(*prefix) && !strncasecmp(name_buffer, "wsrep", strlen("wsrep"))) + { + is_wsrep_var= TRUE; + } +#endif /* WITH_WSREP */ + if (ucase_names) my_caseup_str(system_charset_info, name_buffer); else @@ -2944,8 +2972,9 @@ static bool show_status_array(THD *thd, const char *wild, DBUG_ASSERT(name_buffer[0] >= 'a'); DBUG_ASSERT(name_buffer[0] <= 'z'); - /* traditionally status variables have a first letter uppercased */ - if (status_var) + // WSREP_TODO: remove once lp:1306875 has been addressed. + if (IF_WSREP(is_wsrep_var == FALSE, 1) && + status_var) name_buffer[0]-= 'a' - 'A'; } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 80ac0978834..b86de2f6cc1 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5264,6 +5264,12 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, int create_res; DBUG_ENTER("mysql_create_like_table"); +#ifdef WITH_WSREP + if (WSREP_ON && !thd->wsrep_applier && + wsrep_create_like_table(thd, table, src_table, create_info)) + goto end; +#endif + /* We the open source table to get its description in HA_CREATE_INFO and Alter_info objects. This also acquires a shared metadata lock @@ -5525,6 +5531,8 @@ err: thd->query_length(), is_trans)) res= 1; } + +end: DBUG_RETURN(res); } @@ -8117,6 +8125,7 @@ simple_rename_or_index_change(THD *thd, TABLE_LIST *table_list, if (!error) { error= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); + if (!error) my_ok(thd); } diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 70ac6265046..268fad5d90e 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -434,7 +434,8 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) binlogged, so they share the same danger, so trust_function_creators applies to them too. */ - if (!trust_function_creators && mysql_bin_log.is_open() && + if (!trust_function_creators && + IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), mysql_bin_log.is_open()) && !(thd->security_ctx->master_access & SUPER_ACL)) { my_error(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER, MYF(0)); @@ -2437,3 +2438,4 @@ bool load_table_name_for_trigger(THD *thd, DBUG_RETURN(FALSE); } + diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc index e98679b1d51..5e23c6ee32b 100644 --- a/sql/sql_truncate.cc +++ b/sql/sql_truncate.cc @@ -24,6 +24,7 @@ #include "sql_acl.h" // DROP_ACL #include "sql_parse.h" // check_one_table_access() #include "sql_truncate.h" +#include "wsrep_mysqld.h" #include "sql_show.h" //append_identifier() @@ -411,6 +412,12 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref) { bool hton_can_recreate; +#ifdef WITH_WSREP + if (WSREP(thd) && wsrep_to_isolation_begin(thd, + table_ref->db, + table_ref->table_name, NULL)) + DBUG_RETURN(TRUE); +#endif /* WITH_WSREP */ if (lock_table(thd, table_ref, &hton_can_recreate)) DBUG_RETURN(TRUE); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index faf8e4c61d2..c458f01303d 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2011, 2013, Monty Program Ab. + Copyright (c) 2011, 2014, Monty Program Ab. 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 @@ -976,7 +976,8 @@ int mysql_update(THD *thd, */ if ((error < 0) || thd->transaction.stmt.modified_non_trans_table) { - if (mysql_bin_log.is_open()) + if (IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), + mysql_bin_log.is_open())) { int errcode= 0; if (error < 0) @@ -2219,7 +2220,8 @@ void multi_update::abort_result_set() The query has to binlog because there's a modified non-transactional table either from the query's list or via a stored routine: bug#13270,23333 */ - if (mysql_bin_log.is_open()) + if (IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), + mysql_bin_log.is_open())) { /* THD::killed status might not have been set ON at time of an error @@ -2488,7 +2490,8 @@ bool multi_update::send_eof() if (local_error == 0 || thd->transaction.stmt.modified_non_trans_table) { - if (mysql_bin_log.is_open()) + if (IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), + mysql_bin_log.is_open())) { int errcode= 0; if (local_error == 0) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index a261d611aa6..a06d702f620 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7156,7 +7156,7 @@ alter: } view_tail {} - | ALTER definer_opt EVENT_SYM sp_name + | ALTER definer_opt remember_name EVENT_SYM sp_name { /* It is safe to use Lex->spname because @@ -7168,9 +7168,12 @@ alter: if (!(Lex->event_parse_data= Event_parse_data::new_instance(thd))) MYSQL_YYABORT; - Lex->event_parse_data->identifier= $4; + Lex->event_parse_data->identifier= $5; Lex->sql_command= SQLCOM_ALTER_EVENT; +#ifdef WITH_WSREP + Lex->stmt_definition_begin= $3; +#endif } ev_alter_on_schedule_completion opt_ev_rename_to @@ -7178,7 +7181,7 @@ alter: opt_ev_comment opt_ev_sql_stmt { - if (!($6 || $7 || $8 || $9 || $10)) + if (!($7 || $8 || $9 || $10 || $11)) { my_parse_error(ER(ER_SYNTAX_ERROR)); MYSQL_YYABORT; @@ -7188,6 +7191,9 @@ alter: can overwrite it */ Lex->sql_command= SQLCOM_ALTER_EVENT; +#ifdef WITH_WSREP + Lex->stmt_definition_end= (char*)YYLIP->get_cpp_ptr(); +#endif } | ALTER TABLESPACE alter_tablespace_info { diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 9495d16247d..c76ee5e6358 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -465,6 +465,26 @@ static bool binlog_format_check(sys_var *self, THD *thd, set_var *var) ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT)) return true; +#ifdef WITH_WSREP + /* MariaDB Galera does not support STATEMENT or MIXED binlog + format currently */ + if (WSREP(thd) && + (var->save_result.ulonglong_value == BINLOG_FORMAT_STMT || + var->save_result.ulonglong_value == BINLOG_FORMAT_MIXED)) + { + WSREP_DEBUG("MariaDB Galera does not support binlog format : %s", + var->save_result.ulonglong_value == BINLOG_FORMAT_STMT ? + "STATEMENT" : "MIXED"); + /* Push also warning, because error message is general */ + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + ER_UNKNOWN_ERROR, + "MariaDB Galera does not support binlog format: %s", + var->save_result.ulonglong_value == BINLOG_FORMAT_STMT ? + "STATEMENT" : "MIXED"); + return true; + } +#endif + return false; } @@ -3317,6 +3337,8 @@ static bool fix_autocommit(sys_var *self, THD *thd, enum_var_type type) if (trans_commit_stmt(thd) || trans_commit(thd)) { thd->variables.option_bits&= ~OPTION_AUTOCOMMIT; + thd->mdl_context.release_transactional_locks(); + WSREP_DEBUG("autocommit, MDL TRX lock released: %lu", thd->thread_id); return true; } /* @@ -4412,6 +4434,270 @@ static Sys_var_tz Sys_time_zone( SESSION_VAR(time_zone), NO_CMD_LINE, DEFAULT(&default_tz), NO_MUTEX_GUARD, IN_BINLOG); +#ifdef WITH_WSREP +#include "wsrep_var.h" +#include "wsrep_sst.h" +#include "wsrep_binlog.h" + +static Sys_var_charptr Sys_wsrep_provider( + "wsrep_provider", "Path to replication provider library", + PREALLOCATED GLOBAL_VAR(wsrep_provider), CMD_LINE(REQUIRED_ARG, OPT_WSREP_PROVIDER), + IN_FS_CHARSET, DEFAULT(WSREP_NONE), + NO_MUTEX_GUARD, NOT_IN_BINLOG, + ON_CHECK(wsrep_provider_check), ON_UPDATE(wsrep_provider_update)); + +static Sys_var_charptr Sys_wsrep_provider_options( + "wsrep_provider_options", "provider specific options", + PREALLOCATED GLOBAL_VAR(wsrep_provider_options), + CMD_LINE(REQUIRED_ARG, OPT_WSREP_PROVIDER_OPTIONS), + IN_FS_CHARSET, DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG, + ON_CHECK(wsrep_provider_options_check), + ON_UPDATE(wsrep_provider_options_update)); + +static Sys_var_charptr Sys_wsrep_data_home_dir( + "wsrep_data_home_dir", "home directory for wsrep provider", + READ_ONLY GLOBAL_VAR(wsrep_data_home_dir), CMD_LINE(REQUIRED_ARG), + IN_FS_CHARSET, DEFAULT(""), + NO_MUTEX_GUARD, NOT_IN_BINLOG); + +static Sys_var_charptr Sys_wsrep_cluster_name( + "wsrep_cluster_name", "Name for the cluster", + PREALLOCATED GLOBAL_VAR(wsrep_cluster_name), CMD_LINE(REQUIRED_ARG), + IN_FS_CHARSET, DEFAULT(WSREP_CLUSTER_NAME), + NO_MUTEX_GUARD, NOT_IN_BINLOG, + ON_CHECK(wsrep_cluster_name_check), + ON_UPDATE(wsrep_cluster_name_update)); + +static PolyLock_mutex PLock_wsrep_slave_threads(&LOCK_wsrep_slave_threads); +static Sys_var_charptr Sys_wsrep_cluster_address ( + "wsrep_cluster_address", "Address to initially connect to cluster", + PREALLOCATED GLOBAL_VAR(wsrep_cluster_address), + CMD_LINE(REQUIRED_ARG, OPT_WSREP_CLUSTER_ADDRESS), + IN_FS_CHARSET, DEFAULT(""), + &PLock_wsrep_slave_threads, NOT_IN_BINLOG, + ON_CHECK(wsrep_cluster_address_check), + ON_UPDATE(wsrep_cluster_address_update)); + +static Sys_var_charptr Sys_wsrep_node_name ( + "wsrep_node_name", "Node name", + PREALLOCATED GLOBAL_VAR(wsrep_node_name), CMD_LINE(REQUIRED_ARG), + IN_FS_CHARSET, DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG, + wsrep_node_name_check, wsrep_node_name_update); + +static Sys_var_charptr Sys_wsrep_node_address ( + "wsrep_node_address", "Node address", + PREALLOCATED GLOBAL_VAR(wsrep_node_address), CMD_LINE(REQUIRED_ARG), + IN_FS_CHARSET, DEFAULT(""), + NO_MUTEX_GUARD, NOT_IN_BINLOG, + ON_CHECK(wsrep_node_address_check), + ON_UPDATE(wsrep_node_address_update)); + +static Sys_var_charptr Sys_wsrep_node_incoming_address( + "wsrep_node_incoming_address", "Client connection address", + PREALLOCATED GLOBAL_VAR(wsrep_node_incoming_address),CMD_LINE(REQUIRED_ARG), + IN_FS_CHARSET, DEFAULT(WSREP_NODE_INCOMING_AUTO), + NO_MUTEX_GUARD, NOT_IN_BINLOG); + +static Sys_var_ulong Sys_wsrep_slave_threads( + "wsrep_slave_threads", "Number of slave appliers to launch", + GLOBAL_VAR(wsrep_slave_threads), CMD_LINE(REQUIRED_ARG), + VALID_RANGE(1, 512), DEFAULT(1), BLOCK_SIZE(1), + &PLock_wsrep_slave_threads, NOT_IN_BINLOG, + ON_CHECK(wsrep_slave_threads_check), + ON_UPDATE(wsrep_slave_threads_update)); + +static Sys_var_charptr Sys_wsrep_dbug_option( + "wsrep_dbug_option", "DBUG options to provider library", + GLOBAL_VAR(wsrep_dbug_option),CMD_LINE(REQUIRED_ARG), + IN_FS_CHARSET, DEFAULT(""), + NO_MUTEX_GUARD, NOT_IN_BINLOG); + +static Sys_var_mybool Sys_wsrep_debug( + "wsrep_debug", "To enable debug level logging", + GLOBAL_VAR(wsrep_debug), CMD_LINE(OPT_ARG), DEFAULT(FALSE)); + +static Sys_var_mybool Sys_wsrep_convert_LOCK_to_trx( + "wsrep_convert_LOCK_to_trx", "To convert locking sessions " + "into transactions", + GLOBAL_VAR(wsrep_convert_LOCK_to_trx), + CMD_LINE(OPT_ARG), DEFAULT(FALSE)); + +static Sys_var_ulong Sys_wsrep_retry_autocommit( + "wsrep_retry_autocommit", "Max number of times to retry " + "a failed autocommit statement", + SESSION_VAR(wsrep_retry_autocommit), CMD_LINE(REQUIRED_ARG), + VALID_RANGE(0, 10000), DEFAULT(1), BLOCK_SIZE(1)); + +static Sys_var_mybool Sys_wsrep_auto_increment_control( + "wsrep_auto_increment_control", "To automatically control the " + "assignment of autoincrement variables", + GLOBAL_VAR(wsrep_auto_increment_control), + CMD_LINE(OPT_ARG), DEFAULT(TRUE)); + +static Sys_var_mybool Sys_wsrep_drupal_282555_workaround( + "wsrep_drupal_282555_workaround", "To use a workaround for" + "bad autoincrement value", + GLOBAL_VAR(wsrep_drupal_282555_workaround), + CMD_LINE(OPT_ARG), DEFAULT(FALSE)); + +static Sys_var_charptr sys_wsrep_sst_method( + "wsrep_sst_method", "State snapshot transfer method", + GLOBAL_VAR(wsrep_sst_method),CMD_LINE(REQUIRED_ARG), + IN_FS_CHARSET, DEFAULT(WSREP_SST_DEFAULT), NO_MUTEX_GUARD, NOT_IN_BINLOG, + ON_CHECK(wsrep_sst_method_check), + ON_UPDATE(wsrep_sst_method_update)); + +static Sys_var_charptr Sys_wsrep_sst_receive_address( + "wsrep_sst_receive_address", "Address where node is waiting for " + "SST contact", + GLOBAL_VAR(wsrep_sst_receive_address),CMD_LINE(REQUIRED_ARG), + IN_FS_CHARSET, DEFAULT(WSREP_SST_ADDRESS_AUTO), NO_MUTEX_GUARD, + NOT_IN_BINLOG, + ON_CHECK(wsrep_sst_receive_address_check), + ON_UPDATE(wsrep_sst_receive_address_update)); + +static Sys_var_charptr Sys_wsrep_sst_auth( + "wsrep_sst_auth", "Authentication for SST connection", + PREALLOCATED GLOBAL_VAR(wsrep_sst_auth), CMD_LINE(REQUIRED_ARG, OPT_WSREP_SST_AUTH), + IN_FS_CHARSET, DEFAULT(NULL), NO_MUTEX_GUARD, + NOT_IN_BINLOG, + ON_CHECK(wsrep_sst_auth_check), + ON_UPDATE(wsrep_sst_auth_update)); + +static Sys_var_charptr Sys_wsrep_sst_donor( + "wsrep_sst_donor", "preferred donor node for the SST", + GLOBAL_VAR(wsrep_sst_donor),CMD_LINE(REQUIRED_ARG), + IN_FS_CHARSET, DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG, + ON_CHECK(wsrep_sst_donor_check), + ON_UPDATE(wsrep_sst_donor_update)); + +static Sys_var_mybool Sys_wsrep_sst_donor_rejects_queries( + "wsrep_sst_donor_rejects_queries", "Reject client queries " + "when donating state snapshot transfer", + GLOBAL_VAR(wsrep_sst_donor_rejects_queries), + CMD_LINE(OPT_ARG), DEFAULT(FALSE)); + +static Sys_var_mybool Sys_wsrep_on ( + "wsrep_on", "To enable wsrep replication ", + SESSION_VAR(wsrep_on), + CMD_LINE(OPT_ARG), DEFAULT(TRUE), + NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), + ON_UPDATE(wsrep_on_update)); + +static Sys_var_charptr Sys_wsrep_start_position ( + "wsrep_start_position", "global transaction position to start from ", + PREALLOCATED GLOBAL_VAR(wsrep_start_position), + CMD_LINE(REQUIRED_ARG, OPT_WSREP_START_POSITION), + IN_FS_CHARSET, DEFAULT(WSREP_START_POSITION_ZERO), + NO_MUTEX_GUARD, NOT_IN_BINLOG, + ON_CHECK(wsrep_start_position_check), + ON_UPDATE(wsrep_start_position_update)); + +static Sys_var_ulong Sys_wsrep_max_ws_size ( + "wsrep_max_ws_size", "Max write set size (bytes)", + GLOBAL_VAR(wsrep_max_ws_size), CMD_LINE(REQUIRED_ARG), + /* Upper limit is 65K short of 4G to avoid overlows on 32-bit systems */ + VALID_RANGE(1024, WSREP_MAX_WS_SIZE), DEFAULT(1073741824UL), BLOCK_SIZE(1)); + +static Sys_var_ulong Sys_wsrep_max_ws_rows ( + "wsrep_max_ws_rows", "Max number of rows in write set", + GLOBAL_VAR(wsrep_max_ws_rows), CMD_LINE(REQUIRED_ARG), + VALID_RANGE(1, 1048576), DEFAULT(131072), BLOCK_SIZE(1)); + +static Sys_var_charptr Sys_wsrep_notify_cmd( + "wsrep_notify_cmd", "", + GLOBAL_VAR(wsrep_notify_cmd),CMD_LINE(REQUIRED_ARG), + IN_FS_CHARSET, DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG); + +static Sys_var_mybool Sys_wsrep_certify_nonPK( + "wsrep_certify_nonPK", "Certify tables with no primary key", + GLOBAL_VAR(wsrep_certify_nonPK), + CMD_LINE(OPT_ARG), DEFAULT(TRUE)); + +static Sys_var_mybool Sys_wsrep_causal_reads( + "wsrep_causal_reads", "(DEPRECATED) Setting this variable is equivalent " + "to setting wsrep_sync_wait READ flag", + SESSION_VAR(wsrep_causal_reads), CMD_LINE(OPT_ARG), DEFAULT(FALSE), + NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), + ON_UPDATE(wsrep_causal_reads_update)); + +static Sys_var_uint Sys_wsrep_sync_wait( + "wsrep_sync_wait", "Ensure \"synchronous\" read view before executing " + "an operation of the type specified by bitmask: 1 - READ(includes " + "SELECT, SHOW and BEGIN/START TRANSACTION); 2 - UPDATE and DELETE; 4 - " + "INSERT and REPLACE", + SESSION_VAR(wsrep_sync_wait), CMD_LINE(OPT_ARG), + VALID_RANGE(WSREP_SYNC_WAIT_NONE, WSREP_SYNC_WAIT_MAX), + DEFAULT(WSREP_SYNC_WAIT_NONE), BLOCK_SIZE(1), + NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), + ON_UPDATE(wsrep_sync_wait_update)); + +static const char *wsrep_OSU_method_names[]= { "TOI", "RSU", NullS }; +static Sys_var_enum Sys_wsrep_OSU_method( + "wsrep_OSU_method", "Method for Online Schema Upgrade", + GLOBAL_VAR(wsrep_OSU_method_options), CMD_LINE(OPT_ARG), + wsrep_OSU_method_names, DEFAULT(WSREP_OSU_TOI), + NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), + ON_UPDATE(0)); + +static PolyLock_mutex PLock_wsrep_desync(&LOCK_wsrep_desync); +static Sys_var_mybool Sys_wsrep_desync ( + "wsrep_desync", "To desynchronize the node from the cluster", + GLOBAL_VAR(wsrep_desync), + CMD_LINE(OPT_ARG), DEFAULT(FALSE), + &PLock_wsrep_desync, NOT_IN_BINLOG, + ON_CHECK(wsrep_desync_check), + ON_UPDATE(wsrep_desync_update)); + +static Sys_var_enum Sys_wsrep_forced_binlog_format( + "wsrep_forced_binlog_format", "binlog format to take effect over user's choice", + GLOBAL_VAR(wsrep_forced_binlog_format), + CMD_LINE(REQUIRED_ARG, OPT_BINLOG_FORMAT), + wsrep_binlog_format_names, DEFAULT(BINLOG_FORMAT_UNSPEC), + NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), + ON_UPDATE(0)); + +static Sys_var_mybool Sys_wsrep_recover_datadir( + "wsrep_recover", "Recover database state after crash and exit", + READ_ONLY GLOBAL_VAR(wsrep_recovery), + CMD_LINE(OPT_ARG, OPT_WSREP_RECOVER), DEFAULT(FALSE)); + +static Sys_var_mybool Sys_wsrep_replicate_myisam( + "wsrep_replicate_myisam", "To enable myisam replication", + GLOBAL_VAR(wsrep_replicate_myisam), CMD_LINE(OPT_ARG), DEFAULT(FALSE)); + +static Sys_var_mybool Sys_wsrep_log_conflicts( + "wsrep_log_conflicts", "To log multi-master conflicts", + GLOBAL_VAR(wsrep_log_conflicts), CMD_LINE(OPT_ARG), DEFAULT(FALSE)); + +static Sys_var_ulong Sys_wsrep_mysql_replication_bundle( + "wsrep_mysql_replication_bundle", "mysql replication group commit ", + GLOBAL_VAR(wsrep_mysql_replication_bundle), CMD_LINE(REQUIRED_ARG), + VALID_RANGE(0, 1000), DEFAULT(0), BLOCK_SIZE(1)); + +static Sys_var_mybool Sys_wsrep_load_data_splitting( + "wsrep_load_data_splitting", "To commit LOAD DATA " + "transaction after every 10K rows inserted", + GLOBAL_VAR(wsrep_load_data_splitting), + CMD_LINE(OPT_ARG), DEFAULT(TRUE)); + +static Sys_var_mybool Sys_wsrep_slave_FK_checks( + "wsrep_slave_FK_checks", "Should slave thread do " + "foreign key constraint checks", + GLOBAL_VAR(wsrep_slave_FK_checks), + CMD_LINE(OPT_ARG), DEFAULT(TRUE)); + +static Sys_var_mybool Sys_wsrep_slave_UK_checks( + "wsrep_slave_UK_checks", "Should slave thread do " + "secondary index uniqueness checks", + GLOBAL_VAR(wsrep_slave_UK_checks), + CMD_LINE(OPT_ARG), DEFAULT(FALSE)); + +static Sys_var_mybool Sys_wsrep_restart_slave( + "wsrep_restart_slave", "Should MySQL slave be restarted automatically, when node joins back to cluster", + GLOBAL_VAR(wsrep_restart_slave), CMD_LINE(OPT_ARG), DEFAULT(FALSE)); +#endif /* WITH_WSREP */ + static bool fix_host_cache_size(sys_var *, THD *, enum_var_type) { hostname_cache_resize((uint) host_cache_size); diff --git a/sql/table.cc b/sql/table.cc index d720a16f6e5..735dbf6eedd 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -40,6 +40,7 @@ #include "sql_statistics.h" #include "discover.h" #include "mdl.h" // MDL_wait_for_graph_visitor +#include "ha_partition.h" /* INFORMATION_SCHEMA name */ LEX_STRING INFORMATION_SCHEMA_NAME= {C_STRING_WITH_LEN("information_schema")}; diff --git a/sql/transaction.cc b/sql/transaction.cc index 933e39ae357..9b3507de2eb 100644 --- a/sql/transaction.cc +++ b/sql/transaction.cc @@ -97,6 +97,10 @@ static bool xa_trans_force_rollback(THD *thd) by ha_rollback()/THD::transaction::cleanup(). */ thd->transaction.xid_state.rm_error= 0; +#ifdef WITH_WSREP + if (WSREP_ON) + wsrep_register_hton(thd, TRUE); +#endif /* WITH_WSREP */ if (ha_rollback_trans(thd, true)) { my_error(ER_XAER_RMERR, MYF(0)); @@ -135,10 +139,18 @@ bool trans_begin(THD *thd, uint flags) (thd->variables.option_bits & OPTION_TABLE_LOCK)) { thd->variables.option_bits&= ~OPTION_TABLE_LOCK; +#ifdef WITH_WSREP + if (WSREP_ON) + wsrep_register_hton(thd, TRUE); +#endif /* WITH_WSREP */ thd->server_status&= ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY); DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS")); res= MY_TEST(ha_commit_trans(thd, TRUE)); +#ifdef WITH_WSREP + if (WSREP_ON) + wsrep_post_commit(thd, TRUE); +#endif /* WITH_WSREP */ } thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG); @@ -181,6 +193,12 @@ bool trans_begin(THD *thd, uint flags) thd->tx_read_only= false; } +#ifdef WITH_WSREP + thd->wsrep_PA_safe= true; + if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) + DBUG_RETURN(TRUE); +#endif /* WITH_WSREP */ + thd->variables.option_bits|= OPTION_BEGIN; thd->server_status|= SERVER_STATUS_IN_TRANS; if (thd->tx_read_only) @@ -212,10 +230,18 @@ bool trans_commit(THD *thd) if (trans_check(thd)) DBUG_RETURN(TRUE); +#ifdef WITH_WSREP + if (WSREP_ON) + wsrep_register_hton(thd, TRUE); +#endif /* WITH_WSREP */ thd->server_status&= ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY); DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS")); res= ha_commit_trans(thd, TRUE); +#ifdef WITH_WSREP + if (WSREP_ON) + wsrep_post_commit(thd, TRUE); +#endif /* WITH_WSREP */ /* if res is non-zero, then ha_commit_trans has rolled back the transaction, so the hooks for rollback will be called. @@ -261,10 +287,18 @@ bool trans_commit_implicit(THD *thd) /* Safety if one did "drop table" on locked tables */ if (!thd->locked_tables_mode) thd->variables.option_bits&= ~OPTION_TABLE_LOCK; +#ifdef WITH_WSREP + if (WSREP_ON) + wsrep_register_hton(thd, TRUE); +#endif /* WITH_WSREP */ thd->server_status&= ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY); DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS")); res= MY_TEST(ha_commit_trans(thd, TRUE)); +#ifdef WITH_WSREP + if (WSREP_ON) + wsrep_post_commit(thd, TRUE); +#endif /* WITH_WSREP */ } thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG); @@ -297,9 +331,16 @@ bool trans_rollback(THD *thd) int res; DBUG_ENTER("trans_rollback"); +#ifdef WITH_WSREP + thd->wsrep_PA_safe= true; +#endif /* WITH_WSREP */ if (trans_check(thd)) DBUG_RETURN(TRUE); +#ifdef WITH_WSREP + if (WSREP_ON) + wsrep_register_hton(thd, TRUE); +#endif /* WITH_WSREP */ thd->server_status&= ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY); DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS")); @@ -390,11 +431,19 @@ bool trans_commit_stmt(THD *thd) if (thd->transaction.stmt.ha_list) { +#ifdef WITH_WSREP + if (WSREP_ON) + wsrep_register_hton(thd, FALSE); +#endif /* WITH_WSREP */ res= ha_commit_trans(thd, FALSE); if (! thd->in_active_multi_stmt_transaction()) { thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation; thd->tx_read_only= thd->variables.tx_read_only; +#ifdef WITH_WSREP + if (WSREP_ON) + wsrep_post_commit(thd, FALSE); +#endif /* WITH_WSREP */ } } @@ -435,6 +484,10 @@ bool trans_rollback_stmt(THD *thd) if (thd->transaction.stmt.ha_list) { +#ifdef WITH_WSREP + if (WSREP_ON) + wsrep_register_hton(thd, FALSE); +#endif /* WITH_WSREP */ ha_rollback_trans(thd, FALSE); if (! thd->in_active_multi_stmt_transaction()) { @@ -812,9 +865,17 @@ bool trans_xa_commit(THD *thd) } else if (xa_state == XA_IDLE && thd->lex->xa_opt == XA_ONE_PHASE) { +#ifdef WITH_WSREP + if (WSREP_ON) + wsrep_register_hton(thd, TRUE); +#endif /* WITH_WSREP */ int r= ha_commit_trans(thd, TRUE); if ((res= MY_TEST(r))) my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0)); +#ifdef WITH_WSREP + if (WSREP_ON) + wsrep_post_commit(thd, TRUE); +#endif /* WITH_WSREP */ } else if (xa_state == XA_PREPARED && thd->lex->xa_opt == XA_NONE) { @@ -833,6 +894,10 @@ bool trans_xa_commit(THD *thd) if (thd->mdl_context.acquire_lock(&mdl_request, thd->variables.lock_wait_timeout)) { +#ifdef WITH_WSREP + if (WSREP_ON) + wsrep_register_hton(thd, TRUE); +#endif /* WITH_WSREP */ ha_rollback_trans(thd, TRUE); my_error(ER_XAER_RMERR, MYF(0)); } diff --git a/sql/tztime.cc b/sql/tztime.cc index d3b4fec6335..577474cd78f 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -2708,6 +2708,13 @@ main(int argc, char **argv) free_defaults(default_argv); return 1; } + +#ifdef WITH_WSREP + // Replicate MyISAM DDL for this session, cf. lp:1161432 + // timezone info unfixable in XtraDB Cluster + printf("SET GLOBAL wsrep_replicate_myisam= ON;\n"); +#endif /* WITH_WSREP */ + if (argc == 1 && !opt_leap) { /* Argument is timezonedir */ @@ -2755,6 +2762,11 @@ main(int argc, char **argv) free_root(&tz_storage, MYF(0)); } +#ifdef WITH_WSREP + // Reset wsrep_replicate_myisam. lp:1161432 + printf("SET GLOBAL wsrep_replicate_myisam= OFF;\n"); +#endif /* WITH_WSREP */ + free_defaults(default_argv); my_end(0); return 0; diff --git a/sql/wsrep_applier.cc b/sql/wsrep_applier.cc new file mode 100644 index 00000000000..23687e98c32 --- /dev/null +++ b/sql/wsrep_applier.cc @@ -0,0 +1,387 @@ +/* Copyright (C) 2013 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + +#include "wsrep_priv.h" +#include "wsrep_binlog.h" // wsrep_dump_rbr_buf() + +#include "log_event.h" // EVENT_LEN_OFFSET, etc. +#include "wsrep_applier.h" + +/* + read the first event from (*buf). The size of the (*buf) is (*buf_len). + At the end (*buf) is shitfed to point to the following event or NULL and + (*buf_len) will be changed to account just being read bytes of the 1st event. +*/ + +static Log_event* wsrep_read_log_event( + char **arg_buf, size_t *arg_buf_len, + const Format_description_log_event *description_event) +{ + DBUG_ENTER("wsrep_read_log_event"); + char *head= (*arg_buf); + + uint data_len = uint4korr(head + EVENT_LEN_OFFSET); + char *buf= (*arg_buf); + const char *error= 0; + Log_event *res= 0; + + if (data_len > wsrep_max_ws_size) + { + error = "Event too big"; + goto err; + } + + res= Log_event::read_log_event(buf, data_len, &error, description_event, true); + +err: + if (!res) + { + DBUG_ASSERT(error != 0); + sql_print_error("Error in Log_event::read_log_event(): " + "'%s', data_len: %d, event_type: %d", + error,data_len,head[EVENT_TYPE_OFFSET]); + } + (*arg_buf)+= data_len; + (*arg_buf_len)-= data_len; + DBUG_RETURN(res); +} + +#include "transaction.h" // trans_commit(), trans_rollback() +#include "rpl_rli.h" // class Relay_log_info; +#include "sql_base.h" // close_temporary_table() + +static inline void +wsrep_set_apply_format(THD* thd, Format_description_log_event* ev) +{ + if (thd->wsrep_apply_format) + { + delete (Format_description_log_event*)thd->wsrep_apply_format; + } + thd->wsrep_apply_format= ev; +} + +static inline Format_description_log_event* +wsrep_get_apply_format(THD* thd) +{ + if (thd->wsrep_apply_format) + return (Format_description_log_event*) thd->wsrep_apply_format; + /* TODO: mariadb does not support rli->get_rli_description_event() + * => look for alternative way to remember last FDE in replication + */ + //return thd->wsrep_rli->get_rli_description_event(); + thd->wsrep_apply_format = new Format_description_log_event(4); + return (Format_description_log_event*) thd->wsrep_apply_format; +} + +static wsrep_cb_status_t wsrep_apply_events(THD* thd, + const void* events_buf, + size_t buf_len) +{ + char *buf= (char *)events_buf; + int rcode= 0; + int event= 1; + + DBUG_ENTER("wsrep_apply_events"); + + if (thd->killed == KILL_CONNECTION) + { + WSREP_INFO("applier has been aborted, skipping apply_rbr: %lld", + (long long) wsrep_thd_trx_seqno(thd)); + DBUG_RETURN(WSREP_CB_FAILURE); + } + + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + thd->wsrep_query_state= QUERY_EXEC; + if (thd->wsrep_conflict_state!= REPLAYING) + thd->wsrep_conflict_state= NO_CONFLICT; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + + if (!buf_len) WSREP_DEBUG("empty rbr buffer to apply: %lld", + (long long) wsrep_thd_trx_seqno(thd)); + + while(buf_len) + { + int exec_res; + Log_event* ev= wsrep_read_log_event(&buf, &buf_len, + wsrep_get_apply_format(thd)); + + if (!ev) + { + WSREP_ERROR("applier could not read binlog event, seqno: %lld, len: %zu", + (long long)wsrep_thd_trx_seqno(thd), buf_len); + rcode= 1; + goto error; + } + + switch (ev->get_type_code()) { + case FORMAT_DESCRIPTION_EVENT: + wsrep_set_apply_format(thd, (Format_description_log_event*)ev); + continue; +#ifdef GTID_SUPPORT + case GTID_LOG_EVENT: + { + Gtid_log_event* gev= (Gtid_log_event*)ev; + if (gev->get_gno() == 0) + { + /* Skip GTID log event to make binlog to generate LTID on commit */ + delete ev; + continue; + } + } +#endif /* GTID_SUPPORT */ + default: + break; + } + + thd->set_server_id(ev->server_id); // use the original server id for logging + thd->set_time(); // time the query + wsrep_xid_init(&thd->transaction.xid_state.xid, + &thd->wsrep_trx_meta.gtid.uuid, + thd->wsrep_trx_meta.gtid.seqno); + thd->lex->current_select= 0; + if (!ev->when) + { + my_hrtime_t hrtime= my_hrtime(); + ev->when= hrtime_to_my_time(hrtime); + ev->when_sec_part= hrtime_sec_part(hrtime); + } + + ev->thd = thd; + //exec_res = ev->apply_event(thd->wsrep_rli); + exec_res = ev->apply_event(thd->wsrep_rgi); + DBUG_PRINT("info", ("exec_event result: %d", exec_res)); + + if (exec_res) + { + WSREP_WARN("RBR event %d %s apply warning: %d, %lld", + event, ev->get_type_str(), exec_res, + (long long) wsrep_thd_trx_seqno(thd)); + rcode= exec_res; + /* stop processing for the first error */ + delete ev; + goto error; + } + event++; + + if (thd->wsrep_conflict_state!= NO_CONFLICT && + thd->wsrep_conflict_state!= REPLAYING) + WSREP_WARN("conflict state after RBR event applying: %d, %lld", + thd->wsrep_query_state, (long long)wsrep_thd_trx_seqno(thd)); + + if (thd->wsrep_conflict_state == MUST_ABORT) { + WSREP_WARN("RBR event apply failed, rolling back: %lld", + (long long) wsrep_thd_trx_seqno(thd)); + trans_rollback(thd); + thd->locked_tables_list.unlock_locked_tables(thd); + /* Release transactional metadata locks. */ + thd->mdl_context.release_transactional_locks(); + thd->wsrep_conflict_state= NO_CONFLICT; + DBUG_RETURN(WSREP_CB_FAILURE); + } + + delete ev; + } + + error: + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + thd->wsrep_query_state= QUERY_IDLE; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + + assert(thd->wsrep_exec_mode== REPL_RECV); + + if (thd->killed == KILL_CONNECTION) + WSREP_INFO("applier aborted: %lld", (long long)wsrep_thd_trx_seqno(thd)); + + if (rcode) DBUG_RETURN(WSREP_CB_FAILURE); + DBUG_RETURN(WSREP_CB_SUCCESS); +} + +wsrep_cb_status_t wsrep_apply_cb(void* const ctx, + const void* const buf, + size_t const buf_len, + uint32_t const flags, + const wsrep_trx_meta_t* meta) +{ + THD* const thd((THD*)ctx); + + thd->wsrep_trx_meta = *meta; + +#ifdef WSREP_PROC_INFO + snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, + "applying write set %lld: %p, %zu", + (long long)wsrep_thd_trx_seqno(thd), buf, buf_len); + thd_proc_info(thd, thd->wsrep_info); +#else + thd_proc_info(thd, "applying write set"); +#endif /* WSREP_PROC_INFO */ + + /* tune FK and UK checking policy */ + if (wsrep_slave_UK_checks == FALSE) + thd->variables.option_bits|= OPTION_RELAXED_UNIQUE_CHECKS; + else + thd->variables.option_bits&= ~OPTION_RELAXED_UNIQUE_CHECKS; + + if (wsrep_slave_FK_checks == FALSE) + thd->variables.option_bits|= OPTION_NO_FOREIGN_KEY_CHECKS; + else + thd->variables.option_bits&= ~OPTION_NO_FOREIGN_KEY_CHECKS; + + if (flags & WSREP_FLAG_ISOLATION) + { + thd->wsrep_apply_toi= true; + /* + Don't run in transaction mode with TOI actions. + */ + thd->variables.option_bits&= ~OPTION_BEGIN; + thd->server_status&= ~SERVER_STATUS_IN_TRANS; + } + wsrep_cb_status_t rcode(wsrep_apply_events(thd, buf, buf_len)); + +#ifdef WSREP_PROC_INFO + snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, + "applied write set %lld", (long long)wsrep_thd_trx_seqno(thd)); + thd_proc_info(thd, thd->wsrep_info); +#else + thd_proc_info(thd, "applied write set"); +#endif /* WSREP_PROC_INFO */ + + if (WSREP_CB_SUCCESS != rcode) + { + wsrep_dump_rbr_buf(thd, buf, buf_len); + } + + TABLE *tmp; + while ((tmp = thd->temporary_tables)) + { + WSREP_DEBUG("Applier %lu, has temporary tables: %s.%s", + thd->thread_id, + (tmp->s) ? tmp->s->db.str : "void", + (tmp->s) ? tmp->s->table_name.str : "void"); + close_temporary_table(thd, tmp, 1, 1); + } + + return rcode; +} + +static wsrep_cb_status_t wsrep_commit(THD* const thd, + wsrep_seqno_t const global_seqno) +{ +#ifdef WSREP_PROC_INFO + snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, + "committing %lld", (long long)wsrep_thd_trx_seqno(thd)); + thd_proc_info(thd, thd->wsrep_info); +#else + thd_proc_info(thd, "committing"); +#endif /* WSREP_PROC_INFO */ + + wsrep_cb_status_t const rcode(trans_commit(thd) ? + WSREP_CB_FAILURE : WSREP_CB_SUCCESS); + +#ifdef WSREP_PROC_INFO + snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, + "committed %lld", (long long)wsrep_thd_trx_seqno(thd)); + thd_proc_info(thd, thd->wsrep_info); +#else + thd_proc_info(thd, "committed"); +#endif /* WSREP_PROC_INFO */ + + if (WSREP_CB_SUCCESS == rcode) + { + thd->wsrep_rgi->cleanup_context(thd, false); +#ifdef GTID_SUPPORT + thd->variables.gtid_next.set_automatic(); +#endif /* GTID_SUPPORT */ + // TODO: mark snapshot with global_seqno. + } + + return rcode; +} + +static wsrep_cb_status_t wsrep_rollback(THD* const thd, + wsrep_seqno_t const global_seqno) +{ +#ifdef WSREP_PROC_INFO + snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, + "rolling back %lld", (long long)wsrep_thd_trx_seqno(thd)); + thd_proc_info(thd, thd->wsrep_info); +#else + thd_proc_info(thd, "rolling back"); +#endif /* WSREP_PROC_INFO */ + + wsrep_cb_status_t const rcode(trans_rollback(thd) ? + WSREP_CB_FAILURE : WSREP_CB_SUCCESS); + +#ifdef WSREP_PROC_INFO + snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, + "rolled back %lld", (long long)wsrep_thd_trx_seqno(thd)); + thd_proc_info(thd, thd->wsrep_info); +#else + thd_proc_info(thd, "rolled back"); +#endif /* WSREP_PROC_INFO */ + + return rcode; +} + +wsrep_cb_status_t wsrep_commit_cb(void* const ctx, + uint32_t const flags, + const wsrep_trx_meta_t* meta, + wsrep_bool_t* const exit, + bool const commit) +{ + THD* const thd((THD*)ctx); + + assert(meta->gtid.seqno == wsrep_thd_trx_seqno(thd)); + + wsrep_cb_status_t rcode; + + if (commit) + rcode = wsrep_commit(thd, meta->gtid.seqno); + else + rcode = wsrep_rollback(thd, meta->gtid.seqno); + + wsrep_set_apply_format(thd, NULL); + thd->mdl_context.release_transactional_locks(); + free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC)); + thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation; + + if (wsrep_slave_count_change < 0 && commit && WSREP_CB_SUCCESS == rcode) + { + mysql_mutex_lock(&LOCK_wsrep_slave_threads); + if (wsrep_slave_count_change < 0) + { + wsrep_slave_count_change++; + *exit = true; + } + mysql_mutex_unlock(&LOCK_wsrep_slave_threads); + } + + if (*exit == false && thd->wsrep_applier) + { + /* From trans_begin() */ + thd->variables.option_bits|= OPTION_BEGIN; + thd->server_status|= SERVER_STATUS_IN_TRANS; + thd->wsrep_apply_toi= false; + } + + return rcode; +} + + +wsrep_cb_status_t wsrep_unordered_cb(void* const ctx, + const void* const data, + size_t const size) +{ + return WSREP_CB_SUCCESS; +} diff --git a/sql/wsrep_applier.h b/sql/wsrep_applier.h new file mode 100644 index 00000000000..816970db67c --- /dev/null +++ b/sql/wsrep_applier.h @@ -0,0 +1,38 @@ +/* Copyright 2013 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef WSREP_APPLIER_H +#define WSREP_APPLIER_H + +#include + +/* wsrep callback prototypes */ + +wsrep_cb_status_t wsrep_apply_cb(void *ctx, + const void* buf, size_t buf_len, + uint32_t flags, + const wsrep_trx_meta_t* meta); + +wsrep_cb_status_t wsrep_commit_cb(void *ctx, + uint32_t flags, + const wsrep_trx_meta_t* meta, + wsrep_bool_t* exit, + bool commit); + +wsrep_cb_status_t wsrep_unordered_cb(void* ctx, + const void* data, + size_t size); + +#endif /* WSREP_APPLIER_H */ diff --git a/sql/wsrep_binlog.cc b/sql/wsrep_binlog.cc new file mode 100644 index 00000000000..ee8a9cb130b --- /dev/null +++ b/sql/wsrep_binlog.cc @@ -0,0 +1,414 @@ +/* Copyright (C) 2013 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + +#include "wsrep_binlog.h" +#include "wsrep_priv.h" +#include "log.h" + +extern handlerton *binlog_hton; +/* + Write the contents of a cache to a memory buffer. + + This function quite the same as MYSQL_BIN_LOG::write_cache(), + with the exception that here we write in buffer instead of log file. + */ +int wsrep_write_cache_buf(IO_CACHE *cache, uchar **buf, size_t *buf_len) +{ + *buf= NULL; + *buf_len= 0; + + my_off_t const saved_pos(my_b_tell(cache)); + + if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0)) + { + WSREP_ERROR("failed to initialize io-cache"); + return ER_ERROR_ON_WRITE; + } + + uint length = my_b_bytes_in_cache(cache); + if (unlikely(0 == length)) length = my_b_fill(cache); + + size_t total_length = 0; + + if (likely(length > 0)) do + { + total_length += length; + /* + Bail out if buffer grows too large. + A temporary fix to avoid allocating indefinitely large buffer, + not a real limit on a writeset size which includes other things + like header and keys. + */ + if (total_length > wsrep_max_ws_size) + { + WSREP_WARN("transaction size limit (%lu) exceeded: %zu", + wsrep_max_ws_size, total_length); + goto error; + } + uchar* tmp = (uchar *)my_realloc(*buf, total_length, + MYF(MY_ALLOW_ZERO_PTR)); + if (!tmp) + { + WSREP_ERROR("could not (re)allocate buffer: %zu + %u", + *buf_len, length); + goto error; + } + *buf = tmp; + + memcpy(*buf + *buf_len, cache->read_pos, length); + *buf_len = total_length; + cache->read_pos = cache->read_end; + } while ((cache->file >= 0) && (length = my_b_fill(cache))); + + if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0)) + { + WSREP_WARN("failed to initialize io-cache"); + goto cleanup; + } + + return 0; + +error: + if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0)) + { + WSREP_WARN("failed to initialize io-cache"); + } +cleanup: + my_free(*buf); + *buf= NULL; + *buf_len= 0; + return ER_ERROR_ON_WRITE; +} + +#define STACK_SIZE 4096 /* 4K - for buffer preallocated on the stack: + * many transactions would fit in there + * so there is no need to reach for the heap */ + +/* Returns minimum multiple of HEAP_PAGE_SIZE that is >= length */ +static inline size_t +heap_size(size_t length) +{ + return (length + HEAP_PAGE_SIZE - 1)/HEAP_PAGE_SIZE*HEAP_PAGE_SIZE; +} + +/* append data to writeset */ +static inline wsrep_status_t +wsrep_append_data(wsrep_t* const wsrep, + wsrep_ws_handle_t* const ws, + const void* const data, + size_t const len) +{ + struct wsrep_buf const buff = { data, len }; + wsrep_status_t const rc(wsrep->append_data(wsrep, ws, &buff, 1, + WSREP_DATA_ORDERED, true)); + if (rc != WSREP_OK) + { + WSREP_WARN("append_data() returned %d", rc); + } + + return rc; +} + +/* + Write the contents of a cache to wsrep provider. + + This function quite the same as MYSQL_BIN_LOG::write_cache(), + with the exception that here we write in buffer instead of log file. + + This version reads all of cache into single buffer and then appends to a + writeset at once. + */ +static int wsrep_write_cache_once(wsrep_t* const wsrep, + THD* const thd, + IO_CACHE* const cache, + size_t* const len) +{ + my_off_t const saved_pos(my_b_tell(cache)); + + if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0)) + { + WSREP_ERROR("failed to initialize io-cache"); + return ER_ERROR_ON_WRITE; + } + + int err(WSREP_OK); + + size_t total_length(0); + uchar stack_buf[STACK_SIZE]; /* to avoid dynamic allocations for few data*/ + uchar* heap_buf(NULL); + uchar* buf(stack_buf); + size_t allocated(sizeof(stack_buf)); + size_t used(0); + + uint length(my_b_bytes_in_cache(cache)); + if (unlikely(0 == length)) length = my_b_fill(cache); + + if (likely(length > 0)) do + { + total_length += length; + /* + Bail out if buffer grows too large. + A temporary fix to avoid allocating indefinitely large buffer, + not a real limit on a writeset size which includes other things + like header and keys. + */ + if (unlikely(total_length > wsrep_max_ws_size)) + { + WSREP_WARN("transaction size limit (%lu) exceeded: %zu", + wsrep_max_ws_size, total_length); + err = WSREP_TRX_SIZE_EXCEEDED; + goto cleanup; + } + + if (total_length > allocated) + { + size_t const new_size(heap_size(total_length)); + uchar* tmp = (uchar *)my_realloc(heap_buf, new_size, + MYF(MY_ALLOW_ZERO_PTR)); + if (!tmp) + { + WSREP_ERROR("could not (re)allocate buffer: %zu + %u", + allocated, length); + err = WSREP_TRX_SIZE_EXCEEDED; + goto cleanup; + } + + heap_buf = tmp; + buf = heap_buf; + allocated = new_size; + + if (used <= STACK_SIZE && used > 0) // there's data in stack_buf + { + DBUG_ASSERT(buf == stack_buf); + memcpy(heap_buf, stack_buf, used); + } + } + + memcpy(buf + used, cache->read_pos, length); + used = total_length; + cache->read_pos = cache->read_end; + } while ((cache->file >= 0) && (length = my_b_fill(cache))); + + if (used > 0) + err = wsrep_append_data(wsrep, &thd->wsrep_ws_handle, buf, used); + + if (WSREP_OK == err) *len = total_length; + +cleanup: + if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0)) + { + WSREP_ERROR("failed to reinitialize io-cache"); + } + + if (unlikely(WSREP_OK != err)) wsrep_dump_rbr_buf(thd, buf, used); + + my_free(heap_buf); + return err; +} + +/* + Write the contents of a cache to wsrep provider. + + This function quite the same as MYSQL_BIN_LOG::write_cache(), + with the exception that here we write in buffer instead of log file. + + This version uses incremental data appending as it reads it from cache. + */ +static int wsrep_write_cache_inc(wsrep_t* const wsrep, + THD* const thd, + IO_CACHE* const cache, + size_t* const len) +{ + my_off_t const saved_pos(my_b_tell(cache)); + + if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0)) + { + WSREP_ERROR("failed to initialize io-cache"); + return WSREP_TRX_ERROR; + } + + int err(WSREP_OK); + + size_t total_length(0); + + uint length(my_b_bytes_in_cache(cache)); + if (unlikely(0 == length)) length = my_b_fill(cache); + + if (likely(length > 0)) do + { + total_length += length; + /* bail out if buffer grows too large + not a real limit on a writeset size which includes other things + like header and keys. + */ + if (unlikely(total_length > wsrep_max_ws_size)) + { + WSREP_WARN("transaction size limit (%lu) exceeded: %zu", + wsrep_max_ws_size, total_length); + err = WSREP_TRX_SIZE_EXCEEDED; + goto cleanup; + } + + if(WSREP_OK != (err=wsrep_append_data(wsrep, &thd->wsrep_ws_handle, + cache->read_pos, length))) + goto cleanup; + + cache->read_pos = cache->read_end; + } while ((cache->file >= 0) && (length = my_b_fill(cache))); + + if (WSREP_OK == err) *len = total_length; + +cleanup: + if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0)) + { + WSREP_ERROR("failed to reinitialize io-cache"); + } + + return err; +} + +/* + Write the contents of a cache to wsrep provider. + + This function quite the same as MYSQL_BIN_LOG::write_cache(), + with the exception that here we write in buffer instead of log file. + */ +int wsrep_write_cache(wsrep_t* const wsrep, + THD* const thd, + IO_CACHE* const cache, + size_t* const len) +{ + if (wsrep_incremental_data_collection) { + return wsrep_write_cache_inc(wsrep, thd, cache, len); + } + else { + return wsrep_write_cache_once(wsrep, thd, cache, len); + } +} + +void wsrep_dump_rbr_buf(THD *thd, const void* rbr_buf, size_t buf_len) +{ + char filename[PATH_MAX]= {0}; + int len= snprintf(filename, PATH_MAX, "%s/GRA_%ld_%lld.log", + wsrep_data_home_dir, thd->thread_id, + (long long)wsrep_thd_trx_seqno(thd)); + if (len >= PATH_MAX) + { + WSREP_ERROR("RBR dump path too long: %d, skipping dump.", len); + return; + } + + FILE *of= fopen(filename, "wb"); + if (of) + { + fwrite (rbr_buf, buf_len, 1, of); + fclose(of); + } + else + { + WSREP_ERROR("Failed to open file '%s': %d (%s)", + filename, errno, strerror(errno)); + } +} + +/* + wsrep exploits binlog's caches even if binlogging itself is not + activated. In such case connection close needs calling + actual binlog's method. + Todo: split binlog hton from its caches to use ones by wsrep + without referring to binlog's stuff. +*/ +int wsrep_binlog_close_connection(THD* thd) +{ + DBUG_ENTER("wsrep_binlog_close_connection"); + if (thd_get_ha_data(thd, binlog_hton) != NULL) + binlog_hton->close_connection (binlog_hton, thd); + DBUG_RETURN(0); +} + +int wsrep_binlog_savepoint_set(THD *thd, void *sv) +{ + if (!wsrep_emulate_bin_log) return 0; + int rcode = binlog_hton->savepoint_set(binlog_hton, thd, sv); + return rcode; +} + +int wsrep_binlog_savepoint_rollback(THD *thd, void *sv) +{ + if (!wsrep_emulate_bin_log) return 0; + int rcode = binlog_hton->savepoint_rollback(binlog_hton, thd, sv); + return rcode; +} + +void wsrep_dump_rbr_direct(THD* thd, IO_CACHE* cache) +{ + char filename[PATH_MAX]= {0}; + int len= snprintf(filename, PATH_MAX, "%s/GRA_%ld_%lld.log", + wsrep_data_home_dir, thd->thread_id, + (long long)wsrep_thd_trx_seqno(thd)); + size_t bytes_in_cache = 0; + // check path + if (len >= PATH_MAX) + { + WSREP_ERROR("RBR dump path too long: %d, skipping dump.", len); + return ; + } + // init cache + my_off_t const saved_pos(my_b_tell(cache)); + if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0)) + { + WSREP_ERROR("failed to initialize io-cache"); + return ; + } + // open file + FILE* of = fopen(filename, "wb"); + if (!of) + { + WSREP_ERROR("Failed to open file '%s': %d (%s)", + filename, errno, strerror(errno)); + goto cleanup; + } + // ready to write + bytes_in_cache= my_b_bytes_in_cache(cache); + if (unlikely(bytes_in_cache == 0)) bytes_in_cache = my_b_fill(cache); + if (likely(bytes_in_cache > 0)) do + { + if (my_fwrite(of, cache->read_pos, bytes_in_cache, + MYF(MY_WME | MY_NABP)) == (size_t) -1) + { + WSREP_ERROR("Failed to write file '%s'", filename); + goto cleanup; + } + cache->read_pos= cache->read_end; + } while ((cache->file >= 0) && (bytes_in_cache= my_b_fill(cache))); + if(cache->error == -1) + { + WSREP_ERROR("RBR inconsistent"); + goto cleanup; + } +cleanup: + // init back + if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0)) + { + WSREP_ERROR("failed to reinitialize io-cache"); + } + // close file + if (of) fclose(of); +} + +void thd_binlog_flush_pending_rows_event(THD *thd, bool stmt_end) +{ + thd->binlog_flush_pending_rows_event(stmt_end); +} diff --git a/sql/wsrep_binlog.h b/sql/wsrep_binlog.h new file mode 100644 index 00000000000..a3d8ec6ec2c --- /dev/null +++ b/sql/wsrep_binlog.h @@ -0,0 +1,59 @@ +/* Copyright (C) 2013 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + +#ifndef WSREP_BINLOG_H +#define WSREP_BINLOG_H + +#include "sql_class.h" // THD, IO_CACHE + +#define HEAP_PAGE_SIZE 65536 /* 64K */ +#define WSREP_MAX_WS_SIZE (0xFFFFFFFFUL - HEAP_PAGE_SIZE) + +/* + Write the contents of a cache to a memory buffer. + + This function quite the same as MYSQL_BIN_LOG::write_cache(), + with the exception that here we write in buffer instead of log file. + */ +int wsrep_write_cache_buf(IO_CACHE *cache, uchar **buf, size_t *buf_len); + +/* + Write the contents of a cache to wsrep provider. + + This function quite the same as MYSQL_BIN_LOG::write_cache(), + with the exception that here we write in buffer instead of log file. + + @param len total amount of data written + @return wsrep error status + */ +int wsrep_write_cache (wsrep_t* wsrep, + THD* thd, + IO_CACHE* cache, + size_t* len); + +/* Dump replication buffer to disk */ +void wsrep_dump_rbr_buf(THD *thd, const void* rbr_buf, size_t buf_len); + +/* Dump replication buffer to disk without intermediate buffer */ +void wsrep_dump_rbr_direct(THD* thd, IO_CACHE* cache); + +int wsrep_binlog_close_connection(THD* thd); +int wsrep_binlog_savepoint_set(THD *thd, void *sv); +int wsrep_binlog_savepoint_rollback(THD *thd, void *sv); + +/* Dump replication buffer to disk without intermediate buffer */ +void wsrep_dump_rbr_direct(THD* thd, IO_CACHE* cache); + +#endif /* WSREP_BINLOG_H */ diff --git a/sql/wsrep_check_opts.cc b/sql/wsrep_check_opts.cc new file mode 100644 index 00000000000..5ec18c79978 --- /dev/null +++ b/sql/wsrep_check_opts.cc @@ -0,0 +1,379 @@ +/* Copyright 2011 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +//#include +#include +//#include +//#include + +#include "wsrep_mysqld.h" + +#include +#include +#include +#include + +/* This file is about checking for correctness of mysql configuration options */ + +struct opt +{ + const char* const name; + const char* value; +}; + +/* A list of options to check. + * At first we assume default values and then see if they are changed on CLI or + * in my.cnf */ +static struct opt opts[] = +{ + { "wsrep_slave_threads", "1" }, // mysqld.cc + { "bind_address", "0.0.0.0" }, // mysqld.cc + { "wsrep_sst_method", "rsync" }, // mysqld.cc + { "wsrep_sst_receive_address","AUTO"}, // mysqld.cc + { "binlog_format", "ROW" }, // mysqld.cc + { "wsrep_provider", "none" }, // mysqld.cc + { "query_cache_type", "0" }, // mysqld.cc + { "query_cache_size", "0" }, // mysqld.cc + { "locked_in_memory", "0" }, // mysqld.cc + { "wsrep_cluster_address", "0" }, // mysqld.cc + { "locks_unsafe_for_binlog", "0" }, // ha_innodb.cc + { "autoinc_lock_mode", "1" }, // ha_innodb.cc + { 0, 0 } +}; + +enum +{ + WSREP_SLAVE_THREADS, + BIND_ADDRESS, + WSREP_SST_METHOD, + WSREP_SST_RECEIVE_ADDRESS, + BINLOG_FORMAT, + WSREP_PROVIDER, + QUERY_CACHE_TYPE, + QUERY_CACHE_SIZE, + LOCKED_IN_MEMORY, + WSREP_CLUSTER_ADDRESS, + LOCKS_UNSAFE_FOR_BINLOG, + AUTOINC_LOCK_MODE +}; + + +/* A class to make a copy of argv[] vector */ +struct argv_copy +{ + int const argc_; + char** argv_; + + argv_copy (int const argc, const char* const argv[]) : + argc_ (argc), + argv_ (reinterpret_cast(calloc(argc_, sizeof(char*)))) + { + if (argv_) + { + for (int i = 0; i < argc_; ++i) + { + argv_[i] = strdup(argv[i]); + + if (!argv_[i]) + { + argv_free (); // free whatever bee allocated + return; + } + } + } + } + + ~argv_copy () { argv_free (); } + +private: + argv_copy (const argv_copy&); + argv_copy& operator= (const argv_copy&); + + void argv_free() + { + if (argv_) + { + for (int i = 0; (i < argc_) && argv_[i] ; ++i) free (argv_[i]); + free (argv_); + argv_ = 0; + } + } +}; + +/* a short corresponding to '--' byte sequence */ +static short const long_opt_prefix ('-' + ('-' << 8)); + +/* Normalizes long options to have '_' instead of '-' */ +static int +normalize_opts (argv_copy& a) +{ + if (a.argv_) + { + for (int i = 0; i < a.argc_; ++i) + { + char* ptr = a.argv_[i]; + if (long_opt_prefix == *(short*)ptr) // long option + { + ptr += 2; + const char* end = strchr(ptr, '='); + + if (!end) end = ptr + strlen(ptr); + + for (; ptr != end; ++ptr) if ('-' == *ptr) *ptr = '_'; + } + } + + return 0; + } + + return EINVAL; +} + +/* Find required options in the argument list and change their values */ +static int +find_opts (argv_copy& a, struct opt* const opts) +{ + for (int i = 0; i < a.argc_; ++i) + { + char* ptr = a.argv_[i] + 2; // we're interested only in long options + + struct opt* opt = opts; + for (; 0 != opt->name; ++opt) + { + if (!strstr(ptr, opt->name)) continue; // try next option + + /* 1. try to find value after the '=' */ + opt->value = strchr(ptr, '=') + 1; + + /* 2. if no '=', try next element in the argument vector */ + if (reinterpret_cast(1) == opt->value) + { + /* also check that the next element is not an option itself */ + if (i + 1 < a.argc_ && *(a.argv_[i + 1]) != '-') + { + ++i; + opt->value = a.argv_[i]; + } + else opt->value = ""; // no value supplied (like boolean opt) + } + + break; // option found, break inner loop + } + } + + return 0; +} + +/* Parses string for an integer. Returns 0 on success. */ +int get_long_long (const struct opt& opt, long long* const val, int const base) +{ + const char* const str = opt.value; + + if ('\0' != *str) + { + char* endptr; + + *val = strtoll (str, &endptr, base); + + if ('k' == *endptr || 'K' == *endptr) + { + *val *= 1024L; + endptr++; + } + else if ('m' == *endptr || 'M' == *endptr) + { + *val *= 1024L * 1024L; + endptr++; + } + else if ('g' == *endptr || 'G' == *endptr) + { + *val *= 1024L * 1024L * 1024L; + endptr++; + } + + if ('\0' == *endptr) return 0; // the whole string was a valid integer + } + + WSREP_ERROR ("Bad value for *%s: '%s'. Should be integer.", + opt.name, opt.value); + + return EINVAL; +} + +/* This is flimzy coz hell knows how mysql interprets boolean strings... + * and, no, I'm not going to become versed in how mysql handles options - + * I'd rather sing. + + Aha, http://dev.mysql.com/doc/refman/5.1/en/dynamic-system-variables.html: + Variables that have a type of “boolean†can be set to 0, 1, ON or OFF. (If you + set them on the command line or in an option file, use the numeric values.) + + So it is '0' for FALSE, '1' or empty string for TRUE + + */ +int get_bool (const struct opt& opt, bool* const val) +{ + const char* str = opt.value; + + while (isspace(*str)) ++str; // skip initial whitespaces + + ssize_t str_len = strlen(str); + switch (str_len) + { + case 0: + *val = true; + return 0; + case 1: + if ('0' == *str || '1' == *str) + { + *val = ('1' == *str); + return 0; + } + } + + WSREP_ERROR ("Bad value for *%s: '%s'. Should be '0', '1' or empty string.", + opt.name, opt.value); + + return EINVAL; +} + +static int +check_opts (int const argc, const char* const argv[], struct opt opts[]) +{ + /* First, make a copy of argv to be able to manipulate it */ + argv_copy a(argc, argv); + + if (!a.argv_) + { + WSREP_ERROR ("Could not copy argv vector: not enough memory."); + return ENOMEM; + } + + int err = normalize_opts (a); + if (err) + { + WSREP_ERROR ("Failed to normalize options."); + return err; + } + + err = find_opts (a, opts); + if (err) + { + WSREP_ERROR ("Failed to parse options."); + return err; + } + + /* At this point we have updated default values in our option list to + what has been specified on the command line / my.cnf */ + + long long slave_threads; + err = get_long_long (opts[WSREP_SLAVE_THREADS], &slave_threads, 10); + if (err) return err; + + int rcode = 0; + + if (slave_threads > 1) + /* Need to check AUTOINC_LOCK_MODE and LOCKS_UNSAFE_FOR_BINLOG */ + { + long long autoinc_lock_mode; + err = get_long_long (opts[AUTOINC_LOCK_MODE], &autoinc_lock_mode, 10); + if (err) return err; + + bool locks_unsafe_for_binlog; + err = get_bool (opts[LOCKS_UNSAFE_FOR_BINLOG],&locks_unsafe_for_binlog); + if (err) return err; + + if (autoinc_lock_mode != 2) + { + WSREP_ERROR ("Parallel applying (wsrep_slave_threads > 1) requires" + " innodb_autoinc_lock_mode = 2."); + rcode = EINVAL; + } + } + + bool locked_in_memory; + err = get_bool (opts[LOCKED_IN_MEMORY], &locked_in_memory); + if (err) { WSREP_ERROR("get_bool error: %s", strerror(err)); return err; } + if (locked_in_memory) + { + WSREP_ERROR ("Memory locking is not supported (locked_in_memory=%s)", + locked_in_memory ? "ON" : "OFF"); + rcode = EINVAL; + } + + if (!strcasecmp(opts[WSREP_SST_METHOD].value,"mysqldump")) + { + if (!strcasecmp(opts[BIND_ADDRESS].value, "127.0.0.1") || + !strcasecmp(opts[BIND_ADDRESS].value, "localhost")) + { + WSREP_ERROR ("wsrep_sst_method is set to 'mysqldump' yet " + "mysqld bind_address is set to '%s', which makes it " + "impossible to receive state transfer from another " + "node, since mysqld won't accept such connections. " + "If you wish to use mysqldump state transfer method, " + "set bind_address to allow mysql client connections " + "from other cluster members (e.g. 0.0.0.0).", + opts[BIND_ADDRESS].value); + rcode = EINVAL; + } + } + else + { + // non-mysqldump SST requires wsrep_cluster_address on startup + if (strlen(opts[WSREP_CLUSTER_ADDRESS].value) == 0) + { + WSREP_ERROR ("%s SST method requires wsrep_cluster_address to be " + "configured on startup.",opts[WSREP_SST_METHOD].value); + rcode = EINVAL; + } + } + + if (strcasecmp(opts[WSREP_SST_RECEIVE_ADDRESS].value, "AUTO")) + { + if (!strncasecmp(opts[WSREP_SST_RECEIVE_ADDRESS].value, + "127.0.0.1", strlen("127.0.0.1")) || + !strncasecmp(opts[WSREP_SST_RECEIVE_ADDRESS].value, + "localhost", strlen("localhost"))) + { + WSREP_WARN ("wsrep_sst_receive_address is set to '%s' which " + "makes it impossible for another host to reach this " + "one. Please set it to the address which this node " + "can be connected at by other cluster members.", + opts[WSREP_SST_RECEIVE_ADDRESS].value); +// rcode = EINVAL; + } + } + + if (strcasecmp(opts[WSREP_PROVIDER].value, "none")) + { + if (strcasecmp(opts[BINLOG_FORMAT].value, "ROW")) + { + WSREP_ERROR ("Only binlog_format = 'ROW' is currently supported. " + "Configured value: '%s'. Please adjust your " + "configuration.", opts[BINLOG_FORMAT].value); + + rcode = EINVAL; + } + } + + return rcode; +} + +int +wsrep_check_opts (int const argc, char* const* const argv) +{ + return check_opts (argc, argv, opts); +} + diff --git a/sql/wsrep_hton.cc b/sql/wsrep_hton.cc new file mode 100644 index 00000000000..96f1431a82f --- /dev/null +++ b/sql/wsrep_hton.cc @@ -0,0 +1,577 @@ +/* Copyright 2008 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include +#include "sql_base.h" +#include "rpl_filter.h" +#include +#include "wsrep_mysqld.h" +#include "wsrep_binlog.h" +#include +#include + +extern ulonglong thd_to_trx_id(THD *thd); + +extern "C" int thd_binlog_format(const MYSQL_THD thd); +// todo: share interface with ha_innodb.c + +enum wsrep_trx_status wsrep_run_wsrep_commit(THD *thd, handlerton *hton, + bool all); + +/* + Cleanup after local transaction commit/rollback, replay or TOI. +*/ +void wsrep_cleanup_transaction(THD *thd) +{ + if (wsrep_emulate_bin_log) thd_binlog_trx_reset(thd); + thd->wsrep_ws_handle.trx_id= WSREP_UNDEFINED_TRX_ID; + thd->wsrep_trx_meta.gtid= WSREP_GTID_UNDEFINED; + thd->wsrep_trx_meta.depends_on= WSREP_SEQNO_UNDEFINED; + thd->wsrep_exec_mode= LOCAL_STATE; + return; +} + +/* + wsrep hton +*/ +handlerton *wsrep_hton; + + +/* + Registers wsrep hton at commit time if transaction has registered htons + for supported engine types. + + Hton should not be registered for TOTAL_ORDER operations. + + Registration is needed for both LOCAL_MODE and REPL_RECV transactions to run + commit in 2pc so that wsrep position gets properly recorded in storage + engines. + + Note that all hton calls should immediately return for threads that are + in REPL_RECV mode as their states are controlled by wsrep appliers or + replaying code. Only threads in LOCAL_MODE should run wsrep callbacks + from hton methods. +*/ +void wsrep_register_hton(THD* thd, bool all) +{ + if (thd->wsrep_exec_mode != TOTAL_ORDER && !thd->wsrep_apply_toi) + { + THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt; + for (Ha_trx_info *i= trans->ha_list; WSREP(thd) && i; i = i->next()) + { + if ((i->ht()->db_type == DB_TYPE_INNODB) || + (i->ht()->db_type == DB_TYPE_TOKUDB)) + { + trans_register_ha(thd, all, wsrep_hton); + + /* follow innodb read/write settting + * but, as an exception: CTAS with empty result set will not be + * replicated unless we declare wsrep hton as read/write here + */ + if (i->is_trx_read_write() || + (thd->lex->sql_command == SQLCOM_CREATE_TABLE && + thd->wsrep_exec_mode == LOCAL_STATE)) + { + thd->ha_data[wsrep_hton->slot].ha_info[all].set_trx_read_write(); + } + break; + } + } + } +} + +/* + Calls wsrep->post_commit() for locally executed transactions that have + got seqno from provider (must commit) and don't require replaying. + */ +void wsrep_post_commit(THD* thd, bool all) +{ + if (thd->wsrep_exec_mode == LOCAL_COMMIT) + { + DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno != WSREP_SEQNO_UNDEFINED); + if (wsrep->post_commit(wsrep, &thd->wsrep_ws_handle)) + { + DBUG_PRINT("wsrep", ("set committed fail")); + WSREP_WARN("set committed fail: %llu %d", + (long long)thd->real_id, thd->get_stmt_da()->status()); + } + wsrep_cleanup_transaction(thd); + } +} + +/* + wsrep exploits binlog's caches even if binlogging itself is not + activated. In such case connection close needs calling + actual binlog's method. + Todo: split binlog hton from its caches to use ones by wsrep + without referring to binlog's stuff. +*/ +static int +wsrep_close_connection(handlerton* hton, THD* thd) +{ + DBUG_ENTER("wsrep_close_connection"); + + if (thd->wsrep_exec_mode == REPL_RECV) + { + DBUG_RETURN(0); + } + DBUG_RETURN(wsrep_binlog_close_connection (thd)); +} + +/* + prepare/wsrep_run_wsrep_commit can fail in two ways + - certification test or an equivalent. As a result, + the current transaction just rolls back + Error codes: + WSREP_TRX_CERT_FAIL, WSREP_TRX_SIZE_EXCEEDED, WSREP_TRX_ERROR + - a post-certification failure makes this server unable to + commit its own WS and therefore the server must abort +*/ +static int wsrep_prepare(handlerton *hton, THD *thd, bool all) +{ + DBUG_ENTER("wsrep_prepare"); + + if (thd->wsrep_exec_mode == REPL_RECV) + { + DBUG_RETURN(0); + } + + DBUG_ASSERT(thd->ha_data[wsrep_hton->slot].ha_info[all].is_trx_read_write()); + DBUG_ASSERT(thd->wsrep_exec_mode == LOCAL_STATE); + DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno == WSREP_SEQNO_UNDEFINED); + + if ((all || + !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) && + (thd->variables.wsrep_on && !wsrep_trans_cache_is_empty(thd))) + { + DBUG_RETURN (wsrep_run_wsrep_commit(thd, hton, all)); + } + DBUG_RETURN(0); +} + +static int wsrep_savepoint_set(handlerton *hton, THD *thd, void *sv) +{ + DBUG_ENTER("wsrep_savepoint_set"); + + if (thd->wsrep_exec_mode == REPL_RECV) + { + DBUG_RETURN(0); + } + + if (!wsrep_emulate_bin_log) DBUG_RETURN(0); + int rcode = wsrep_binlog_savepoint_set(thd, sv); + DBUG_RETURN(rcode); +} + +static int wsrep_savepoint_rollback(handlerton *hton, THD *thd, void *sv) +{ + DBUG_ENTER("wsrep_savepoint_rollback"); + + if (thd->wsrep_exec_mode == REPL_RECV) + { + DBUG_RETURN(0); + } + + if (!wsrep_emulate_bin_log) DBUG_RETURN(0); + int rcode = wsrep_binlog_savepoint_rollback(thd, sv); + DBUG_RETURN(rcode); +} + +static int wsrep_rollback(handlerton *hton, THD *thd, bool all) +{ + DBUG_ENTER("wsrep_rollback"); + + if (thd->wsrep_exec_mode == REPL_RECV) + { + DBUG_RETURN(0); + } + + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + switch (thd->wsrep_exec_mode) + { + case TOTAL_ORDER: + case REPL_RECV: + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + WSREP_DEBUG("Avoiding wsrep rollback for failed DDL: %s", thd->query()); + DBUG_RETURN(0); + default: break; + } + + if ((all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) && + (thd->variables.wsrep_on && thd->wsrep_conflict_state != MUST_REPLAY)) + { + if (wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle)) + { + DBUG_PRINT("wsrep", ("setting rollback fail")); + WSREP_ERROR("settting rollback fail: thd: %llu SQL: %s", + (long long)thd->real_id, thd->query()); + } + wsrep_cleanup_transaction(thd); + } + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + DBUG_RETURN(0); +} + +int wsrep_commit(handlerton *hton, THD *thd, bool all) +{ + DBUG_ENTER("wsrep_commit"); + + if (thd->wsrep_exec_mode == REPL_RECV) + { + DBUG_RETURN(0); + } + + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + if ((all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) && + (thd->variables.wsrep_on && thd->wsrep_conflict_state != MUST_REPLAY)) + { + if (thd->wsrep_exec_mode == LOCAL_COMMIT) + { + DBUG_ASSERT(thd->ha_data[wsrep_hton->slot].ha_info[all].is_trx_read_write()); + /* + Call to wsrep->post_commit() (moved to wsrep_post_commit()) must + be done only after commit has done for all involved htons. + */ + DBUG_PRINT("wsrep", ("commit")); + } + else + { + /* + Transaction didn't go through wsrep->pre_commit() so just roll back + possible changes to clean state. + */ + if (WSREP_PROVIDER_EXISTS) { + if (wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle)) + { + DBUG_PRINT("wsrep", ("setting rollback fail")); + WSREP_ERROR("settting rollback fail: thd: %llu SQL: %s", + (long long)thd->real_id, thd->query()); + } + } + wsrep_cleanup_transaction(thd); + } + } + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + DBUG_RETURN(0); +} + + +extern Rpl_filter* binlog_filter; +extern my_bool opt_log_slave_updates; + +enum wsrep_trx_status +wsrep_run_wsrep_commit(THD *thd, handlerton *hton, bool all) +{ + int rcode= -1; + size_t data_len= 0; + IO_CACHE *cache; + int replay_round= 0; + + if (thd->get_stmt_da()->is_error()) { + WSREP_ERROR("commit issue, error: %d %s", + thd->get_stmt_da()->sql_errno(), thd->get_stmt_da()->message()); + } + + DBUG_ENTER("wsrep_run_wsrep_commit"); + + if (thd->slave_thread && !opt_log_slave_updates) DBUG_RETURN(WSREP_TRX_OK); + + if (thd->wsrep_exec_mode == REPL_RECV) { + + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + if (thd->wsrep_conflict_state == MUST_ABORT) { + if (wsrep_debug) + WSREP_INFO("WSREP: must abort for BF"); + DBUG_PRINT("wsrep", ("BF apply commit fail")); + thd->wsrep_conflict_state = NO_CONFLICT; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + // + // TODO: test all calls of the rollback. + // rollback must happen automagically innobase_rollback(hton, thd, 1); + // + DBUG_RETURN(WSREP_TRX_ERROR); + } + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } + + if (thd->wsrep_exec_mode != LOCAL_STATE) DBUG_RETURN(WSREP_TRX_OK); + + if (thd->wsrep_consistency_check == CONSISTENCY_CHECK_RUNNING) { + WSREP_DEBUG("commit for consistency check: %s", thd->query()); + DBUG_RETURN(WSREP_TRX_OK); + } + + DBUG_PRINT("wsrep", ("replicating commit")); + + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + if (thd->wsrep_conflict_state == MUST_ABORT) { + DBUG_PRINT("wsrep", ("replicate commit fail")); + thd->wsrep_conflict_state = ABORTED; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + if (wsrep_debug) { + WSREP_INFO("innobase_commit, abort %s", + (thd->query()) ? thd->query() : "void"); + } + DBUG_RETURN(WSREP_TRX_CERT_FAIL); + } + + mysql_mutex_lock(&LOCK_wsrep_replaying); + + while (wsrep_replaying > 0 && + thd->wsrep_conflict_state == NO_CONFLICT && + thd->killed == NOT_KILLED && + !shutdown_in_progress) + { + + mysql_mutex_unlock(&LOCK_wsrep_replaying); + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + + mysql_mutex_lock(&thd->mysys_var->mutex); + thd_proc_info(thd, "wsrep waiting on replaying"); + thd->mysys_var->current_mutex= &LOCK_wsrep_replaying; + thd->mysys_var->current_cond= &COND_wsrep_replaying; + mysql_mutex_unlock(&thd->mysys_var->mutex); + + mysql_mutex_lock(&LOCK_wsrep_replaying); + // Using timedwait is a hack to avoid deadlock in case if BF victim + // misses the signal. + struct timespec wtime = {0, 1000000}; + mysql_cond_timedwait(&COND_wsrep_replaying, &LOCK_wsrep_replaying, + &wtime); + + if (replay_round++ % 100000 == 0) + WSREP_DEBUG("commit waiting for replaying: replayers %d, thd: (%lu) " + "conflict: %d (round: %d)", + wsrep_replaying, thd->thread_id, + thd->wsrep_conflict_state, replay_round); + + mysql_mutex_unlock(&LOCK_wsrep_replaying); + + mysql_mutex_lock(&thd->mysys_var->mutex); + thd->mysys_var->current_mutex= 0; + thd->mysys_var->current_cond= 0; + mysql_mutex_unlock(&thd->mysys_var->mutex); + + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + mysql_mutex_lock(&LOCK_wsrep_replaying); + } + mysql_mutex_unlock(&LOCK_wsrep_replaying); + + if (thd->wsrep_conflict_state == MUST_ABORT) { + DBUG_PRINT("wsrep", ("replicate commit fail")); + thd->wsrep_conflict_state = ABORTED; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + WSREP_DEBUG("innobase_commit abort after replaying wait %s", + (thd->query()) ? thd->query() : "void"); + DBUG_RETURN(WSREP_TRX_CERT_FAIL); + } + + thd->wsrep_query_state = QUERY_COMMITTING; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + + cache = get_trans_log(thd); + rcode = 0; + if (cache) { + thd->binlog_flush_pending_rows_event(true); + rcode = wsrep_write_cache(wsrep, thd, cache, &data_len); + if (WSREP_OK != rcode) { + WSREP_ERROR("rbr write fail, data_len: %zu, %d", data_len, rcode); + DBUG_RETURN(WSREP_TRX_SIZE_EXCEEDED); + } + } + + if (data_len == 0) + { + if (thd->get_stmt_da()->is_ok() && + thd->get_stmt_da()->affected_rows() > 0 && + !binlog_filter->is_on()) + { + WSREP_DEBUG("empty rbr buffer, query: %s, " + "affected rows: %llu, " + "changed tables: %d, " + "sql_log_bin: %d, " + "wsrep status (%d %d %d)", + thd->query(), thd->get_stmt_da()->affected_rows(), + stmt_has_updated_trans_table(thd), thd->variables.sql_log_bin, + thd->wsrep_exec_mode, thd->wsrep_query_state, + thd->wsrep_conflict_state); + } + else + { + WSREP_DEBUG("empty rbr buffer, query: %s", thd->query()); + } + thd->wsrep_query_state= QUERY_EXEC; + DBUG_RETURN(WSREP_TRX_OK); + } + + if (WSREP_UNDEFINED_TRX_ID == thd->wsrep_ws_handle.trx_id) + { + WSREP_WARN("SQL statement was ineffective, THD: %lu, buf: %zu\n" + "QUERY: %s\n" + " => Skipping replication", + thd->thread_id, data_len, thd->query()); + rcode = WSREP_TRX_FAIL; + } + else if (!rcode) + { + if (WSREP_OK == rcode) + rcode = wsrep->pre_commit(wsrep, + (wsrep_conn_id_t)thd->thread_id, + &thd->wsrep_ws_handle, + WSREP_FLAG_COMMIT | + ((thd->wsrep_PA_safe) ? + 0ULL : WSREP_FLAG_PA_UNSAFE), + &thd->wsrep_trx_meta); + + if (rcode == WSREP_TRX_MISSING) { + WSREP_WARN("Transaction missing in provider, thd: %ld, SQL: %s", + thd->thread_id, thd->query()); + rcode = WSREP_TRX_FAIL; + } else if (rcode == WSREP_BF_ABORT) { + WSREP_DEBUG("thd %lu seqno %lld BF aborted by provider, will replay", + thd->thread_id, (long long)thd->wsrep_trx_meta.gtid.seqno); + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + thd->wsrep_conflict_state = MUST_REPLAY; + DBUG_ASSERT(wsrep_thd_trx_seqno(thd) > 0); + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + mysql_mutex_lock(&LOCK_wsrep_replaying); + wsrep_replaying++; + WSREP_DEBUG("replaying increased: %d, thd: %lu", + wsrep_replaying, thd->thread_id); + mysql_mutex_unlock(&LOCK_wsrep_replaying); + } + } else { + WSREP_ERROR("I/O error reading from thd's binlog iocache: " + "errno=%d, io cache code=%d", my_errno, cache->error); + DBUG_ASSERT(0); // failure like this can not normally happen + DBUG_RETURN(WSREP_TRX_ERROR); + } + + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + switch(rcode) { + case 0: + /* + About MUST_ABORT: We assume that even if thd conflict state was set + to MUST_ABORT, underlying transaction was not rolled back or marked + as deadlock victim in QUERY_COMMITTING state. Conflict state is + set to NO_CONFLICT and commit proceeds as usual. + */ + if (thd->wsrep_conflict_state == MUST_ABORT) + thd->wsrep_conflict_state= NO_CONFLICT; + + if (thd->wsrep_conflict_state != NO_CONFLICT) + { + WSREP_WARN("thd %lu seqno %lld: conflict state %d after post commit", + thd->thread_id, + (long long)thd->wsrep_trx_meta.gtid.seqno, + thd->wsrep_conflict_state); + } + thd->wsrep_exec_mode= LOCAL_COMMIT; + DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno != WSREP_SEQNO_UNDEFINED); + /* Override XID iff it was generated by mysql */ + if (thd->transaction.xid_state.xid.get_my_xid()) + { + wsrep_xid_init(&thd->transaction.xid_state.xid, + &thd->wsrep_trx_meta.gtid.uuid, + thd->wsrep_trx_meta.gtid.seqno); + } + DBUG_PRINT("wsrep", ("replicating commit success")); + break; + case WSREP_BF_ABORT: + DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno != WSREP_SEQNO_UNDEFINED); + case WSREP_TRX_FAIL: + WSREP_DEBUG("commit failed for reason: %d", rcode); + DBUG_PRINT("wsrep", ("replicating commit fail")); + + thd->wsrep_query_state= QUERY_EXEC; + + if (thd->wsrep_conflict_state == MUST_ABORT) { + thd->wsrep_conflict_state= ABORTED; + } + else + { + WSREP_DEBUG("conflict state: %d", thd->wsrep_conflict_state); + if (thd->wsrep_conflict_state == NO_CONFLICT) + { + thd->wsrep_conflict_state = CERT_FAILURE; + WSREP_LOG_CONFLICT(NULL, thd, FALSE); + } + } + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + + DBUG_RETURN(WSREP_TRX_CERT_FAIL); + + case WSREP_SIZE_EXCEEDED: + WSREP_ERROR("transaction size exceeded"); + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + DBUG_RETURN(WSREP_TRX_SIZE_EXCEEDED); + case WSREP_CONN_FAIL: + WSREP_ERROR("connection failure"); + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + DBUG_RETURN(WSREP_TRX_ERROR); + default: + WSREP_ERROR("unknown connection failure"); + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + DBUG_RETURN(WSREP_TRX_ERROR); + } + + thd->wsrep_query_state= QUERY_EXEC; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + + DBUG_RETURN(WSREP_TRX_OK); +} + + +static int wsrep_hton_init(void *p) +{ + wsrep_hton= (handlerton *)p; + //wsrep_hton->state=opt_bin_log ? SHOW_OPTION_YES : SHOW_OPTION_NO; + wsrep_hton->state= SHOW_OPTION_YES; + wsrep_hton->db_type=(legacy_db_type)0; + wsrep_hton->savepoint_offset= sizeof(my_off_t); + wsrep_hton->close_connection= wsrep_close_connection; + wsrep_hton->savepoint_set= wsrep_savepoint_set; + wsrep_hton->savepoint_rollback= wsrep_savepoint_rollback; + wsrep_hton->commit= wsrep_commit; + wsrep_hton->rollback= wsrep_rollback; + wsrep_hton->prepare= wsrep_prepare; + wsrep_hton->flags= HTON_NOT_USER_SELECTABLE | HTON_HIDDEN; // todo: fix flags + wsrep_hton->slot= 0; + return 0; +} + + +struct st_mysql_storage_engine wsrep_storage_engine= +{ MYSQL_HANDLERTON_INTERFACE_VERSION }; + + +mysql_declare_plugin(wsrep) +{ + MYSQL_STORAGE_ENGINE_PLUGIN, + &wsrep_storage_engine, + "wsrep", + "Codership Oy", + "A pseudo storage engine to represent transactions in multi-master " + "synchornous replication", + PLUGIN_LICENSE_GPL, + wsrep_hton_init, /* Plugin Init */ + NULL, /* Plugin Deinit */ + 0x0100 /* 1.0 */, + NULL, /* status variables */ + NULL, /* system variables */ + NULL, /* config options */ + 0, /* flags */ +} +mysql_declare_plugin_end; diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc new file mode 100644 index 00000000000..c1b15bd02c2 --- /dev/null +++ b/sql/wsrep_mysqld.cc @@ -0,0 +1,2433 @@ +/* Copyright 2008-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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include +#include +#include +#include "slave.h" +#include "rpl_mi.h" +#include "sql_repl.h" +#include "rpl_filter.h" +#include "sql_callback.h" +#include "sp_head.h" +#include "sp.h" +#include "wsrep_priv.h" +#include "wsrep_thd.h" +#include "wsrep_sst.h" +#include "wsrep_utils.h" +#include "wsrep_var.h" +#include "wsrep_binlog.h" +#include "wsrep_applier.h" +#include +#include +#include "log_event.h" +#include + +wsrep_t *wsrep = NULL; +my_bool wsrep_emulate_bin_log = FALSE; // activating parts of binlog interface +#ifdef GTID_SUPPORT +/* Sidno in global_sid_map corresponding to group uuid */ +rpl_sidno wsrep_sidno= -1; +#endif /* GTID_SUPPORT */ +my_bool wsrep_preordered_opt= FALSE; + +/* + * Begin configuration options and their default values + */ + +extern int wsrep_replaying; +extern ulong wsrep_running_threads; +extern ulong my_bind_addr; +extern my_bool plugins_are_initialized; +extern uint kill_cached_threads; +extern mysql_cond_t COND_thread_cache; + +const char* wsrep_data_home_dir = NULL; +const char* wsrep_dbug_option = ""; + +long wsrep_slave_threads = 1; // # of slave action appliers wanted +int wsrep_slave_count_change = 0; // # of appliers to stop or start +my_bool wsrep_debug = 0; // enable debug level logging +my_bool wsrep_convert_LOCK_to_trx = 1; // convert locking sessions to trx +ulong wsrep_retry_autocommit = 5; // retry aborted autocommit trx +my_bool wsrep_auto_increment_control = 1; // control auto increment variables +my_bool wsrep_drupal_282555_workaround = 1; // retry autoinc insert after dupkey +my_bool wsrep_incremental_data_collection = 0; // incremental data collection +ulong wsrep_max_ws_size = 1073741824UL;//max ws (RBR buffer) size +ulong wsrep_max_ws_rows = 65536; // max number of rows in ws +int wsrep_to_isolation = 0; // # of active TO isolation threads +my_bool wsrep_certify_nonPK = 1; // certify, even when no primary key +long wsrep_max_protocol_version = 3; // maximum protocol version to use +ulong wsrep_forced_binlog_format = BINLOG_FORMAT_UNSPEC; +my_bool wsrep_recovery = 0; // recovery +my_bool wsrep_replicate_myisam = 0; // enable myisam replication +my_bool wsrep_log_conflicts = 0; +ulong wsrep_mysql_replication_bundle = 0; +my_bool wsrep_desync = 0; // desynchronize the node from the + // cluster +my_bool wsrep_load_data_splitting = 1; // commit load data every 10K intervals +my_bool wsrep_restart_slave = 0; // should mysql slave thread be + // restarted, if node joins back +my_bool wsrep_restart_slave_activated = 0; // node has dropped, and slave + // restart will be needed +my_bool wsrep_slave_UK_checks = 0; // slave thread does UK checks +my_bool wsrep_slave_FK_checks = 0; // slave thread does FK checks +/* + * End configuration options + */ + +/* + * Other wsrep global variables. + */ +my_bool wsrep_inited = 0; // initialized ? + +static const wsrep_uuid_t cluster_uuid = WSREP_UUID_UNDEFINED; +static char cluster_uuid_str[40]= { 0, }; +static const char* cluster_status_str[WSREP_VIEW_MAX] = +{ + "Primary", + "non-Primary", + "Disconnected" +}; + +static char provider_name[256]= { 0, }; +static char provider_version[256]= { 0, }; +static char provider_vendor[256]= { 0, }; + +/* + * wsrep status variables + */ +my_bool wsrep_connected = FALSE; +my_bool wsrep_ready = FALSE; // node can accept queries +const char* wsrep_cluster_state_uuid = cluster_uuid_str; +long long wsrep_cluster_conf_id = WSREP_SEQNO_UNDEFINED; +const char* wsrep_cluster_status = cluster_status_str[WSREP_VIEW_DISCONNECTED]; +long wsrep_cluster_size = 0; +long wsrep_local_index = -1; +long long wsrep_local_bf_aborts = 0; +const char* wsrep_provider_name = provider_name; +const char* wsrep_provider_version = provider_version; +const char* wsrep_provider_vendor = provider_vendor; +/* End wsrep status variables */ + +wsrep_uuid_t local_uuid = WSREP_UUID_UNDEFINED; +wsrep_seqno_t local_seqno = WSREP_SEQNO_UNDEFINED; +wsp::node_status local_status; +long wsrep_protocol_version = 3; + +// Boolean denoting if server is in initial startup phase. This is needed +// to make sure that main thread waiting in wsrep_sst_wait() is signaled +// if there was no state gap on receiving first view event. +static my_bool wsrep_startup = TRUE; + + +static void wsrep_log_cb(wsrep_log_level_t level, const char *msg) { + switch (level) { + case WSREP_LOG_INFO: + sql_print_information("WSREP: %s", msg); + break; + case WSREP_LOG_WARN: + sql_print_warning("WSREP: %s", msg); + break; + case WSREP_LOG_ERROR: + case WSREP_LOG_FATAL: + sql_print_error("WSREP: %s", msg); + break; + case WSREP_LOG_DEBUG: + if (wsrep_debug) sql_print_information ("[Debug] WSREP: %s", msg); + default: + break; + } +} + +static void wsrep_log_states (wsrep_log_level_t const level, + const wsrep_uuid_t* const group_uuid, + wsrep_seqno_t const group_seqno, + const wsrep_uuid_t* const node_uuid, + wsrep_seqno_t const node_seqno) +{ + char uuid_str[37]; + char msg[256]; + + wsrep_uuid_print (group_uuid, uuid_str, sizeof(uuid_str)); + snprintf (msg, 255, "WSREP: Group state: %s:%lld", + uuid_str, (long long)group_seqno); + wsrep_log_cb (level, msg); + + wsrep_uuid_print (node_uuid, uuid_str, sizeof(uuid_str)); + snprintf (msg, 255, "WSREP: Local state: %s:%lld", + uuid_str, (long long)node_seqno); + wsrep_log_cb (level, msg); +} + +static my_bool set_SE_checkpoint(THD* unused, plugin_ref plugin, void* arg) +{ + XID* xid= reinterpret_cast(arg); + handlerton* hton= plugin_data(plugin, handlerton *); + if (hton->set_checkpoint) + { + const wsrep_uuid_t* uuid(wsrep_xid_uuid(xid)); + char uuid_str[40] = {0, }; + wsrep_uuid_print(uuid, uuid_str, sizeof(uuid_str)); + WSREP_DEBUG("Set WSREPXid for InnoDB: %s:%lld", + uuid_str, (long long)wsrep_xid_seqno(xid)); + hton->set_checkpoint(hton, xid); + } + return FALSE; +} + +void wsrep_set_SE_checkpoint(XID* xid) +{ + plugin_foreach(NULL, set_SE_checkpoint, MYSQL_STORAGE_ENGINE_PLUGIN, xid); +} + +static my_bool get_SE_checkpoint(THD* unused, plugin_ref plugin, void* arg) +{ + XID* xid= reinterpret_cast(arg); + handlerton* hton= plugin_data(plugin, handlerton *); + if (hton->get_checkpoint) + { + hton->get_checkpoint(hton, xid); + const wsrep_uuid_t* uuid(wsrep_xid_uuid(xid)); + char uuid_str[40] = {0, }; + wsrep_uuid_print(uuid, uuid_str, sizeof(uuid_str)); + WSREP_DEBUG("Read WSREPXid from InnoDB: %s:%lld", + uuid_str, (long long)wsrep_xid_seqno(xid)); + } + return FALSE; +} + +void wsrep_get_SE_checkpoint(XID* xid) +{ + plugin_foreach(NULL, get_SE_checkpoint, MYSQL_STORAGE_ENGINE_PLUGIN, xid); +} + +#ifdef GTID_SUPPORT +void wsrep_init_sidno(const wsrep_uuid_t& uuid) +{ + /* generate new Sid map entry from inverted uuid */ + rpl_sid sid; + wsrep_uuid_t ltid_uuid; + for (size_t i= 0; i < sizeof(ltid_uuid.data); ++i) + { + ltid_uuid.data[i] = ~local_uuid.data[i]; + } + sid.copy_from(ltid_uuid.data); + global_sid_lock->wrlock(); + wsrep_sidno= global_sid_map->add_sid(sid); + WSREP_INFO("inited wsrep sidno %d", wsrep_sidno); + global_sid_lock->unlock(); +} +#endif /* GTID_SUPPORT */ + +static wsrep_cb_status_t +wsrep_view_handler_cb (void* app_ctx, + void* recv_ctx, + const wsrep_view_info_t* view, + const char* state, + size_t state_len, + void** sst_req, + size_t* sst_req_len) +{ + *sst_req = NULL; + *sst_req_len = 0; + + wsrep_member_status_t new_status= local_status.get(); + + if (memcmp(&cluster_uuid, &view->state_id.uuid, sizeof(wsrep_uuid_t))) + { + memcpy((wsrep_uuid_t*)&cluster_uuid, &view->state_id.uuid, + sizeof(cluster_uuid)); + + wsrep_uuid_print (&cluster_uuid, cluster_uuid_str, + sizeof(cluster_uuid_str)); + } + + wsrep_cluster_conf_id= view->view; + wsrep_cluster_status= cluster_status_str[view->status]; + wsrep_cluster_size= view->memb_num; + wsrep_local_index= view->my_idx; + + WSREP_INFO("New cluster view: global state: %s:%lld, view# %lld: %s, " + "number of nodes: %ld, my index: %ld, protocol version %d", + wsrep_cluster_state_uuid, (long long)view->state_id.seqno, + (long long)wsrep_cluster_conf_id, wsrep_cluster_status, + wsrep_cluster_size, wsrep_local_index, view->proto_ver); + + /* Proceed further only if view is PRIMARY */ + if (WSREP_VIEW_PRIMARY != view->status) { + wsrep_ready_set(FALSE); + new_status= WSREP_MEMBER_UNDEFINED; + /* Always record local_uuid and local_seqno in non-prim since this + * may lead to re-initializing provider and start position is + * determined according to these variables */ + // WRONG! local_uuid should be the last primary configuration uuid we were + // a member of. local_seqno should be updated in commit calls. + // local_uuid= cluster_uuid; + // local_seqno= view->first - 1; + goto out; + } + + switch (view->proto_ver) + { + case 0: + case 1: + case 2: + case 3: + // version change + if (view->proto_ver != wsrep_protocol_version) + { + my_bool wsrep_ready_saved= wsrep_ready; + wsrep_ready_set(FALSE); + WSREP_INFO("closing client connections for " + "protocol change %ld -> %d", + wsrep_protocol_version, view->proto_ver); + wsrep_close_client_connections(TRUE); + wsrep_protocol_version= view->proto_ver; + wsrep_ready_set(wsrep_ready_saved); + } + break; + default: + WSREP_ERROR("Unsupported application protocol version: %d", + view->proto_ver); + unireg_abort(1); + } + + if (view->state_gap) + { + WSREP_WARN("Gap in state sequence. Need state transfer."); + + /* After that wsrep will call wsrep_sst_prepare. */ + /* keep ready flag 0 until we receive the snapshot */ + wsrep_ready_set(FALSE); + + /* Close client connections to ensure that they don't interfere + * with SST */ + WSREP_DEBUG("[debug]: closing client connections for PRIM"); + wsrep_close_client_connections(TRUE); + + ssize_t const req_len= wsrep_sst_prepare (sst_req); + + if (req_len < 0) + { + WSREP_ERROR("SST preparation failed: %zd (%s)", -req_len, + strerror(-req_len)); + new_status= WSREP_MEMBER_UNDEFINED; + } + else + { + assert(sst_req != NULL); + *sst_req_len= req_len; + new_status= WSREP_MEMBER_JOINER; + } + } + else + { + /* + * NOTE: Initialize wsrep_group_uuid here only if it wasn't initialized + * before - OR - it was reinitilized on startup (lp:992840) + */ + if (wsrep_startup) + { + if (wsrep_before_SE()) + { + wsrep_SE_init_grab(); + // Signal mysqld init thread to continue + wsrep_sst_complete (&cluster_uuid, view->state_id.seqno, false); + // and wait for SE initialization + wsrep_SE_init_wait(); + } + else + { + local_uuid= cluster_uuid; + local_seqno= view->state_id.seqno; + } + /* Init storage engine XIDs from first view */ + XID xid; + wsrep_xid_init(&xid, &local_uuid, local_seqno); + wsrep_set_SE_checkpoint(&xid); + new_status= WSREP_MEMBER_JOINED; +#ifdef GTID_SUPPORT + wsrep_init_sidno(local_uuid); +#endif /* GTID_SUPPORT */ + } + + // just some sanity check + if (memcmp (&local_uuid, &cluster_uuid, sizeof (wsrep_uuid_t))) + { + WSREP_ERROR("Undetected state gap. Can't continue."); + wsrep_log_states(WSREP_LOG_FATAL, &cluster_uuid, view->state_id.seqno, + &local_uuid, -1); + unireg_abort(1); + } + } + + if (wsrep_auto_increment_control) + { + global_system_variables.auto_increment_offset= view->my_idx + 1; + global_system_variables.auto_increment_increment= view->memb_num; + } + + { /* capabilities may be updated on new configuration */ + uint64_t const caps(wsrep->capabilities (wsrep)); + + my_bool const idc((caps & WSREP_CAP_INCREMENTAL_WRITESET) != 0); + if (TRUE == wsrep_incremental_data_collection && FALSE == idc) + { + WSREP_WARN("Unsupported protocol downgrade: " + "incremental data collection disabled. Expect abort."); + } + wsrep_incremental_data_collection = idc; + } + +out: + if (view->status == WSREP_VIEW_PRIMARY) wsrep_startup= FALSE; + local_status.set(new_status, view); + + return WSREP_CB_SUCCESS; +} + +void wsrep_ready_set (my_bool x) +{ + WSREP_DEBUG("Setting wsrep_ready to %d", x); + if (mysql_mutex_lock (&LOCK_wsrep_ready)) abort(); + if (wsrep_ready != x) + { + wsrep_ready= x; + mysql_cond_signal (&COND_wsrep_ready); + } + mysql_mutex_unlock (&LOCK_wsrep_ready); +} + +// Wait until wsrep has reached ready state +void wsrep_ready_wait () +{ + if (mysql_mutex_lock (&LOCK_wsrep_ready)) abort(); + while (!wsrep_ready) + { + WSREP_INFO("Waiting to reach ready state"); + mysql_cond_wait (&COND_wsrep_ready, &LOCK_wsrep_ready); + } + WSREP_INFO("ready state reached"); + mysql_mutex_unlock (&LOCK_wsrep_ready); +} + +static void wsrep_synced_cb(void* app_ctx) +{ + WSREP_INFO("Synchronized with group, ready for connections"); + bool signal_main= false; + if (mysql_mutex_lock (&LOCK_wsrep_ready)) abort(); + if (!wsrep_ready) + { + wsrep_ready= TRUE; + mysql_cond_signal (&COND_wsrep_ready); + signal_main= true; + + } + local_status.set(WSREP_MEMBER_SYNCED); + mysql_mutex_unlock (&LOCK_wsrep_ready); + + if (signal_main) + { + wsrep_SE_init_grab(); + // Signal mysqld init thread to continue + wsrep_sst_complete (&local_uuid, local_seqno, false); + // and wait for SE initialization + wsrep_SE_init_wait(); + } + if (wsrep_restart_slave_activated) + { + int rcode; + WSREP_INFO("MySQL slave restart"); + wsrep_restart_slave_activated= FALSE; + + mysql_mutex_lock(&LOCK_active_mi); + if ((rcode = start_slave_threads(1 /* need mutex */, + 0 /* no wait for start*/, + active_mi, + master_info_file, + relay_log_info_file, + SLAVE_SQL))) + { + WSREP_WARN("Failed to create slave threads: %d", rcode); + } + mysql_mutex_unlock(&LOCK_active_mi); + + } +} + +static void wsrep_init_position() +{ + /* read XIDs from storage engines */ + XID xid; + memset(&xid, 0, sizeof(xid)); + xid.formatID= -1; + wsrep_get_SE_checkpoint(&xid); + + if (xid.formatID == -1) + { + WSREP_INFO("Read nil XID from storage engines, skipping position init"); + return; + } + else if (!wsrep_is_wsrep_xid(&xid)) + { + WSREP_WARN("Read non-wsrep XID from storage engines, skipping position init"); + return; + } + + const wsrep_uuid_t* uuid= wsrep_xid_uuid(&xid); + const wsrep_seqno_t seqno= wsrep_xid_seqno(&xid); + + char uuid_str[40] = {0, }; + wsrep_uuid_print(uuid, uuid_str, sizeof(uuid_str)); + WSREP_INFO("Initial position: %s:%lld", uuid_str, (long long)seqno); + + + if (!memcmp(&local_uuid, &WSREP_UUID_UNDEFINED, sizeof(local_uuid)) && + local_seqno == WSREP_SEQNO_UNDEFINED) + { + // Initial state + local_uuid= *uuid; + local_seqno= seqno; + } + else if (memcmp(&local_uuid, uuid, sizeof(local_uuid)) || + local_seqno != seqno) + { + WSREP_WARN("Initial position was provided by configuration or SST, " + "avoiding override"); + } +} + +extern char* my_bind_addr_str; + +int wsrep_init() +{ + int rcode= -1; + DBUG_ASSERT(wsrep_inited == 0); + + wsrep_ready_set(FALSE); + assert(wsrep_provider); + + wsrep_init_position(); + + if ((rcode= wsrep_load(wsrep_provider, &wsrep, wsrep_log_cb)) != WSREP_OK) + { + if (strcasecmp(wsrep_provider, WSREP_NONE)) + { + WSREP_ERROR("wsrep_load(%s) failed: %s (%d). Reverting to no provider.", + wsrep_provider, strerror(rcode), rcode); + strcpy((char*)wsrep_provider, WSREP_NONE); // damn it's a dirty hack + (void) wsrep_init(); + return rcode; + } + else /* this is for recursive call above */ + { + WSREP_ERROR("Could not revert to no provider: %s (%d). Need to abort.", + strerror(rcode), rcode); + unireg_abort(1); + } + } + + if (!WSREP_PROVIDER_EXISTS) + { + // enable normal operation in case no provider is specified + wsrep_ready_set(TRUE); + wsrep_inited= 1; + global_system_variables.wsrep_on = 0; + wsrep_init_args args; + args.logger_cb = wsrep_log_cb; + args.options = (wsrep_provider_options) ? + wsrep_provider_options : ""; + rcode = wsrep->init(wsrep, &args); + if (rcode) + { + DBUG_PRINT("wsrep",("wsrep::init() failed: %d", rcode)); + WSREP_ERROR("wsrep::init() failed: %d, must shutdown", rcode); + wsrep->free(wsrep); + free(wsrep); + wsrep = NULL; + } + return rcode; + } + else + { + global_system_variables.wsrep_on = 1; + strncpy(provider_name, + wsrep->provider_name, sizeof(provider_name) - 1); + strncpy(provider_version, + wsrep->provider_version, sizeof(provider_version) - 1); + strncpy(provider_vendor, + wsrep->provider_vendor, sizeof(provider_vendor) - 1); + } + + if (!wsrep_data_home_dir || strlen(wsrep_data_home_dir) == 0) + wsrep_data_home_dir = mysql_real_data_home; + + char node_addr[512]= { 0, }; + size_t const node_addr_max= sizeof(node_addr) - 1; + if (!wsrep_node_address || !strcmp(wsrep_node_address, "")) + { + size_t const ret= wsrep_guess_ip(node_addr, node_addr_max); + if (!(ret > 0 && ret < node_addr_max)) + { + WSREP_WARN("Failed to guess base node address. Set it explicitly via " + "wsrep_node_address."); + node_addr[0]= '\0'; + } + } + else + { + strncpy(node_addr, wsrep_node_address, node_addr_max); + } + + char inc_addr[512]= { 0, }; + size_t const inc_addr_max= sizeof (inc_addr); + if ((!wsrep_node_incoming_address || + !strcmp (wsrep_node_incoming_address, WSREP_NODE_INCOMING_AUTO))) + { + unsigned int my_bind_ip= INADDR_ANY; // default if not set + if (my_bind_addr_str && strlen(my_bind_addr_str)) + { + my_bind_ip= wsrep_check_ip(my_bind_addr_str); + } + + if (INADDR_ANY != my_bind_ip) + { + if (INADDR_NONE != my_bind_ip && INADDR_LOOPBACK != my_bind_ip) + { + snprintf(inc_addr, inc_addr_max, "%s:%u", + my_bind_addr_str, (int)mysqld_port); + } // else leave inc_addr an empty string - mysqld is not listening for + // client connections on network interfaces. + } + else // mysqld binds to 0.0.0.0, take IP from wsrep_node_address if possible + { + size_t const node_addr_len= strlen(node_addr); + if (node_addr_len > 0) + { + const char* const colon= strrchr(node_addr, ':'); + if (strchr(node_addr, ':') == colon) // 1 or 0 ':' + { + size_t const ip_len= colon ? colon - node_addr : node_addr_len; + if (ip_len + 7 /* :55555\0 */ < inc_addr_max) + { + memcpy (inc_addr, node_addr, ip_len); + snprintf(inc_addr + ip_len, inc_addr_max - ip_len, ":%u", + (int)mysqld_port); + } + else + { + WSREP_WARN("Guessing address for incoming client connections: " + "address too long."); + inc_addr[0]= '\0'; + } + } + else + { + WSREP_WARN("Guessing address for incoming client connections: " + "too many colons :) ."); + inc_addr[0]= '\0'; + } + } + + if (!strlen(inc_addr)) + { + WSREP_WARN("Guessing address for incoming client connections failed. " + "Try setting wsrep_node_incoming_address explicitly."); + } + } + } + else if (!strchr(wsrep_node_incoming_address, ':')) // no port included + { + if ((int)inc_addr_max <= + snprintf(inc_addr, inc_addr_max, "%s:%u", + wsrep_node_incoming_address,(int)mysqld_port)) + { + WSREP_WARN("Guessing address for incoming client connections: " + "address too long."); + inc_addr[0]= '\0'; + } + } + else + { + size_t const need = strlen (wsrep_node_incoming_address); + if (need >= inc_addr_max) { + WSREP_WARN("wsrep_node_incoming_address too long: %zu", need); + inc_addr[0]= '\0'; + } + else { + memcpy (inc_addr, wsrep_node_incoming_address, need); + } + } + + struct wsrep_init_args wsrep_args; + + struct wsrep_gtid const state_id = { local_uuid, local_seqno }; + + wsrep_args.data_dir = wsrep_data_home_dir; + wsrep_args.node_name = (wsrep_node_name) ? wsrep_node_name : ""; + wsrep_args.node_address = node_addr; + wsrep_args.node_incoming = inc_addr; + wsrep_args.options = (wsrep_provider_options) ? + wsrep_provider_options : ""; + wsrep_args.proto_ver = wsrep_max_protocol_version; + + wsrep_args.state_id = &state_id; + + wsrep_args.logger_cb = wsrep_log_cb; + wsrep_args.view_handler_cb = wsrep_view_handler_cb; + wsrep_args.apply_cb = wsrep_apply_cb; + wsrep_args.commit_cb = wsrep_commit_cb; + wsrep_args.unordered_cb = wsrep_unordered_cb; + wsrep_args.sst_donate_cb = wsrep_sst_donate_cb; + wsrep_args.synced_cb = wsrep_synced_cb; + + rcode = wsrep->init(wsrep, &wsrep_args); + + if (rcode) + { + DBUG_PRINT("wsrep",("wsrep::init() failed: %d", rcode)); + WSREP_ERROR("wsrep::init() failed: %d, must shutdown", rcode); + wsrep->free(wsrep); + free(wsrep); + wsrep = NULL; + } else { + wsrep_inited= 1; + } + + return rcode; +} + +extern int wsrep_on(void *); + +void wsrep_init_startup (bool first) +{ + if (wsrep_init()) unireg_abort(1); + + wsrep_thr_lock_init(wsrep_thd_is_BF, wsrep_abort_thd, + wsrep_debug, wsrep_convert_LOCK_to_trx, wsrep_on); + + /* Skip replication start if no cluster address */ + if (!wsrep_cluster_address || strlen(wsrep_cluster_address) == 0) return; + + if (first) wsrep_sst_grab(); // do it so we can wait for SST below + + if (!wsrep_start_replication()) unireg_abort(1); + + wsrep_create_rollbacker(); + wsrep_create_appliers(1); + + if (first && !wsrep_sst_wait()) unireg_abort(1);// wait until SST is completed +} + + +void wsrep_deinit(bool free_options) +{ + DBUG_ASSERT(wsrep_inited == 1); + wsrep_unload(wsrep); + wsrep= 0; + provider_name[0]= '\0'; + provider_version[0]= '\0'; + provider_vendor[0]= '\0'; + wsrep_inited= 0; + + if (free_options) + { + wsrep_sst_auth_free(); + } +} + +void wsrep_recover() +{ + if (!memcmp(&local_uuid, &WSREP_UUID_UNDEFINED, sizeof(wsrep_uuid_t)) && + local_seqno == -2) + { + char uuid_str[40]; + wsrep_uuid_print(&local_uuid, uuid_str, sizeof(uuid_str)); + WSREP_INFO("Position %s:%lld given at startup, skipping position recovery", + uuid_str, (long long)local_seqno); + return; + } + XID xid; + memset(&xid, 0, sizeof(xid)); + xid.formatID= -1; + wsrep_get_SE_checkpoint(&xid); + char uuid_str[40]; + wsrep_uuid_print(wsrep_xid_uuid(&xid), uuid_str, sizeof(uuid_str)); + WSREP_INFO("Recovered position: %s:%lld", uuid_str, + (long long)wsrep_xid_seqno(&xid)); +} + + +void wsrep_stop_replication(THD *thd) +{ + WSREP_INFO("Stop replication"); + if (!wsrep) + { + WSREP_INFO("Provider was not loaded, in stop replication"); + return; + } + + /* disconnect from group first to get wsrep_ready == FALSE */ + WSREP_DEBUG("Provider disconnect"); + wsrep->disconnect(wsrep); + + wsrep_connected= FALSE; + + wsrep_close_client_connections(TRUE); + + /* wait until appliers have stopped */ + wsrep_wait_appliers_close(thd); + + return; +} + +/* This one is set to true when --wsrep-new-cluster is found in the command + * line arguments */ +static my_bool wsrep_new_cluster= FALSE; +#define WSREP_NEW_CLUSTER "--wsrep-new-cluster" +/* Finds and hides --wsrep-new-cluster from the arguments list + * by moving it to the end of the list and decrementing argument count */ +void wsrep_filter_new_cluster (int* argc, char* argv[]) +{ + int i; + for (i= *argc - 1; i > 0; i--) + { + /* make a copy of the argument to convert possible underscores to hyphens. + * the copy need not to be longer than WSREP_NEW_CLUSTER option */ + char arg[sizeof(WSREP_NEW_CLUSTER) + 1]= { 0, }; + strncpy(arg, argv[i], sizeof(arg) - 1); + char* underscore(arg); + while (NULL != (underscore= strchr(underscore, '_'))) *underscore= '-'; + + if (!strcmp(arg, WSREP_NEW_CLUSTER)) + { + wsrep_new_cluster= TRUE; + *argc -= 1; + /* preserve the order of remaining arguments AND + * preserve the original argument pointers - just in case */ + char* wnc= argv[i]; + memmove(&argv[i], &argv[i + 1], (*argc - i)*sizeof(argv[i])); + argv[*argc]= wnc; /* this will be invisible to the rest of the program */ + } + } +} + +bool wsrep_start_replication() +{ + wsrep_status_t rcode; + + /* + if provider is trivial, don't even try to connect, + but resume local node operation + */ + if (!WSREP_PROVIDER_EXISTS) + { + // enable normal operation in case no provider is specified + wsrep_ready_set(TRUE); + return true; + } + + if (!wsrep_cluster_address || strlen(wsrep_cluster_address)== 0) + { + // if provider is non-trivial, but no address is specified, wait for address + wsrep_ready_set(FALSE); + return true; + } + + bool const bootstrap(TRUE == wsrep_new_cluster); + wsrep_new_cluster= FALSE; + + WSREP_INFO("Start replication"); + + if ((rcode = wsrep->connect(wsrep, + wsrep_cluster_name, + wsrep_cluster_address, + wsrep_sst_donor, + bootstrap))) + { + if (-ESOCKTNOSUPPORT == rcode) + { + DBUG_PRINT("wsrep",("unrecognized cluster address: '%s', rcode: %d", + wsrep_cluster_address, rcode)); + WSREP_ERROR("unrecognized cluster address: '%s', rcode: %d", + wsrep_cluster_address, rcode); + } + else + { + DBUG_PRINT("wsrep",("wsrep->connect() failed: %d", rcode)); + WSREP_ERROR("wsrep::connect() failed: %d", rcode); + } + + return false; + } + else + { + wsrep_connected= TRUE; + + char* opts= wsrep->options_get(wsrep); + if (opts) + { + wsrep_provider_options_init(opts); + free(opts); + } + else + { + WSREP_WARN("Failed to get wsrep options"); + } + } + + return true; +} + +bool wsrep_sync_wait (THD* thd, uint mask) +{ + if ((thd->variables.wsrep_sync_wait & mask) && + thd->variables.wsrep_on && + !thd->in_active_multi_stmt_transaction() && + thd->wsrep_conflict_state != REPLAYING) + { + WSREP_DEBUG("wsrep_sync_wait: thd->variables.wsrep_sync_wait = %u, mask = %u", + thd->variables.wsrep_sync_wait, mask); + // This allows autocommit SELECTs and a first SELECT after SET AUTOCOMMIT=0 + // TODO: modify to check if thd has locked any rows. + wsrep_gtid_t gtid; + wsrep_status_t ret= wsrep->causal_read (wsrep, >id); + + if (unlikely(WSREP_OK != ret)) + { + const char* msg; + int err; + + // Possibly relevant error codes: + // ER_CHECKREAD, ER_ERROR_ON_READ, ER_INVALID_DEFAULT, ER_EMPTY_QUERY, + // ER_FUNCTION_NOT_DEFINED, ER_NOT_ALLOWED_COMMAND, ER_NOT_SUPPORTED_YET, + // ER_FEATURE_DISABLED, ER_QUERY_INTERRUPTED + + switch (ret) + { + case WSREP_NOT_IMPLEMENTED: + msg= "synchronous reads by wsrep backend. " + "Please unset wsrep_causal_reads variable."; + err= ER_NOT_SUPPORTED_YET; + break; + default: + msg= "Synchronous wait failed."; + err= ER_LOCK_WAIT_TIMEOUT; // NOTE: the above msg won't be displayed + // with ER_LOCK_WAIT_TIMEOUT + } + + my_error(err, MYF(0), msg); + + return true; + } + } + + return false; +} + +/* + * Helpers to deal with TOI key arrays + */ +typedef struct wsrep_key_arr +{ + wsrep_key_t* keys; + size_t keys_len; +} wsrep_key_arr_t; + + +static void wsrep_keys_free(wsrep_key_arr_t* key_arr) +{ + for (size_t i= 0; i < key_arr->keys_len; ++i) + { + my_free((void*)key_arr->keys[i].key_parts); + } + my_free(key_arr->keys); + key_arr->keys= 0; + key_arr->keys_len= 0; +} + + +/*! + * @param db Database string + * @param table Table string + * @param key Array of wsrep_key_t + * @param key_len In: number of elements in key array, Out: number of + * elements populated + * + * @return true if preparation was successful, otherwise false. + */ + +static bool wsrep_prepare_key_for_isolation(const char* db, + const char* table, + wsrep_buf_t* key, + size_t* key_len) +{ + if (*key_len < 2) return false; + + switch (wsrep_protocol_version) + { + case 0: + *key_len= 0; + break; + case 1: + case 2: + case 3: + { + *key_len= 0; + if (db) + { + // sql_print_information("%s.%s", db, table); + if (db) + { + key[*key_len].ptr= db; + key[*key_len].len= strlen(db); + ++(*key_len); + if (table) + { + key[*key_len].ptr= table; + key[*key_len].len= strlen(table); + ++(*key_len); + } + } + } + break; + } + default: + return false; + } + + return true; +} + +/* Prepare key list from db/table and table_list */ +static bool wsrep_prepare_keys_for_isolation(THD* thd, + const char* db, + const char* table, + const TABLE_LIST* table_list, + wsrep_key_arr_t* ka) +{ + ka->keys= 0; + ka->keys_len= 0; + + extern TABLE* find_temporary_table(THD*, const TABLE_LIST*); + + if (db || table) + { + TABLE_LIST tmp_table; + MDL_request mdl_request; + + memset(&tmp_table, 0, sizeof(tmp_table)); + tmp_table.table_name= (char*)table; + tmp_table.db= (char*)db; + tmp_table.mdl_request.init(MDL_key::GLOBAL, (db) ? db : "", + (table) ? table : "", + MDL_INTENTION_EXCLUSIVE, MDL_STATEMENT); + + if (!table || !find_temporary_table(thd, &tmp_table)) + { + if (!(ka->keys= (wsrep_key_t*)my_malloc(sizeof(wsrep_key_t), MYF(0)))) + { + WSREP_ERROR("Can't allocate memory for key_array"); + goto err; + } + ka->keys_len= 1; + if (!(ka->keys[0].key_parts= (wsrep_buf_t*) + my_malloc(sizeof(wsrep_buf_t)*2, MYF(0)))) + { + WSREP_ERROR("Can't allocate memory for key_parts"); + goto err; + } + ka->keys[0].key_parts_num= 2; + if (!wsrep_prepare_key_for_isolation( + db, table, + (wsrep_buf_t*)ka->keys[0].key_parts, + &ka->keys[0].key_parts_num)) + { + WSREP_ERROR("Preparing keys for isolation failed"); + goto err; + } + } + } + + for (const TABLE_LIST* table= table_list; table; table= table->next_global) + { + if (!find_temporary_table(thd, table)) + { + wsrep_key_t* tmp; + tmp= (wsrep_key_t*)my_realloc( + ka->keys, (ka->keys_len + 1) * sizeof(wsrep_key_t), + MYF(MY_ALLOW_ZERO_PTR)); + + if (!tmp) + { + WSREP_ERROR("Can't allocate memory for key_array"); + goto err; + } + ka->keys= tmp; + if (!(ka->keys[ka->keys_len].key_parts= (wsrep_buf_t*) + my_malloc(sizeof(wsrep_buf_t)*2, MYF(0)))) + { + WSREP_ERROR("Can't allocate memory for key_parts"); + goto err; + } + ka->keys[ka->keys_len].key_parts_num= 2; + ++ka->keys_len; + if (!wsrep_prepare_key_for_isolation( + table->db, table->table_name, + (wsrep_buf_t*)ka->keys[ka->keys_len - 1].key_parts, + &ka->keys[ka->keys_len - 1].key_parts_num)) + { + WSREP_ERROR("Preparing keys for isolation failed"); + goto err; + } + } + } + return true; +err: + wsrep_keys_free(ka); + return false; +} + + +bool wsrep_prepare_key_for_innodb(const uchar* cache_key, + size_t cache_key_len, + const uchar* row_id, + size_t row_id_len, + wsrep_buf_t* key, + size_t* key_len) +{ + if (*key_len < 3) return false; + + *key_len= 0; + switch (wsrep_protocol_version) + { + case 0: + { + key[0].ptr = cache_key; + key[0].len = cache_key_len; + + *key_len = 1; + break; + } + case 1: + case 2: + case 3: + { + key[0].ptr = cache_key; + key[0].len = strlen( (char*)cache_key ); + + key[1].ptr = cache_key + strlen( (char*)cache_key ) + 1; + key[1].len = strlen( (char*)(key[1].ptr) ); + + *key_len = 2; + break; + } + default: + return false; + } + + key[*key_len].ptr = row_id; + key[*key_len].len = row_id_len; + ++(*key_len); + + return true; +} + + +/* + * Construct Query_log_Event from thd query and serialize it + * into buffer. + * + * Return 0 in case of success, 1 in case of error. + */ +int wsrep_to_buf_helper( + THD* thd, const char *query, uint query_len, uchar** buf, size_t* buf_len) +{ + IO_CACHE tmp_io_cache; + if (open_cached_file(&tmp_io_cache, mysql_tmpdir, TEMP_PREFIX, + 65536, MYF(MY_WME))) + return 1; + int ret(0); + +#ifdef GTID_SUPPORT + if (thd->variables.gtid_next.type == GTID_GROUP) + { + Gtid_log_event gtid_ev(thd, FALSE, &thd->variables.gtid_next); + if (!gtid_ev.is_valid()) ret= 0; + if (!ret && gtid_ev.write(&tmp_io_cache)) ret= 1; + } +#endif /* GTID_SUPPORT */ + + /* if there is prepare query, add event for it */ + if (!ret && thd->wsrep_TOI_pre_query) + { + Query_log_event ev(thd, thd->wsrep_TOI_pre_query, + thd->wsrep_TOI_pre_query_len, + FALSE, FALSE, FALSE, 0); + if (ev.write(&tmp_io_cache)) ret= 1; + } + + /* continue to append the actual query */ + Query_log_event ev(thd, query, query_len, FALSE, FALSE, FALSE, 0); + if (!ret && ev.write(&tmp_io_cache)) ret= 1; + if (!ret && wsrep_write_cache_buf(&tmp_io_cache, buf, buf_len)) ret= 1; + close_cached_file(&tmp_io_cache); + return ret; +} + +#include "sql_show.h" +static int +create_view_query(THD *thd, uchar** buf, size_t* buf_len) +{ + LEX *lex= thd->lex; + SELECT_LEX *select_lex= &lex->select_lex; + TABLE_LIST *first_table= select_lex->table_list.first; + TABLE_LIST *views = first_table; + + String buff; + const LEX_STRING command[3]= + {{ C_STRING_WITH_LEN("CREATE ") }, + { C_STRING_WITH_LEN("ALTER ") }, + { C_STRING_WITH_LEN("CREATE OR REPLACE ") }}; + + buff.append(command[thd->lex->create_view_mode].str, + command[thd->lex->create_view_mode].length); + + if (!lex->definer) + { + /* + DEFINER-clause is missing; we have to create default definer in + persistent arena to be PS/SP friendly. + If this is an ALTER VIEW then the current user should be set as + the definer. + */ + + if (!(lex->definer= create_default_definer(thd, false))) + { + WSREP_WARN("view default definer issue"); + } + } + + views->algorithm = lex->create_view_algorithm; + views->definer.user = lex->definer->user; + views->definer.host = lex->definer->host; + views->view_suid = lex->create_view_suid; + views->with_check = lex->create_view_check; + + view_store_options(thd, views, &buff); + buff.append(STRING_WITH_LEN("VIEW ")); + /* Test if user supplied a db (ie: we did not use thd->db) */ + if (views->db && views->db[0] && + (thd->db == NULL || strcmp(views->db, thd->db))) + { + append_identifier(thd, &buff, views->db, + views->db_length); + buff.append('.'); + } + append_identifier(thd, &buff, views->table_name, + views->table_name_length); + if (lex->view_list.elements) + { + List_iterator_fast names(lex->view_list); + LEX_STRING *name; + int i; + + for (i= 0; (name= names++); i++) + { + buff.append(i ? ", " : "("); + append_identifier(thd, &buff, name->str, name->length); + } + buff.append(')'); + } + buff.append(STRING_WITH_LEN(" AS ")); + //buff.append(views->source.str, views->source.length); + buff.append(thd->lex->create_view_select.str, + thd->lex->create_view_select.length); + //int errcode= query_error_code(thd, TRUE); + //if (thd->binlog_query(THD::STMT_QUERY_TYPE, + // buff.ptr(), buff.length(), FALSE, FALSE, FALSE, errcod + return wsrep_to_buf_helper(thd, buff.ptr(), buff.length(), buf, buf_len); +} + +static int wsrep_TOI_begin(THD *thd, char *db_, char *table_, + const TABLE_LIST* table_list) +{ + wsrep_status_t ret(WSREP_WARNING); + uchar* buf(0); + size_t buf_len(0); + int buf_err; + + WSREP_DEBUG("TO BEGIN: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd), + thd->wsrep_exec_mode, thd->query() ); + switch (thd->lex->sql_command) + { + case SQLCOM_CREATE_VIEW: + buf_err= create_view_query(thd, &buf, &buf_len); + break; + case SQLCOM_CREATE_PROCEDURE: + case SQLCOM_CREATE_SPFUNCTION: + buf_err= wsrep_create_sp(thd, &buf, &buf_len); + break; + case SQLCOM_CREATE_TRIGGER: + buf_err= wsrep_create_trigger_query(thd, &buf, &buf_len); + break; + case SQLCOM_CREATE_EVENT: + buf_err= wsrep_create_event_query(thd, &buf, &buf_len); + break; + case SQLCOM_ALTER_EVENT: + buf_err= wsrep_alter_event_query(thd, &buf, &buf_len); + break; + default: + buf_err= wsrep_to_buf_helper(thd, thd->query(), thd->query_length(), &buf, + &buf_len); + break; + } + + wsrep_key_arr_t key_arr= {0, 0}; + struct wsrep_buf buff = { buf, buf_len }; + if (!buf_err && + wsrep_prepare_keys_for_isolation(thd, db_, table_, table_list, &key_arr)&& + WSREP_OK == (ret = wsrep->to_execute_start(wsrep, thd->thread_id, + key_arr.keys, key_arr.keys_len, + &buff, 1, + &thd->wsrep_trx_meta))) + { + thd->wsrep_exec_mode= TOTAL_ORDER; + wsrep_to_isolation++; + my_free(buf); + wsrep_keys_free(&key_arr); + WSREP_DEBUG("TO BEGIN: %lld, %d",(long long)wsrep_thd_trx_seqno(thd), + thd->wsrep_exec_mode); + } + else { + /* jump to error handler in mysql_execute_command() */ + WSREP_WARN("TO isolation failed for: %d, sql: %s. Check wsrep " + "connection state and retry the query.", + ret, (thd->query()) ? thd->query() : "void"); + my_error(ER_LOCK_DEADLOCK, MYF(0), "WSREP replication failed. Check " + "your wsrep connection state and retry the query."); + if (buf) my_free(buf); + wsrep_keys_free(&key_arr); + return -1; + } + return 0; +} + +static void wsrep_TOI_end(THD *thd) { + wsrep_status_t ret; + wsrep_to_isolation--; + + WSREP_DEBUG("TO END: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd), + thd->wsrep_exec_mode, (thd->query()) ? thd->query() : "void"); + + XID xid; + wsrep_xid_init(&xid, &thd->wsrep_trx_meta.gtid.uuid, + thd->wsrep_trx_meta.gtid.seqno); + wsrep_set_SE_checkpoint(&xid); + WSREP_DEBUG("TO END: %lld, update seqno", + (long long)wsrep_thd_trx_seqno(thd)); + + if (WSREP_OK == (ret = wsrep->to_execute_end(wsrep, thd->thread_id))) { + WSREP_DEBUG("TO END: %lld", (long long)wsrep_thd_trx_seqno(thd)); + } + else { + WSREP_WARN("TO isolation end failed for: %d, sql: %s", + ret, (thd->query()) ? thd->query() : "void"); + } +} + +static int wsrep_RSU_begin(THD *thd, char *db_, char *table_) +{ + wsrep_status_t ret(WSREP_WARNING); + WSREP_DEBUG("RSU BEGIN: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd), + thd->wsrep_exec_mode, thd->query() ); + + ret = wsrep->desync(wsrep); + if (ret != WSREP_OK) + { + WSREP_WARN("RSU desync failed %d for %s", ret, thd->query()); + my_error(ER_LOCK_DEADLOCK, MYF(0)); + return(ret); + } + mysql_mutex_lock(&LOCK_wsrep_replaying); + wsrep_replaying++; + mysql_mutex_unlock(&LOCK_wsrep_replaying); + + if (wsrep_wait_committing_connections_close(5000)) + { + /* no can do, bail out from DDL */ + WSREP_WARN("RSU failed due to pending transactions, %s", thd->query()); + mysql_mutex_lock(&LOCK_wsrep_replaying); + wsrep_replaying--; + mysql_mutex_unlock(&LOCK_wsrep_replaying); + + ret = wsrep->resync(wsrep); + if (ret != WSREP_OK) + { + WSREP_WARN("resync failed %d for %s", ret, thd->query()); + } + my_error(ER_LOCK_DEADLOCK, MYF(0)); + return(1); + } + + wsrep_seqno_t seqno = wsrep->pause(wsrep); + if (seqno == WSREP_SEQNO_UNDEFINED) + { + WSREP_WARN("pause failed %lld for %s", (long long)seqno, thd->query()); + return(1); + } + WSREP_DEBUG("paused at %lld", (long long)seqno); + thd->variables.wsrep_on = 0; + return 0; +} + +static void wsrep_RSU_end(THD *thd) +{ + wsrep_status_t ret(WSREP_WARNING); + WSREP_DEBUG("RSU END: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd), + thd->wsrep_exec_mode, thd->query() ); + + + mysql_mutex_lock(&LOCK_wsrep_replaying); + wsrep_replaying--; + mysql_mutex_unlock(&LOCK_wsrep_replaying); + + ret = wsrep->resume(wsrep); + if (ret != WSREP_OK) + { + WSREP_WARN("resume failed %d for %s", ret, thd->query()); + } + ret = wsrep->resync(wsrep); + if (ret != WSREP_OK) + { + WSREP_WARN("resync failed %d for %s", ret, thd->query()); + return; + } + thd->variables.wsrep_on = 1; +} + +int wsrep_to_isolation_begin(THD *thd, char *db_, char *table_, + const TABLE_LIST* table_list) +{ + int ret= 0; + + /* + No isolation for applier or replaying threads. + */ + if (thd->wsrep_exec_mode == REPL_RECV) + return 0; + + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + + if (thd->wsrep_conflict_state == MUST_ABORT) + { + WSREP_INFO("thread: %lu, %s has been aborted due to multi-master conflict", + thd->thread_id, thd->query()); + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + return WSREP_TRX_FAIL; + } + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + + DBUG_ASSERT(thd->wsrep_exec_mode == LOCAL_STATE); + DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno == WSREP_SEQNO_UNDEFINED); + + if (thd->global_read_lock.can_acquire_protection()) + { + WSREP_DEBUG("Aborting TOI: Global Read-Lock (FTWRL) in place: %s %lu", + thd->query(), thd->thread_id); + return -1; + } + + if (wsrep_debug && thd->mdl_context.has_locks()) + { + WSREP_DEBUG("thread holds MDL locks at TI begin: %s %lu", + thd->query(), thd->thread_id); + } + + /* + It makes sense to set auto_increment_* to defaults in TOI operations. + Must be done before wsrep_TOI_begin() since Query_log_event encapsulating + TOI statement and auto inc variables for wsrep replication is constructed + there. Variables are reset back in THD::reset_for_next_command() before + processing of next command. + */ + if (wsrep_auto_increment_control) + { + thd->variables.auto_increment_offset = 1; + thd->variables.auto_increment_increment = 1; + } + + if (thd->variables.wsrep_on && thd->wsrep_exec_mode==LOCAL_STATE) + { + switch (wsrep_OSU_method_options) { + case WSREP_OSU_TOI: ret = wsrep_TOI_begin(thd, db_, table_, + table_list); break; + case WSREP_OSU_RSU: ret = wsrep_RSU_begin(thd, db_, table_); break; + } + if (!ret) + { + thd->wsrep_exec_mode= TOTAL_ORDER; + } + } + return ret; +} + +void wsrep_to_isolation_end(THD *thd) +{ + if (thd->wsrep_exec_mode == TOTAL_ORDER) + { + switch(wsrep_OSU_method_options) + { + case WSREP_OSU_TOI: wsrep_TOI_end(thd); break; + case WSREP_OSU_RSU: wsrep_RSU_end(thd); break; + } + wsrep_cleanup_transaction(thd); + } +} + +#define WSREP_MDL_LOG(severity, msg, req, gra) \ + WSREP_##severity( \ + "%s\n" \ + "request: (%lu \tseqno %lld \twsrep (%d, %d, %d) cmd %d %d \t%s)\n" \ + "granted: (%lu \tseqno %lld \twsrep (%d, %d, %d) cmd %d %d \t%s)", \ + msg, \ + req->thread_id, (long long)wsrep_thd_trx_seqno(req), \ + req->wsrep_exec_mode, req->wsrep_query_state, req->wsrep_conflict_state, \ + req->get_command(), req->lex->sql_command, req->query(), \ + gra->thread_id, (long long)wsrep_thd_trx_seqno(gra), \ + gra->wsrep_exec_mode, gra->wsrep_query_state, gra->wsrep_conflict_state, \ + gra->get_command(), gra->lex->sql_command, gra->query()); + +bool +wsrep_grant_mdl_exception(MDL_context *requestor_ctx, + MDL_ticket *ticket +) { + if (!WSREP_ON) return FALSE; + + THD *request_thd = requestor_ctx->get_thd(); + THD *granted_thd = ticket->get_ctx()->get_thd(); + bool ret = FALSE; + + mysql_mutex_lock(&request_thd->LOCK_wsrep_thd); + if (request_thd->wsrep_exec_mode == TOTAL_ORDER || + request_thd->wsrep_exec_mode == REPL_RECV) + { + mysql_mutex_unlock(&request_thd->LOCK_wsrep_thd); + WSREP_MDL_LOG(DEBUG, "MDL conflict ", request_thd, granted_thd); + ticket->wsrep_report(wsrep_debug); + + mysql_mutex_lock(&granted_thd->LOCK_wsrep_thd); + if (granted_thd->wsrep_exec_mode == TOTAL_ORDER || + granted_thd->wsrep_exec_mode == REPL_RECV) + { + WSREP_MDL_LOG(INFO, "MDL BF-BF conflict", request_thd, granted_thd); + ticket->wsrep_report(true); + mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd); + ret = TRUE; + } + else if (granted_thd->lex->sql_command == SQLCOM_FLUSH) + { + WSREP_DEBUG("mdl granted over FLUSH BF"); + ticket->wsrep_report(wsrep_debug); + mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd); + ret = TRUE; + } + else if (request_thd->lex->sql_command == SQLCOM_DROP_TABLE) + { + WSREP_DEBUG("DROP caused BF abort"); + ticket->wsrep_report(wsrep_debug); + mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd); + wsrep_abort_thd((void*)request_thd, (void*)granted_thd, 1); + ret = FALSE; + } + else if (granted_thd->wsrep_query_state == QUERY_COMMITTING) + { + WSREP_DEBUG("mdl granted, but commiting thd abort scheduled"); + ticket->wsrep_report(wsrep_debug); + mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd); + wsrep_abort_thd((void*)request_thd, (void*)granted_thd, 1); + ret = FALSE; + } + else + { + WSREP_MDL_LOG(DEBUG, "MDL conflict-> BF abort", request_thd, granted_thd); + ticket->wsrep_report(wsrep_debug); + mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd); + wsrep_abort_thd((void*)request_thd, (void*)granted_thd, 1); + ret = FALSE; + } + } + else + { + mysql_mutex_unlock(&request_thd->LOCK_wsrep_thd); + } + return ret; +} + + +pthread_handler_t start_wsrep_THD(void *arg) +{ + THD *thd; + rpl_sql_thread_info sql_info(NULL); + wsrep_thd_processor_fun processor= (wsrep_thd_processor_fun)arg; + + if (my_thread_init()) + { + WSREP_ERROR("Could not initialize thread"); + return(NULL); + } + + if (!(thd= new THD(true))) + { + return(NULL); + } + mysql_mutex_lock(&LOCK_thread_count); + thd->thread_id=thread_id++; + + thd->real_id=pthread_self(); // Keep purify happy + thread_count++; + thread_created++; + threads.append(thd); + + my_net_init(&thd->net,(st_vio*) 0, MYF(0)); + + DBUG_PRINT("wsrep",(("creating thread %lld"), (long long)thd->thread_id)); + thd->prior_thr_create_utime= thd->start_utime= microsecond_interval_timer(); + (void) mysql_mutex_unlock(&LOCK_thread_count); + + /* from bootstrap()... */ + thd->bootstrap=1; + thd->max_client_packet_length= thd->net.max_packet; + thd->security_ctx->master_access= ~(ulong)0; + thd->system_thread_info.rpl_sql_info= &sql_info; + + /* from handle_one_connection... */ + pthread_detach_this_thread(); + + mysql_thread_set_psi_id(thd->thread_id); + thd->thr_create_utime= microsecond_interval_timer(); + if (MYSQL_CALLBACK_ELSE(thread_scheduler, init_new_connection_thread, (), 0)) + { + close_connection(thd, ER_OUT_OF_RESOURCES); + statistic_increment(aborted_connects,&LOCK_status); + MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0)); + + return(NULL); + } + +// + /* + handle_one_connection() is normally the only way a thread would + start and would always be on the very high end of the stack , + therefore, the thread stack always starts at the address of the + first local variable of handle_one_connection, which is thd. We + need to know the start of the stack so that we could check for + stack overruns. + */ + DBUG_PRINT("wsrep", ("handle_one_connection called by thread %lld\n", + (long long)thd->thread_id)); + /* now that we've called my_thread_init(), it is safe to call DBUG_* */ + + thd->thread_stack= (char*) &thd; + if (thd->store_globals()) + { + close_connection(thd, ER_OUT_OF_RESOURCES); + statistic_increment(aborted_connects,&LOCK_status); + MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0)); + delete thd; + + return(NULL); + } + + thd->system_thread= SYSTEM_THREAD_SLAVE_SQL; + thd->security_ctx->skip_grants(); + + /* handle_one_connection() again... */ + //thd->version= refresh_version; + thd->proc_info= 0; + thd->set_command(COM_SLEEP); + thd->set_time(); + thd->init_for_queries(); + + mysql_mutex_lock(&LOCK_thread_count); + wsrep_running_threads++; + mysql_cond_broadcast(&COND_thread_count); + mysql_mutex_unlock(&LOCK_thread_count); + + processor(thd); + + close_connection(thd, 0); + + mysql_mutex_lock(&LOCK_thread_count); + wsrep_running_threads--; + WSREP_DEBUG("wsrep running threads now: %lu", wsrep_running_threads); + mysql_cond_broadcast(&COND_thread_count); + mysql_mutex_unlock(&LOCK_thread_count); + + // Note: We can't call THD destructor without crashing + // if plugins have not been initialized. However, in most of the + // cases this means that pre SE initialization SST failed and + // we are going to exit anyway. + if (plugins_are_initialized) + { + net_end(&thd->net); + MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 1)); + } + else + { + // TODO: lightweight cleanup to get rid of: + // 'Error in my_thread_global_end(): 2 threads didn't exit' + // at server shutdown + } + + my_thread_end(); + if (thread_handling > SCHEDULER_ONE_THREAD_PER_CONNECTION) + { + mysql_mutex_lock(&LOCK_thread_count); + delete thd; + thread_count--; + mysql_mutex_unlock(&LOCK_thread_count); + } + return(NULL); +} + + +/**/ +static bool abort_replicated(THD *thd) +{ + bool ret_code= false; + if (thd->wsrep_query_state== QUERY_COMMITTING) + { + if (wsrep_debug) WSREP_INFO("aborting replicated trx: %lu", thd->real_id); + + (void)wsrep_abort_thd(thd, thd, TRUE); + ret_code= true; + } + return ret_code; +} + + +/**/ +static inline bool is_client_connection(THD *thd) +{ + return (thd->wsrep_client_thread && thd->variables.wsrep_on); +} + + +static inline bool is_replaying_connection(THD *thd) +{ + bool ret; + + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + ret= (thd->wsrep_conflict_state == REPLAYING) ? true : false; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + + return ret; +} + + +static inline bool is_committing_connection(THD *thd) +{ + bool ret; + + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + ret= (thd->wsrep_query_state == QUERY_COMMITTING) ? true : false; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + + return ret; +} + + +static bool have_client_connections() +{ + THD *tmp; + + I_List_iterator it(threads); + while ((tmp=it++)) + { + DBUG_PRINT("quit",("Informing thread %ld that it's time to die", + tmp->thread_id)); + if (is_client_connection(tmp) && tmp->killed == KILL_CONNECTION) + { + (void)abort_replicated(tmp); + return true; + } + } + return false; +} + +/* + returns the number of wsrep appliers running. + However, the caller (thd parameter) is not taken in account + */ +static int have_wsrep_appliers(THD *thd) +{ + int ret= 0; + THD *tmp; + + I_List_iterator it(threads); + while ((tmp=it++)) + { + ret+= (tmp != thd && tmp->wsrep_applier); + } + return ret; +} + + +static void wsrep_close_thread(THD *thd) +{ + thd->killed= KILL_CONNECTION; + MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (thd)); + if (thd->mysys_var) + { + thd->mysys_var->abort=1; + mysql_mutex_lock(&thd->mysys_var->mutex); + if (thd->mysys_var->current_cond) + { + mysql_mutex_lock(thd->mysys_var->current_mutex); + mysql_cond_broadcast(thd->mysys_var->current_cond); + mysql_mutex_unlock(thd->mysys_var->current_mutex); + } + mysql_mutex_unlock(&thd->mysys_var->mutex); + } +} + + +static my_bool have_committing_connections() +{ + THD *tmp; + mysql_mutex_lock(&LOCK_thread_count); // For unlink from list + + I_List_iterator it(threads); + while ((tmp=it++)) + { + if (!is_client_connection(tmp)) + continue; + + if (is_committing_connection(tmp)) + { + return TRUE; + } + } + mysql_mutex_unlock(&LOCK_thread_count); + return FALSE; +} + + +int wsrep_wait_committing_connections_close(int wait_time) +{ + int sleep_time= 100; + + while (have_committing_connections() && wait_time > 0) + { + WSREP_DEBUG("wait for committing transaction to close: %d", wait_time); + my_sleep(sleep_time); + wait_time -= sleep_time; + } + if (have_committing_connections()) + { + return 1; + } + return 0; +} + + +void wsrep_close_client_connections(my_bool wait_to_end) +{ + /* + First signal all threads that it's time to die + */ + + THD *tmp; + mysql_mutex_lock(&LOCK_thread_count); // For unlink from list + + bool kill_cached_threads_saved= kill_cached_threads; + kill_cached_threads= true; // prevent future threads caching + mysql_cond_broadcast(&COND_thread_cache); // tell cached threads to die + + I_List_iterator it(threads); + while ((tmp=it++)) + { + DBUG_PRINT("quit",("Informing thread %ld that it's time to die", + tmp->thread_id)); + /* We skip slave threads & scheduler on this first loop through. */ + if (!is_client_connection(tmp)) + continue; + + if (is_replaying_connection(tmp)) + { + tmp->killed= KILL_CONNECTION; + continue; + } + + /* replicated transactions must be skipped */ + if (abort_replicated(tmp)) + continue; + + WSREP_DEBUG("closing connection %ld", tmp->thread_id); + wsrep_close_thread(tmp); + } + mysql_mutex_unlock(&LOCK_thread_count); + + if (thread_count) + sleep(2); // Give threads time to die + + mysql_mutex_lock(&LOCK_thread_count); + /* + Force remaining threads to die by closing the connection to the client + */ + + I_List_iterator it2(threads); + while ((tmp=it2++)) + { +#ifndef __bsdi__ // Bug in BSDI kernel + if (is_client_connection(tmp) && + !abort_replicated(tmp) && + !is_replaying_connection(tmp)) + { + WSREP_INFO("killing local connection: %ld",tmp->thread_id); + close_connection(tmp,0); + } +#endif + } + + DBUG_PRINT("quit",("Waiting for threads to die (count=%u)",thread_count)); + if (wsrep_debug) + WSREP_INFO("waiting for client connections to close: %u", thread_count); + + while (wait_to_end && have_client_connections()) + { + mysql_cond_wait(&COND_thread_count, &LOCK_thread_count); + DBUG_PRINT("quit",("One thread died (count=%u)", thread_count)); + } + + kill_cached_threads= kill_cached_threads_saved; + + mysql_mutex_unlock(&LOCK_thread_count); + + /* All client connection threads have now been aborted */ +} + + +void wsrep_close_applier(THD *thd) +{ + WSREP_DEBUG("closing applier %ld", thd->thread_id); + wsrep_close_thread(thd); +} + + +void wsrep_close_threads(THD *thd) +{ + THD *tmp; + mysql_mutex_lock(&LOCK_thread_count); // For unlink from list + + I_List_iterator it(threads); + while ((tmp=it++)) + { + DBUG_PRINT("quit",("Informing thread %ld that it's time to die", + tmp->thread_id)); + /* We skip slave threads & scheduler on this first loop through. */ + if (tmp->wsrep_applier && tmp != thd) + { + WSREP_DEBUG("closing wsrep thread %ld", tmp->thread_id); + wsrep_close_thread (tmp); + } + } + + mysql_mutex_unlock(&LOCK_thread_count); +} + + +void wsrep_close_applier_threads(int count) +{ + THD *tmp; + mysql_mutex_lock(&LOCK_thread_count); // For unlink from list + + I_List_iterator it(threads); + while ((tmp=it++) && count) + { + DBUG_PRINT("quit",("Informing thread %ld that it's time to die", + tmp->thread_id)); + /* We skip slave threads & scheduler on this first loop through. */ + if (tmp->wsrep_applier) + { + WSREP_DEBUG("closing wsrep applier thread %ld", tmp->thread_id); + tmp->wsrep_applier_closing= TRUE; + count--; + } + } + + mysql_mutex_unlock(&LOCK_thread_count); +} + + +void wsrep_wait_appliers_close(THD *thd) +{ + /* Wait for wsrep appliers to gracefully exit */ + mysql_mutex_lock(&LOCK_thread_count); + while (have_wsrep_appliers(thd) > 1) + // 1 is for rollbacker thread which needs to be killed explicitly. + // This gotta be fixed in a more elegant manner if we gonna have arbitrary + // number of non-applier wsrep threads. + { + if (thread_handling > SCHEDULER_ONE_THREAD_PER_CONNECTION) + { + mysql_mutex_unlock(&LOCK_thread_count); + my_sleep(100); + mysql_mutex_lock(&LOCK_thread_count); + } + else + mysql_cond_wait(&COND_thread_count,&LOCK_thread_count); + DBUG_PRINT("quit",("One applier died (count=%u)",thread_count)); + } + mysql_mutex_unlock(&LOCK_thread_count); + /* Now kill remaining wsrep threads: rollbacker */ + wsrep_close_threads (thd); + /* and wait for them to die */ + mysql_mutex_lock(&LOCK_thread_count); + while (have_wsrep_appliers(thd) > 0) + { + if (thread_handling > SCHEDULER_ONE_THREAD_PER_CONNECTION) + { + mysql_mutex_unlock(&LOCK_thread_count); + my_sleep(100); + mysql_mutex_lock(&LOCK_thread_count); + } + else + mysql_cond_wait(&COND_thread_count,&LOCK_thread_count); + DBUG_PRINT("quit",("One thread died (count=%u)",thread_count)); + } + mysql_mutex_unlock(&LOCK_thread_count); + + /* All wsrep applier threads have now been aborted. However, if this thread + is also applier, we are still running... + */ +} + + +void wsrep_kill_mysql(THD *thd) +{ + if (mysqld_server_started) + { + if (!shutdown_in_progress) + { + WSREP_INFO("starting shutdown"); + kill_mysql(); + } + } + else + { + unireg_abort(1); + } +} + + +int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len) +{ + String log_query; + sp_head *sp = thd->lex->sphead; + ulong saved_mode= thd->variables.sql_mode; + String retstr(64); + retstr.set_charset(system_charset_info); + + log_query.set_charset(system_charset_info); + + if (sp->m_type == TYPE_ENUM_FUNCTION) + { + sp_returns_type(thd, retstr, sp); + } + + if (!create_string(thd, &log_query, + sp->m_type, + (sp->m_explicit_name ? sp->m_db.str : NULL), + (sp->m_explicit_name ? sp->m_db.length : 0), + sp->m_name.str, sp->m_name.length, + sp->m_params.str, sp->m_params.length, + retstr.c_ptr(), retstr.length(), + sp->m_body.str, sp->m_body.length, + sp->m_chistics, &(thd->lex->definer->user), + &(thd->lex->definer->host), + saved_mode)) + { + WSREP_WARN("SP create string failed: %s", thd->query()); + return 1; + } + + return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(), buf, buf_len); +} + + +extern int wsrep_on(void *thd) +{ + return (int)(WSREP(((THD*)thd))); +} + + +extern "C" bool wsrep_thd_is_wsrep_on(THD *thd) +{ + return thd->variables.wsrep_on; +} + + +extern "C" bool wsrep_consistency_check(void *thd) +{ + return ((THD*)thd)->wsrep_consistency_check == CONSISTENCY_CHECK_RUNNING; +} + + +extern "C" void wsrep_thd_set_exec_mode(THD *thd, enum wsrep_exec_mode mode) +{ + thd->wsrep_exec_mode= mode; +} + + +extern "C" void wsrep_thd_set_query_state( + THD *thd, enum wsrep_query_state state) +{ + thd->wsrep_query_state= state; +} + + +extern "C" void wsrep_thd_set_conflict_state( + THD *thd, enum wsrep_conflict_state state) +{ + thd->wsrep_conflict_state= state; +} + + +extern "C" enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd) +{ + return thd->wsrep_exec_mode; +} + + +extern "C" const char *wsrep_thd_exec_mode_str(THD *thd) +{ + return + (!thd) ? "void" : + (thd->wsrep_exec_mode == LOCAL_STATE) ? "local" : + (thd->wsrep_exec_mode == REPL_RECV) ? "applier" : + (thd->wsrep_exec_mode == TOTAL_ORDER) ? "total order" : + (thd->wsrep_exec_mode == LOCAL_COMMIT) ? "local commit" : "void"; +} + + +extern "C" enum wsrep_query_state wsrep_thd_query_state(THD *thd) +{ + return thd->wsrep_query_state; +} + + +extern "C" const char *wsrep_thd_query_state_str(THD *thd) +{ + return + (!thd) ? "void" : + (thd->wsrep_query_state == QUERY_IDLE) ? "idle" : + (thd->wsrep_query_state == QUERY_EXEC) ? "executing" : + (thd->wsrep_query_state == QUERY_COMMITTING) ? "committing" : + (thd->wsrep_query_state == QUERY_EXITING) ? "exiting" : + (thd->wsrep_query_state == QUERY_ROLLINGBACK) ? "rolling back" : "void"; +} + + +extern "C" enum wsrep_conflict_state wsrep_thd_conflict_state(THD *thd) +{ + return thd->wsrep_conflict_state; +} + + +extern "C" const char *wsrep_thd_conflict_state_str(THD *thd) +{ + return + (!thd) ? "void" : + (thd->wsrep_conflict_state == NO_CONFLICT) ? "no conflict" : + (thd->wsrep_conflict_state == MUST_ABORT) ? "must abort" : + (thd->wsrep_conflict_state == ABORTING) ? "aborting" : + (thd->wsrep_conflict_state == MUST_REPLAY) ? "must replay" : + (thd->wsrep_conflict_state == REPLAYING) ? "replaying" : + (thd->wsrep_conflict_state == RETRY_AUTOCOMMIT) ? "retrying" : + (thd->wsrep_conflict_state == CERT_FAILURE) ? "cert failure" : "void"; +} + + +extern "C" wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd) +{ + return &thd->wsrep_ws_handle; +} + + +extern "C" void wsrep_thd_LOCK(THD *thd) +{ + mysql_mutex_lock(&thd->LOCK_wsrep_thd); +} + + +extern "C" void wsrep_thd_UNLOCK(THD *thd) +{ + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); +} + + +extern "C" time_t wsrep_thd_query_start(THD *thd) +{ + return thd->query_start(); +} + + +extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd) +{ + return thd->wsrep_rand; +} + + +extern "C" my_thread_id wsrep_thd_thread_id(THD *thd) +{ + return thd->thread_id; +} + + +extern "C" wsrep_seqno_t wsrep_thd_trx_seqno(THD *thd) +{ + return (thd) ? thd->wsrep_trx_meta.gtid.seqno : WSREP_SEQNO_UNDEFINED; +} + + +extern "C" query_id_t wsrep_thd_query_id(THD *thd) +{ + return thd->query_id; +} + + +extern "C" char *wsrep_thd_query(THD *thd) +{ + return (thd) ? thd->query() : NULL; +} + + +extern "C" query_id_t wsrep_thd_wsrep_last_query_id(THD *thd) +{ + return thd->wsrep_last_query_id; +} + + +extern "C" void wsrep_thd_set_wsrep_last_query_id(THD *thd, query_id_t id) +{ + thd->wsrep_last_query_id= id; +} + + +extern "C" void wsrep_thd_awake(THD *thd, my_bool signal) +{ + if (signal) + { + mysql_mutex_lock(&thd->LOCK_thd_data); + thd->awake(KILL_QUERY); + mysql_mutex_unlock(&thd->LOCK_thd_data); + } + else + { + mysql_mutex_lock(&LOCK_wsrep_replaying); + mysql_cond_broadcast(&COND_wsrep_replaying); + mysql_mutex_unlock(&LOCK_wsrep_replaying); + } +} + + +extern "C" int wsrep_thd_retry_counter(THD *thd) +{ + return(thd->wsrep_retry_counter); +} + + +extern int +wsrep_trx_order_before(void *thd1, void *thd2) +{ + if (wsrep_thd_trx_seqno((THD*)thd1) < wsrep_thd_trx_seqno((THD*)thd2)) { + WSREP_DEBUG("BF conflict, order: %lld %lld\n", + (long long)wsrep_thd_trx_seqno((THD*)thd1), + (long long)wsrep_thd_trx_seqno((THD*)thd2)); + return 1; + } + WSREP_DEBUG("waiting for BF, trx order: %lld %lld\n", + (long long)wsrep_thd_trx_seqno((THD*)thd1), + (long long)wsrep_thd_trx_seqno((THD*)thd2)); + return 0; +} + + +extern "C" int +wsrep_trx_is_aborting(void *thd_ptr) +{ + if (thd_ptr) { + if ((((THD *)thd_ptr)->wsrep_conflict_state == MUST_ABORT) || + (((THD *)thd_ptr)->wsrep_conflict_state == ABORTING)) { + return 1; + } + } + return 0; +} + + +my_bool wsrep_read_only_option(THD *thd, TABLE_LIST *all_tables) +{ + int opt_readonly_saved = opt_readonly; + ulong flag_saved = (ulong)(thd->security_ctx->master_access & SUPER_ACL); + + opt_readonly = 0; + thd->security_ctx->master_access &= ~SUPER_ACL; + + my_bool ret = !deny_updates_if_read_only_option(thd, all_tables); + + opt_readonly = opt_readonly_saved; + thd->security_ctx->master_access |= flag_saved; + + return ret; +} + + +void wsrep_copy_query(THD *thd) +{ + thd->wsrep_retry_command = thd->get_command(); + thd->wsrep_retry_query_len = thd->query_length(); + if (thd->wsrep_retry_query) { + my_free(thd->wsrep_retry_query); + } + thd->wsrep_retry_query = (char *)my_malloc( + thd->wsrep_retry_query_len + 1, MYF(0)); + strncpy(thd->wsrep_retry_query, thd->query(), thd->wsrep_retry_query_len); + thd->wsrep_retry_query[thd->wsrep_retry_query_len] = '\0'; +} + + +bool wsrep_is_show_query(enum enum_sql_command command) +{ + DBUG_ASSERT(command >= 0 && command <= SQLCOM_END); + return (sql_command_flags[command] & CF_STATUS_COMMAND) != 0; +} + +bool wsrep_create_like_table(THD* thd, TABLE_LIST* table, + TABLE_LIST* src_table, + HA_CREATE_INFO *create_info) +{ + TABLE *tmp_table; + bool is_tmp_table= FALSE; + + for (tmp_table= thd->temporary_tables; tmp_table; tmp_table=tmp_table->next) + { + if (!strcmp(src_table->db, tmp_table->s->db.str) && + !strcmp(src_table->table_name, tmp_table->s->table_name.str)) + { + is_tmp_table= TRUE; + break; + } + } + if (create_info->options & HA_LEX_CREATE_TMP_TABLE) + { + + /* CREATE TEMPORARY TABLE LIKE must be skipped from replication */ + WSREP_DEBUG("CREATE TEMPORARY TABLE LIKE... skipped replication\n %s", + thd->query()); + } + else if (!is_tmp_table) + { + /* this is straight CREATE TABLE LIKE... eith no tmp tables */ + WSREP_TO_ISOLATION_BEGIN(table->db, table->table_name, NULL); + } + else + { + /* here we have CREATE TABLE LIKE + the temporary table definition will be needed in slaves to + enable the create to succeed + */ + TABLE_LIST tbl; + bzero((void*) &tbl, sizeof(tbl)); + tbl.db= src_table->db; + tbl.table_name= tbl.alias= src_table->table_name; + tbl.table= tmp_table; + char buf[2048]; + String query(buf, sizeof(buf), system_charset_info); + query.length(0); // Have to zero it since constructor doesn't + + (void) store_create_info(thd, &tbl, &query, NULL, TRUE, FALSE); + WSREP_DEBUG("TMP TABLE: %s", query.ptr()); + + thd->wsrep_TOI_pre_query= query.ptr(); + thd->wsrep_TOI_pre_query_len= query.length(); + + WSREP_TO_ISOLATION_BEGIN(table->db, table->table_name, NULL); + + thd->wsrep_TOI_pre_query= NULL; + thd->wsrep_TOI_pre_query_len= 0; + } + + return(false); + +error: + thd->wsrep_TOI_pre_query= NULL; + return (true); +} + + +int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len) +{ + LEX *lex= thd->lex; + String stmt_query; + + LEX_STRING definer_user; + LEX_STRING definer_host; + + if (!lex->definer) + { + if (!thd->slave_thread) + { + if (!(lex->definer= create_default_definer(thd, false))) + return 1; + } + } + + if (lex->definer) + { + /* SUID trigger. */ + + definer_user= lex->definer->user; + definer_host= lex->definer->host; + } + else + { + /* non-SUID trigger. */ + + definer_user.str= 0; + definer_user.length= 0; + + definer_host.str= 0; + definer_host.length= 0; + } + + stmt_query.append(STRING_WITH_LEN("CREATE ")); + + append_definer(thd, &stmt_query, &definer_user, &definer_host); + + LEX_STRING stmt_definition; + stmt_definition.str= (char*) thd->lex->stmt_definition_begin; + stmt_definition.length= thd->lex->stmt_definition_end + - thd->lex->stmt_definition_begin; + trim_whitespace(thd->charset(), & stmt_definition); + + stmt_query.append(stmt_definition.str, stmt_definition.length); + + return wsrep_to_buf_helper(thd, stmt_query.c_ptr(), stmt_query.length(), + buf, buf_len); +} diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h new file mode 100644 index 00000000000..2150ac85bf0 --- /dev/null +++ b/sql/wsrep_mysqld.h @@ -0,0 +1,370 @@ +/* Copyright 2008-2013 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include + +#if !defined(WSREP_MYSQLD_H) && defined(WITH_WSREP) +#define WSREP_MYSQLD_H + +typedef struct st_mysql_show_var SHOW_VAR; +#include +//#include "rpl_gtid.h" +#include "../wsrep/wsrep_api.h" +#include "mdl.h" +#include "mysqld.h" +#include "sql_table.h" + +#define WSREP_UNDEFINED_TRX_ID ULONGLONG_MAX + +class set_var; +class THD; + +enum wsrep_exec_mode { + LOCAL_STATE, + REPL_RECV, + TOTAL_ORDER, + LOCAL_COMMIT +}; + +enum wsrep_query_state { + QUERY_IDLE, + QUERY_EXEC, + QUERY_COMMITTING, + QUERY_EXITING, + QUERY_ROLLINGBACK, +}; + +enum wsrep_conflict_state { + NO_CONFLICT, + MUST_ABORT, + ABORTING, + ABORTED, + MUST_REPLAY, + REPLAYING, + RETRY_AUTOCOMMIT, + CERT_FAILURE, +}; + +enum wsrep_consistency_check_mode { + NO_CONSISTENCY_CHECK, + CONSISTENCY_CHECK_DECLARED, + CONSISTENCY_CHECK_RUNNING, +}; + +struct wsrep_thd_shadow { + ulonglong options; + uint server_status; + enum wsrep_exec_mode wsrep_exec_mode; + Vio *vio; + ulong tx_isolation; + char *db; + size_t db_length; +}; + +// Global wsrep parameters +extern wsrep_t* wsrep; + +// MySQL wsrep options +extern const char* wsrep_provider; +extern const char* wsrep_provider_options; +extern const char* wsrep_cluster_name; +extern const char* wsrep_cluster_address; +extern const char* wsrep_node_name; +extern const char* wsrep_node_address; +extern const char* wsrep_node_incoming_address; +extern const char* wsrep_data_home_dir; +extern const char* wsrep_dbug_option; +extern long wsrep_slave_threads; +extern int wsrep_slave_count_change; +extern MYSQL_PLUGIN_IMPORT my_bool wsrep_debug; +extern my_bool wsrep_convert_LOCK_to_trx; +extern ulong wsrep_retry_autocommit; +extern my_bool wsrep_auto_increment_control; +extern my_bool wsrep_drupal_282555_workaround; +extern my_bool wsrep_incremental_data_collection; +extern const char* wsrep_start_position; +extern ulong wsrep_max_ws_size; +extern ulong wsrep_max_ws_rows; +extern const char* wsrep_notify_cmd; +extern my_bool wsrep_certify_nonPK; +extern long wsrep_max_protocol_version; +extern long wsrep_protocol_version; +extern ulong wsrep_forced_binlog_format; +extern ulong wsrep_OSU_method_options; +extern my_bool wsrep_desync; +extern my_bool wsrep_recovery; +extern my_bool wsrep_replicate_myisam; +extern my_bool wsrep_log_conflicts; +extern ulong wsrep_mysql_replication_bundle; +extern my_bool wsrep_load_data_splitting; +extern my_bool wsrep_restart_slave; +extern my_bool wsrep_restart_slave_activated; +extern my_bool wsrep_slave_FK_checks; +extern my_bool wsrep_slave_UK_checks; + +enum enum_wsrep_OSU_method { WSREP_OSU_TOI, WSREP_OSU_RSU }; +enum enum_wsrep_sync_wait { + WSREP_SYNC_WAIT_NONE = 0x0, + // show, select, begin + WSREP_SYNC_WAIT_BEFORE_READ = 0x1, + WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE = 0x2, + WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE = 0x4, + WSREP_SYNC_WAIT_MAX = 0x7 +}; + +// MySQL status variables +extern my_bool wsrep_connected; +extern my_bool wsrep_ready; +extern const char* wsrep_cluster_state_uuid; +extern long long wsrep_cluster_conf_id; +extern const char* wsrep_cluster_status; +extern long wsrep_cluster_size; +extern long wsrep_local_index; +extern long long wsrep_local_bf_aborts; +extern const char* wsrep_provider_name; +extern const char* wsrep_provider_version; +extern const char* wsrep_provider_vendor; + +int wsrep_show_status(THD *thd, SHOW_VAR *var, char *buff); +void wsrep_free_status(THD *thd); + +/* Filters out --wsrep-new-cluster oprtion from argv[] + * should be called in the very beginning of main() */ +void wsrep_filter_new_cluster (int* argc, char* argv[]); + +int wsrep_init(); +void wsrep_deinit(bool free_options); +void wsrep_recover(); +bool wsrep_before_SE(); // initialize wsrep before storage + // engines (true) or after (false) +/* wsrep initialization sequence at startup + * @param before wsrep_before_SE() value */ +void wsrep_init_startup(bool before); + +// Other wsrep global variables +extern my_bool wsrep_inited; // whether wsrep is initialized ? + +extern "C" enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd); +extern "C" enum wsrep_conflict_state wsrep_thd_conflict_state(THD *thd); +extern "C" enum wsrep_query_state wsrep_thd_query_state(THD *thd); +extern "C" const char * wsrep_thd_exec_mode_str(THD *thd); +extern "C" const char * wsrep_thd_conflict_state_str(THD *thd); +extern "C" const char * wsrep_thd_query_state_str(THD *thd); +extern "C" wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd); + +extern "C" void wsrep_thd_set_exec_mode(THD *thd, enum wsrep_exec_mode mode); +extern "C" void wsrep_thd_set_query_state( + THD *thd, enum wsrep_query_state state); +extern "C" void wsrep_thd_set_conflict_state( + THD *thd, enum wsrep_conflict_state state); + +extern "C" void wsrep_thd_set_trx_to_replay(THD *thd, uint64 trx_id); + +extern "C" void wsrep_thd_LOCK(THD *thd); +extern "C" void wsrep_thd_UNLOCK(THD *thd); +extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd); +extern "C" time_t wsrep_thd_query_start(THD *thd); +extern "C" my_thread_id wsrep_thd_thread_id(THD *thd); +extern "C" int64_t wsrep_thd_trx_seqno(THD *thd); +extern "C" query_id_t wsrep_thd_query_id(THD *thd); +extern "C" char * wsrep_thd_query(THD *thd); +extern "C" query_id_t wsrep_thd_wsrep_last_query_id(THD *thd); +extern "C" void wsrep_thd_set_wsrep_last_query_id(THD *thd, query_id_t id); +extern "C" void wsrep_thd_awake(THD *thd, my_bool signal); +extern "C" int wsrep_thd_retry_counter(THD *thd); + + +extern void wsrep_close_client_connections(my_bool wait_to_end); +extern int wsrep_wait_committing_connections_close(int wait_time); +extern void wsrep_close_applier(THD *thd); +extern void wsrep_wait_appliers_close(THD *thd); +extern void wsrep_close_applier_threads(int count); +extern void wsrep_kill_mysql(THD *thd); + +/* new defines */ +extern void wsrep_stop_replication(THD *thd); +extern bool wsrep_start_replication(); +extern bool wsrep_sync_wait (THD* thd, uint mask = WSREP_SYNC_WAIT_BEFORE_READ); +extern int wsrep_check_opts (int argc, char* const* argv); +extern void wsrep_prepend_PATH (const char* path); +/* some inline functions are defined in wsrep_mysqld_inl.h */ + +/* Other global variables */ +extern wsrep_seqno_t wsrep_locked_seqno; + +#define WSREP_ON \ + (global_system_variables.wsrep_on) + +#define WSREP(thd) \ + (WSREP_ON && (thd && thd->variables.wsrep_on)) + +#define WSREP_CLIENT(thd) \ + (WSREP(thd) && thd->wsrep_client_thread) + +#define WSREP_EMULATE_BINLOG(thd) \ + (WSREP(thd) && wsrep_emulate_bin_log) + +// MySQL logging functions don't seem to understand long long length modifer. +// This is a workaround. It also prefixes all messages with "WSREP" +#define WSREP_LOG(fun, ...) \ + { \ + char msg[1024] = {'\0'}; \ + snprintf(msg, sizeof(msg) - 1, ## __VA_ARGS__); \ + fun("WSREP: %s", msg); \ + } + +#define WSREP_LOG_CONFLICT_THD(thd, role) \ + WSREP_LOG(sql_print_information, \ + "%s: \n " \ + " THD: %lu, mode: %s, state: %s, conflict: %s, seqno: %lld\n " \ + " SQL: %s", \ + role, wsrep_thd_thread_id(thd), wsrep_thd_exec_mode_str(thd), \ + wsrep_thd_query_state_str(thd), \ + wsrep_thd_conflict_state_str(thd), (long long)wsrep_thd_trx_seqno(thd), \ + wsrep_thd_query(thd) \ + ); + +#define WSREP_LOG_CONFLICT(bf_thd, victim_thd, bf_abort) \ + if (wsrep_debug || wsrep_log_conflicts) \ + { \ + WSREP_LOG(sql_print_information, "cluster conflict due to %s for threads:",\ + (bf_abort) ? "high priority abort" : "certification failure" \ + ); \ + if (bf_thd != NULL) WSREP_LOG_CONFLICT_THD(bf_thd, "Winning thread"); \ + if (victim_thd) WSREP_LOG_CONFLICT_THD(victim_thd, "Victim thread"); \ + } + +#define WSREP_PROVIDER_EXISTS \ + (wsrep_provider && strncasecmp(wsrep_provider, WSREP_NONE, FN_REFLEN)) + +extern void wsrep_ready_wait(); + +enum wsrep_trx_status { + WSREP_TRX_OK, + WSREP_TRX_CERT_FAIL, /* certification failure, must abort */ + WSREP_TRX_SIZE_EXCEEDED, /* trx size exceeded */ + WSREP_TRX_ERROR, /* native mysql error */ +}; + +extern enum wsrep_trx_status +wsrep_run_wsrep_commit(THD *thd, handlerton *hton, bool all); +class Ha_trx_info; +struct THD_TRANS; +void wsrep_register_hton(THD* thd, bool all); +void wsrep_post_commit(THD* thd, bool all); +void wsrep_brute_force_killer(THD *thd); +int wsrep_hire_brute_force_killer(THD *thd, uint64_t trx_id); + +extern "C" bool wsrep_consistency_check(void *thd_ptr); + +/* this is visible for client build so that innodb plugin gets this */ +typedef struct wsrep_aborting_thd { + struct wsrep_aborting_thd *next; + THD *aborting_thd; +} *wsrep_aborting_thd_t; + +extern mysql_mutex_t LOCK_wsrep_ready; +extern mysql_cond_t COND_wsrep_ready; +extern mysql_mutex_t LOCK_wsrep_sst; +extern mysql_cond_t COND_wsrep_sst; +extern mysql_mutex_t LOCK_wsrep_sst_init; +extern mysql_cond_t COND_wsrep_sst_init; +extern mysql_mutex_t LOCK_wsrep_rollback; +extern mysql_cond_t COND_wsrep_rollback; +extern int wsrep_replaying; +extern mysql_mutex_t LOCK_wsrep_replaying; +extern mysql_cond_t COND_wsrep_replaying; +extern mysql_mutex_t LOCK_wsrep_slave_threads; +extern mysql_mutex_t LOCK_wsrep_desync; +extern wsrep_aborting_thd_t wsrep_aborting_thd; +extern my_bool wsrep_emulate_bin_log; +extern int wsrep_to_isolation; +#ifdef GTID_SUPPORT +extern rpl_sidno wsrep_sidno; +#endif /* GTID_SUPPORT */ +extern my_bool wsrep_preordered_opt; +extern handlerton *wsrep_hton; + +#ifdef HAVE_PSI_INTERFACE +extern PSI_mutex_key key_LOCK_wsrep_ready; +extern PSI_mutex_key key_COND_wsrep_ready; +extern PSI_mutex_key key_LOCK_wsrep_sst; +extern PSI_cond_key key_COND_wsrep_sst; +extern PSI_mutex_key key_LOCK_wsrep_sst_init; +extern PSI_cond_key key_COND_wsrep_sst_init; +extern PSI_mutex_key key_LOCK_wsrep_sst_thread; +extern PSI_cond_key key_COND_wsrep_sst_thread; +extern PSI_mutex_key key_LOCK_wsrep_rollback; +extern PSI_cond_key key_COND_wsrep_rollback; +extern PSI_mutex_key key_LOCK_wsrep_replaying; +extern PSI_cond_key key_COND_wsrep_replaying; +extern PSI_mutex_key key_LOCK_wsrep_slave_threads; +extern PSI_mutex_key key_LOCK_wsrep_desync; +#endif /* HAVE_PSI_INTERFACE */ +struct TABLE_LIST; +int wsrep_to_isolation_begin(THD *thd, char *db_, char *table_, + const TABLE_LIST* table_list); +void wsrep_to_isolation_end(THD *thd); +void wsrep_cleanup_transaction(THD *thd); +int wsrep_to_buf_helper( + THD* thd, const char *query, uint query_len, uchar** buf, size_t* buf_len); +int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len); +int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len); +int wsrep_create_event_query(THD *thd, uchar** buf, size_t* buf_len); +int wsrep_alter_event_query(THD *thd, uchar** buf, size_t* buf_len); + +struct xid_t; +void wsrep_get_SE_checkpoint(xid_t*); +void wsrep_set_SE_checkpoint(xid_t*); +void wsrep_init_sidno(const wsrep_uuid_t&); +void wsrep_xid_init(xid_t*, const wsrep_uuid_t*, wsrep_seqno_t); +const wsrep_uuid_t* wsrep_xid_uuid(const xid_t*); +wsrep_seqno_t wsrep_xid_seqno(const xid_t*); +extern "C" int wsrep_is_wsrep_xid(const void* xid); + +extern "C" my_thread_id wsrep_thd_thread_id(THD *thd); +extern "C" char *wsrep_thd_query(THD *thd); + +extern bool +wsrep_grant_mdl_exception(MDL_context *requestor_ctx, + MDL_ticket *ticket); +IO_CACHE * get_trans_log(THD * thd); +bool wsrep_trans_cache_is_empty(THD *thd); +void thd_binlog_flush_pending_rows_event(THD *thd, bool stmt_end); +void thd_binlog_rollback_stmt(THD * thd); +void thd_binlog_trx_reset(THD * thd); + +typedef void (*wsrep_thd_processor_fun)(THD *); +pthread_handler_t start_wsrep_THD(void *arg); +int wsrep_wait_committing_connections_close(int wait_time); +void wsrep_close_client_connections(my_bool wait_to_end); +void wsrep_close_applier(THD *thd); +void wsrep_close_applier_threads(int count); +void wsrep_wait_appliers_close(THD *thd); +void wsrep_kill_mysql(THD *thd); +void wsrep_close_threads(THD *thd); +int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len); +my_bool wsrep_read_only_option(THD *thd, TABLE_LIST *all_tables); +void wsrep_copy_query(THD *thd); +bool wsrep_is_show_query(enum enum_sql_command command); +void wsrep_replay_transaction(THD *thd); +bool wsrep_create_like_table(THD* thd, TABLE_LIST* table, + TABLE_LIST* src_table, + HA_CREATE_INFO *create_info); +int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len); + +extern my_bool deny_updates_if_read_only_option(THD *thd, + TABLE_LIST *all_tables); +#endif /* WSREP_MYSQLD_H */ diff --git a/sql/wsrep_notify.cc b/sql/wsrep_notify.cc new file mode 100644 index 00000000000..6eefb961b62 --- /dev/null +++ b/sql/wsrep_notify.cc @@ -0,0 +1,111 @@ +/* Copyright 2010 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include +#include "wsrep_priv.h" +#include "wsrep_utils.h" + +const char* wsrep_notify_cmd=""; + +static const char* _status_str(wsrep_member_status_t status) +{ + switch (status) + { + case WSREP_MEMBER_UNDEFINED: return "Undefined"; + case WSREP_MEMBER_JOINER: return "Joiner"; + case WSREP_MEMBER_DONOR: return "Donor"; + case WSREP_MEMBER_JOINED: return "Joined"; + case WSREP_MEMBER_SYNCED: return "Synced"; + default: return "Error(?)"; + } +} + +void wsrep_notify_status (wsrep_member_status_t status, + const wsrep_view_info_t* view) +{ + if (!wsrep_notify_cmd || 0 == strlen(wsrep_notify_cmd)) + { + WSREP_INFO("wsrep_notify_cmd is not defined, skipping notification."); + return; + } + + char cmd_buf[1 << 16]; // this can be long + long cmd_len = sizeof(cmd_buf) - 1; + char* cmd_ptr = cmd_buf; + long cmd_off = 0; + + cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off, "%s", + wsrep_notify_cmd); + + if (status >= WSREP_MEMBER_UNDEFINED && status < WSREP_MEMBER_ERROR) + { + cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off, " --status %s", + _status_str(status)); + } + else + { + /* here we preserve provider error codes */ + cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off, + " --status 'Error(%d)'", status); + } + + if (0 != view) + { + char uuid_str[40]; + + wsrep_uuid_print (&view->state_id.uuid, uuid_str, sizeof(uuid_str)); + cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off, + " --uuid %s", uuid_str); + + cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off, + " --primary %s", view->view >= 0 ? "yes" : "no"); + + cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off, + " --index %d", view->my_idx); + + if (view->memb_num) + { + cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off, " --members"); + + for (int i = 0; i < view->memb_num; i++) + { + wsrep_uuid_print (&view->members[i].id, uuid_str, sizeof(uuid_str)); + cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off, + "%c%s/%s/%s", i > 0 ? ',' : ' ', + uuid_str, view->members[i].name, + view->members[i].incoming); + } + } + } + + if (cmd_off == cmd_len) + { + WSREP_ERROR("Notification buffer too short (%ld). Aborting notification.", + cmd_len); + return; + } + + wsp::process p(cmd_ptr, "r"); + + p.wait(); + int err = p.error(); + + if (err) + { + WSREP_ERROR("Notification command failed: %d (%s): \"%s\"", + err, strerror(err), cmd_ptr); + } +} + diff --git a/sql/wsrep_priv.h b/sql/wsrep_priv.h new file mode 100644 index 00000000000..5c66587d757 --- /dev/null +++ b/sql/wsrep_priv.h @@ -0,0 +1,53 @@ +/* Copyright 2010 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//! @file declares symbols private to wsrep integration layer + +#ifndef WSREP_PRIV_H +#define WSREP_PRIV_H + +#include "wsrep_mysqld.h" +#include "../wsrep/wsrep_api.h" + +#include +#include +#include + +void wsrep_ready_set (my_bool x); + +ssize_t wsrep_sst_prepare (void** msg); +wsrep_cb_status wsrep_sst_donate_cb (void* app_ctx, + void* recv_ctx, + const void* msg, size_t msg_len, + const wsrep_gtid_t* current_id, + const char* state, size_t state_len, + bool bypass); +extern unsigned int wsrep_check_ip (const char* addr); +extern size_t wsrep_guess_ip (char* buf, size_t buf_len); +extern size_t wsrep_guess_address(char* buf, size_t buf_len); + +extern wsrep_uuid_t local_uuid; +extern wsrep_seqno_t local_seqno; + +// a helper function +extern void wsrep_sst_received(wsrep_t*, const wsrep_uuid_t*, wsrep_seqno_t, + const void*, size_t); +/*! SST thread signals init thread about sst completion */ +extern void wsrep_sst_complete(const wsrep_uuid_t*, wsrep_seqno_t, bool); + +void wsrep_notify_status (wsrep_member_status_t new_status, + const wsrep_view_info_t* view = 0); +#endif /* WSREP_PRIV_H */ diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc new file mode 100644 index 00000000000..c122d88f7cc --- /dev/null +++ b/sql/wsrep_sst.cc @@ -0,0 +1,1127 @@ +/* Copyright 2008-2012 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "wsrep_sst.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wsrep_priv.h" +#include "wsrep_utils.h" +#include +#include + +extern const char wsrep_defaults_file[]; + +const char* wsrep_sst_method = WSREP_SST_DEFAULT; +const char* wsrep_sst_receive_address = WSREP_SST_ADDRESS_AUTO; +const char* wsrep_sst_donor = ""; + char* wsrep_sst_auth = NULL; + +// container for real auth string +static const char* sst_auth_real = NULL; +my_bool wsrep_sst_donor_rejects_queries = FALSE; + +bool wsrep_sst_method_check (sys_var *self, THD* thd, set_var* var) +{ + if ((! var->save_result.string_value.str) || + (var->save_result.string_value.length == 0 )) + { + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, + var->save_result.string_value.str ? + var->save_result.string_value.str : "NULL"); + return 1; + } + + return 0; +} + +bool wsrep_sst_method_update (sys_var *self, THD* thd, enum_var_type type) +{ + return 0; +} + +// TODO: Improve address verification. +static bool sst_receive_address_check (const char* str) +{ + if (!strncasecmp(str, "127.0.0.1", strlen("127.0.0.1")) || + !strncasecmp(str, "localhost", strlen("localhost"))) + { + return 1; + } + + return 0; +} + +bool wsrep_sst_receive_address_check (sys_var *self, THD* thd, set_var* var) +{ + char addr_buf[FN_REFLEN]; + + if ((! var->save_result.string_value.str) || + (var->save_result.string_value.length > (FN_REFLEN - 1))) // safety + { + goto err; + } + + memcpy(addr_buf, var->save_result.string_value.str, + var->save_result.string_value.length); + addr_buf[var->save_result.string_value.length]= 0; + + if (sst_receive_address_check(addr_buf)) + { + goto err; + } + + return 0; + +err: + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, + var->save_result.string_value.str ? + var->save_result.string_value.str : "NULL"); + return 1; +} + +bool wsrep_sst_receive_address_update (sys_var *self, THD* thd, + enum_var_type type) +{ + return 0; +} + +bool wsrep_sst_auth_check (sys_var *self, THD* thd, set_var* var) +{ + return 0; +} + +static bool sst_auth_real_set (const char* value) +{ + const char* v= NULL; + + if (value) + { + v= my_strdup(value, MYF(0)); + } + else // its NULL + { + wsrep_sst_auth_free(); + return 0; + } + + if (v) + { + // set sst_auth_real + if (sst_auth_real) { my_free((void *) sst_auth_real); } + sst_auth_real = v; + + // mask wsrep_sst_auth + if (strlen(sst_auth_real)) + { + if (wsrep_sst_auth) { my_free((void*) wsrep_sst_auth); } + wsrep_sst_auth= my_strdup(WSREP_SST_AUTH_MASK, MYF(0)); + } + return 0; + } + return 1; +} + +void wsrep_sst_auth_free() +{ + if (wsrep_sst_auth) { my_free((void *) wsrep_sst_auth); } + if (sst_auth_real) { my_free((void *) sst_auth_real); } + wsrep_sst_auth= NULL; + sst_auth_real= NULL; +} + +bool wsrep_sst_auth_update (sys_var *self, THD* thd, enum_var_type type) +{ + return sst_auth_real_set (wsrep_sst_auth); +} + +void wsrep_sst_auth_init (const char* value) +{ + if (wsrep_sst_auth == value) wsrep_sst_auth = NULL; + if (value) sst_auth_real_set (value); +} + +bool wsrep_sst_donor_check (sys_var *self, THD* thd, set_var* var) +{ + return 0; +} + +bool wsrep_sst_donor_update (sys_var *self, THD* thd, enum_var_type type) +{ + return 0; +} + +static wsrep_uuid_t cluster_uuid = WSREP_UUID_UNDEFINED; + +bool wsrep_before_SE() +{ + return (wsrep_provider != NULL + && strcmp (wsrep_provider, WSREP_NONE) + && strcmp (wsrep_sst_method, WSREP_SST_SKIP) + && strcmp (wsrep_sst_method, WSREP_SST_MYSQLDUMP)); +} + +static bool sst_complete = false; +static bool sst_needed = false; + +void wsrep_sst_grab () +{ + WSREP_INFO("wsrep_sst_grab()"); + if (mysql_mutex_lock (&LOCK_wsrep_sst)) abort(); + sst_complete = false; + mysql_mutex_unlock (&LOCK_wsrep_sst); +} + +// Wait for end of SST +bool wsrep_sst_wait () +{ + if (mysql_mutex_lock (&LOCK_wsrep_sst)) abort(); + while (!sst_complete) + { + WSREP_INFO("Waiting for SST to complete."); + mysql_cond_wait (&COND_wsrep_sst, &LOCK_wsrep_sst); + } + + if (local_seqno >= 0) + { + WSREP_INFO("SST complete, seqno: %lld", (long long) local_seqno); + } + else + { + WSREP_ERROR("SST failed: %d (%s)", + int(-local_seqno), strerror(-local_seqno)); + } + + mysql_mutex_unlock (&LOCK_wsrep_sst); + + return (local_seqno >= 0); +} + +// Signal end of SST +void wsrep_sst_complete (const wsrep_uuid_t* sst_uuid, + wsrep_seqno_t sst_seqno, + bool needed) +{ + if (mysql_mutex_lock (&LOCK_wsrep_sst)) abort(); + if (!sst_complete) + { + sst_complete = true; + sst_needed = needed; + local_uuid = *sst_uuid; + local_seqno = sst_seqno; + mysql_cond_signal (&COND_wsrep_sst); + } + else + { + /* This can happen when called from wsrep_synced_cb(). + At the moment there is no way to check there + if main thread is still waiting for signal, + so wsrep_sst_complete() is called from there + each time wsrep_ready changes from FALSE -> TRUE. + */ + WSREP_DEBUG("Nobody is waiting for SST."); + } + mysql_mutex_unlock (&LOCK_wsrep_sst); +} + +void wsrep_sst_received (wsrep_t* const wsrep, + const wsrep_uuid_t* const uuid, + wsrep_seqno_t const seqno, + const void* const state, + size_t const state_len) +{ + int const rcode(seqno < 0 ? seqno : 0); + wsrep_gtid_t const state_id = { + *uuid, (rcode ? WSREP_SEQNO_UNDEFINED : seqno) + }; +#ifdef GTID_SUPPORT + wsrep_init_sidno(state_id.uuid); +#endif /* GTID_SUPPORT */ + wsrep->sst_received(wsrep, &state_id, state, state_len, rcode); +} + +// Let applier threads to continue +void wsrep_sst_continue () +{ + if (sst_needed) + { + WSREP_INFO("Signalling provider to continue."); + wsrep_sst_received (wsrep, &local_uuid, local_seqno, NULL, 0); + } +} + +struct sst_thread_arg +{ + const char* cmd; + int err; + char* ret_str; + mysql_mutex_t lock; + mysql_cond_t cond; + + sst_thread_arg (const char* c) : cmd(c), err(-1), ret_str(0) + { + mysql_mutex_init(key_LOCK_wsrep_sst_thread, &lock, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_wsrep_sst_thread, &cond, NULL); + } + + ~sst_thread_arg() + { + mysql_cond_destroy (&cond); + mysql_mutex_unlock (&lock); + mysql_mutex_destroy (&lock); + } +}; + +static int sst_scan_uuid_seqno (const char* str, + wsrep_uuid_t* uuid, wsrep_seqno_t* seqno) +{ + int offt = wsrep_uuid_scan (str, strlen(str), uuid); + if (offt > 0 && strlen(str) > (unsigned int)offt && ':' == str[offt]) + { + *seqno = strtoll (str + offt + 1, NULL, 10); + if (*seqno != LLONG_MAX || errno != ERANGE) + { + return 0; + } + } + + WSREP_ERROR("Failed to parse uuid:seqno pair: '%s'", str); + return EINVAL; +} + +// get rid of trailing \n +static char* my_fgets (char* buf, size_t buf_len, FILE* stream) +{ + char* ret= fgets (buf, buf_len, stream); + + if (ret) + { + size_t len = strlen(ret); + if (len > 0 && ret[len - 1] == '\n') ret[len - 1] = '\0'; + } + + return ret; +} + +/* + Generate opt_binlog_opt_val for sst_donate_other(), sst_prepare_other(). + + Returns zero on success, negative error code otherwise. + + String containing binlog name is stored in param ret if binlog is enabled + and GTID mode is on, otherwise empty string. Returned string should be + freed with my_free(). + */ +static int generate_binlog_opt_val(char** ret) +{ + DBUG_ASSERT(ret); + *ret= NULL; + if (opt_bin_log) + { + assert(opt_bin_logname); + *ret= strcmp(opt_bin_logname, "0") ? + my_strdup(opt_bin_logname, MYF(0)) : my_strdup("", MYF(0)); + } + else + { + *ret= my_strdup("", MYF(0)); + } + if (!*ret) return -ENOMEM; + return 0; +} + +static void* sst_joiner_thread (void* a) +{ + sst_thread_arg* arg= (sst_thread_arg*) a; + int err= 1; + + { + const char magic[] = "ready"; + const size_t magic_len = sizeof(magic) - 1; + const size_t out_len = 512; + char out[out_len]; + + WSREP_INFO("Running: '%s'", arg->cmd); + + wsp::process proc (arg->cmd, "r"); + + if (proc.pipe() && !proc.error()) + { + const char* tmp= my_fgets (out, out_len, proc.pipe()); + + if (!tmp || strlen(tmp) < (magic_len + 2) || + strncasecmp (tmp, magic, magic_len)) + { + WSREP_ERROR("Failed to read '%s ' from: %s\n\tRead: '%s'", + magic, arg->cmd, tmp); + proc.wait(); + if (proc.error()) err = proc.error(); + } + else + { + err = 0; + } + } + else + { + err = proc.error(); + WSREP_ERROR("Failed to execute: %s : %d (%s)", + arg->cmd, err, strerror(err)); + } + + // signal sst_prepare thread with ret code, + // it will go on sending SST request + mysql_mutex_lock (&arg->lock); + if (!err) + { + arg->ret_str = strdup (out + magic_len + 1); + if (!arg->ret_str) err = ENOMEM; + } + arg->err = -err; + mysql_cond_signal (&arg->cond); + mysql_mutex_unlock (&arg->lock); //! @note arg is unusable after that. + + if (err) return NULL; /* lp:808417 - return immediately, don't signal + * initializer thread to ensure single thread of + * shutdown. */ + + wsrep_uuid_t ret_uuid = WSREP_UUID_UNDEFINED; + wsrep_seqno_t ret_seqno = WSREP_SEQNO_UNDEFINED; + + // in case of successfull receiver start, wait for SST completion/end + char* tmp = my_fgets (out, out_len, proc.pipe()); + + proc.wait(); + err= EINVAL; + + if (!tmp) + { + WSREP_ERROR("Failed to read uuid:seqno from joiner script."); + if (proc.error()) err = proc.error(); + } + else + { + err= sst_scan_uuid_seqno (out, &ret_uuid, &ret_seqno); + } + + if (err) + { + ret_uuid= WSREP_UUID_UNDEFINED; + ret_seqno= -err; + } + + // Tell initializer thread that SST is complete + wsrep_sst_complete (&ret_uuid, ret_seqno, true); + } + + return NULL; +} + +static ssize_t sst_prepare_other (const char* method, + const char* addr_in, + const char** addr_out) +{ + ssize_t cmd_len= 1024; + char cmd_str[cmd_len]; + const char* sst_dir= mysql_real_data_home; + const char* binlog_opt= ""; + char* binlog_opt_val= NULL; + + int ret; + if ((ret= generate_binlog_opt_val(&binlog_opt_val))) + { + WSREP_ERROR("sst_prepare_other(): generate_binlog_opt_val() failed: %d", + ret); + return ret; + } + if (strlen(binlog_opt_val)) binlog_opt= WSREP_SST_OPT_BINLOG; + + + ret= snprintf (cmd_str, cmd_len, + "wsrep_sst_%s " + WSREP_SST_OPT_ROLE" 'joiner' " + WSREP_SST_OPT_ADDR" '%s' " + WSREP_SST_OPT_AUTH" '%s' " + WSREP_SST_OPT_DATA" '%s' " + WSREP_SST_OPT_CONF" '%s' " + WSREP_SST_OPT_PARENT" '%d'" + " %s '%s' ", + method, addr_in, (sst_auth_real) ? sst_auth_real : "", + sst_dir, wsrep_defaults_file, (int)getpid(), + binlog_opt, binlog_opt_val); + my_free(binlog_opt_val); + + if (ret < 0 || ret >= cmd_len) + { + WSREP_ERROR("sst_prepare_other(): snprintf() failed: %d", ret); + return (ret < 0 ? ret : -EMSGSIZE); + } + + pthread_t tmp; + sst_thread_arg arg(cmd_str); + mysql_mutex_lock (&arg.lock); + ret = pthread_create (&tmp, NULL, sst_joiner_thread, &arg); + if (ret) + { + WSREP_ERROR("sst_prepare_other(): pthread_create() failed: %d (%s)", + ret, strerror(ret)); + return ret; + } + mysql_cond_wait (&arg.cond, &arg.lock); + + *addr_out= arg.ret_str; + + if (!arg.err) + ret = strlen(*addr_out); + else + { + assert (arg.err < 0); + ret = arg.err; + } + + pthread_detach (tmp); + + return ret; +} + +extern uint mysqld_port; + +/*! Just tells donor where to send mysqldump */ +static ssize_t sst_prepare_mysqldump (const char* addr_in, + const char** addr_out) +{ + ssize_t ret = strlen (addr_in); + + if (!strrchr(addr_in, ':')) + { + ssize_t s = ret + 7; + char* tmp = (char*) malloc (s); + + if (tmp) + { + ret= snprintf (tmp, s, "%s:%u", addr_in, mysqld_port); + + if (ret > 0 && ret < s) + { + *addr_out= tmp; + return ret; + } + if (ret > 0) /* buffer too short */ ret = -EMSGSIZE; + free (tmp); + } + else { + ret= -ENOMEM; + } + + WSREP_ERROR ("Could not prepare state transfer request: " + "adding default port failed: %zd.", ret); + } + else { + *addr_out= addr_in; + } + + return ret; +} + +static bool SE_initialized = false; + +ssize_t wsrep_sst_prepare (void** msg) +{ + const ssize_t ip_max= 256; + char ip_buf[ip_max]; + const char* addr_in= NULL; + const char* addr_out= NULL; + + if (!strcmp(wsrep_sst_method, WSREP_SST_SKIP)) + { + ssize_t ret = strlen(WSREP_STATE_TRANSFER_TRIVIAL) + 1; + *msg = strdup(WSREP_STATE_TRANSFER_TRIVIAL); + if (!msg) + { + WSREP_ERROR("Could not allocate %zd bytes for state request", ret); + unireg_abort(1); + } + return ret; + } + + // Figure out SST address. Common for all SST methods + if (wsrep_sst_receive_address && + strcmp (wsrep_sst_receive_address, WSREP_SST_ADDRESS_AUTO)) + { + addr_in= wsrep_sst_receive_address; + } + else if (wsrep_node_address && strlen(wsrep_node_address)) + { + const char* const colon= strchr (wsrep_node_address, ':'); + if (colon) + { + ptrdiff_t const len= colon - wsrep_node_address; + strncpy (ip_buf, wsrep_node_address, len); + ip_buf[len]= '\0'; + addr_in= ip_buf; + } + else + { + addr_in= wsrep_node_address; + } + } + else + { + ssize_t ret= wsrep_guess_ip (ip_buf, ip_max); + + if (ret && ret < ip_max) + { + addr_in= ip_buf; + } + else + { + WSREP_ERROR("Could not prepare state transfer request: " + "failed to guess address to accept state transfer at. " + "wsrep_sst_receive_address must be set manually."); + unireg_abort(1); + } + } + + ssize_t addr_len= -ENOSYS; + if (!strcmp(wsrep_sst_method, WSREP_SST_MYSQLDUMP)) + { + addr_len= sst_prepare_mysqldump (addr_in, &addr_out); + if (addr_len < 0) unireg_abort(1); + } + else + { + /*! A heuristic workaround until we learn how to stop and start engines */ + if (SE_initialized) + { + // we already did SST at initializaiton, now engines are running + // sql_print_information() is here because the message is too long + // for WSREP_INFO. + sql_print_information ("WSREP: " + "You have configured '%s' state snapshot transfer method " + "which cannot be performed on a running server. " + "Wsrep provider won't be able to fall back to it " + "if other means of state transfer are unavailable. " + "In that case you will need to restart the server.", + wsrep_sst_method); + *msg = 0; + return 0; + } + + addr_len = sst_prepare_other (wsrep_sst_method, addr_in, &addr_out); + if (addr_len < 0) + { + WSREP_ERROR("Failed to prepare for '%s' SST. Unrecoverable.", + wsrep_sst_method); + unireg_abort(1); + } + } + + size_t const method_len(strlen(wsrep_sst_method)); + size_t const msg_len (method_len + addr_len + 2 /* + auth_len + 1*/); + + *msg = malloc (msg_len); + if (NULL != *msg) { + char* const method_ptr(reinterpret_cast(*msg)); + strcpy (method_ptr, wsrep_sst_method); + char* const addr_ptr(method_ptr + method_len + 1); + strcpy (addr_ptr, addr_out); + + WSREP_INFO ("Prepared SST request: %s|%s", method_ptr, addr_ptr); + } + else { + WSREP_ERROR("Failed to allocate SST request of size %zu. Can't continue.", + msg_len); + unireg_abort(1); + } + + if (addr_out != addr_in) /* malloc'ed */ free ((char*)addr_out); + + return msg_len; +} + +// helper method for donors +static int sst_run_shell (const char* cmd_str, int max_tries) +{ + int ret = 0; + + for (int tries=1; tries <= max_tries; tries++) + { + wsp::process proc (cmd_str, "r"); + + if (NULL != proc.pipe()) + { + proc.wait(); + } + + if ((ret = proc.error())) + { + WSREP_ERROR("Try %d/%d: '%s' failed: %d (%s)", + tries, max_tries, proc.cmd(), ret, strerror(ret)); + sleep (1); + } + else + { + WSREP_DEBUG("SST script successfully completed."); + break; + } + } + + return -ret; +} + +static void sst_reject_queries(my_bool close_conn) +{ + wsrep_ready_set (FALSE); // this will be resotred when donor becomes synced + WSREP_INFO("Rejecting client queries for the duration of SST."); + if (TRUE == close_conn) wsrep_close_client_connections(FALSE); +} + +static int sst_mysqldump_check_addr (const char* user, const char* pswd, + const char* host, const char* port) +{ + return 0; +} + +static int sst_donate_mysqldump (const char* addr, + const wsrep_uuid_t* uuid, + const char* uuid_str, + wsrep_seqno_t seqno, + bool bypass) +{ + size_t host_len; + const char* port = strchr (addr, ':'); + + if (port) + { + port += 1; + host_len = port - addr; + } + else + { + port = ""; + host_len = strlen (addr) + 1; + } + + char host[host_len]; + + strncpy (host, addr, host_len - 1); + host[host_len - 1] = '\0'; + + const char* auth = sst_auth_real; + const char* pswd = (auth) ? strchr (auth, ':') : NULL; + size_t user_len; + + if (pswd) + { + pswd += 1; + user_len = pswd - auth; + } + else + { + pswd = ""; + user_len = (auth) ? strlen (auth) + 1 : 1; + } + + char user[user_len]; + + strncpy (user, (auth) ? auth : "", user_len - 1); + user[user_len - 1] = '\0'; + + int ret = sst_mysqldump_check_addr (user, pswd, host, port); + if (!ret) + { + size_t cmd_len= 1024; + char cmd_str[cmd_len]; + + if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(TRUE); + + snprintf (cmd_str, cmd_len, + "wsrep_sst_mysqldump " + WSREP_SST_OPT_USER" '%s' " + WSREP_SST_OPT_PSWD" '%s' " + WSREP_SST_OPT_HOST" '%s' " + WSREP_SST_OPT_PORT" '%s' " + WSREP_SST_OPT_LPORT" '%u' " + WSREP_SST_OPT_SOCKET" '%s' " + WSREP_SST_OPT_CONF" '%s' " + WSREP_SST_OPT_GTID" '%s:%lld'" + "%s", + user, pswd, host, port, mysqld_port, mysqld_unix_port, + wsrep_defaults_file, uuid_str, + (long long)seqno, bypass ? " "WSREP_SST_OPT_BYPASS : ""); + + WSREP_DEBUG("Running: '%s'", cmd_str); + + ret= sst_run_shell (cmd_str, 3); + } + + wsrep_gtid_t const state_id = { *uuid, (ret ? WSREP_SEQNO_UNDEFINED : seqno)}; + + wsrep->sst_sent (wsrep, &state_id, ret); + + return ret; +} + +wsrep_seqno_t wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED; + +static int run_sql_command(THD *thd, const char *query) +{ + thd->set_query((char *)query, strlen(query)); + + Parser_state ps; + if (ps.init(thd, thd->query(), thd->query_length())) + { + WSREP_ERROR("SST query: %s failed", query); + return -1; + } + + mysql_parse(thd, thd->query(), thd->query_length(), &ps); + if (thd->is_error()) + { + int const err= thd->get_stmt_da()->sql_errno(); + WSREP_WARN ("error executing '%s': %d (%s)%s", + query, err, thd->get_stmt_da()->message(), + err == ER_UNKNOWN_SYSTEM_VARIABLE ? + ". Was mysqld built with --with-innodb-disallow-writes ?" : ""); + thd->clear_error(); + return -1; + } + return 0; +} + +static int sst_flush_tables(THD* thd) +{ + WSREP_INFO("Flushing tables for SST..."); + + int err; + int not_used; + CHARSET_INFO *current_charset; + + current_charset = thd->variables.character_set_client; + + if (!is_supported_parser_charset(current_charset)) + { + /* Do not use non-supported parser character sets */ + WSREP_WARN("Current client character set is non-supported parser character set: %s", current_charset->csname); + thd->variables.character_set_client = &my_charset_latin1; + WSREP_WARN("For SST temporally setting character set to : %s", + my_charset_latin1.csname); + } + + if (run_sql_command(thd, "FLUSH TABLES WITH READ LOCK")) + { + WSREP_ERROR("Failed to flush and lock tables"); + err = -1; + } + else + { + /* make sure logs are flushed after global read lock acquired */ + err= reload_acl_and_cache(thd, REFRESH_ENGINE_LOG | REFRESH_BINARY_LOG, + (TABLE_LIST*) 0, ¬_used); + } + + thd->variables.character_set_client = current_charset; + + + if (err) + { + WSREP_ERROR("Failed to flush tables: %d (%s)", err, strerror(err)); + } + else + { + WSREP_INFO("Tables flushed."); + const char base_name[]= "tables_flushed"; + ssize_t const full_len= strlen(mysql_real_data_home) + strlen(base_name)+2; + char real_name[full_len]; + sprintf(real_name, "%s/%s", mysql_real_data_home, base_name); + char tmp_name[full_len + 4]; + sprintf(tmp_name, "%s.tmp", real_name); + + FILE* file= fopen(tmp_name, "w+"); + if (0 == file) + { + err= errno; + WSREP_ERROR("Failed to open '%s': %d (%s)", tmp_name, err,strerror(err)); + } + else + { + fprintf(file, "%s:%lld\n", + wsrep_cluster_state_uuid, (long long)wsrep_locked_seqno); + fsync(fileno(file)); + fclose(file); + if (rename(tmp_name, real_name) == -1) + { + err= errno; + WSREP_ERROR("Failed to rename '%s' to '%s': %d (%s)", + tmp_name, real_name, err,strerror(err)); + } + } + } + + return err; +} + +static void sst_disallow_writes (THD* thd, bool yes) +{ + char query_str[64] = { 0, }; + ssize_t const query_max = sizeof(query_str) - 1; + CHARSET_INFO *current_charset; + + current_charset = thd->variables.character_set_client; + + if (!is_supported_parser_charset(current_charset)) + { + /* Do not use non-supported parser character sets */ + WSREP_WARN("Current client character set is non-supported parser character set: %s", current_charset->csname); + thd->variables.character_set_client = &my_charset_latin1; + WSREP_WARN("For SST temporally setting character set to : %s", + my_charset_latin1.csname); + } + + snprintf (query_str, query_max, "SET GLOBAL innodb_disallow_writes=%d", + yes ? 1 : 0); + + if (run_sql_command(thd, query_str)) + { + WSREP_ERROR("Failed to disallow InnoDB writes"); + } + thd->variables.character_set_client = current_charset; +} + +static void* sst_donor_thread (void* a) +{ + sst_thread_arg* arg= (sst_thread_arg*)a; + + WSREP_INFO("Running: '%s'", arg->cmd); + + int err= 1; + bool locked= false; + + const char* out= NULL; + const size_t out_len= 128; + char out_buf[out_len]; + + wsrep_uuid_t ret_uuid= WSREP_UUID_UNDEFINED; + wsrep_seqno_t ret_seqno= WSREP_SEQNO_UNDEFINED; // seqno of complete SST + + wsp::thd thd(FALSE); // we turn off wsrep_on for this THD so that it can + // operate with wsrep_ready == OFF + wsp::process proc(arg->cmd, "r"); + + err= proc.error(); + +/* Inform server about SST script startup and release TO isolation */ + mysql_mutex_lock (&arg->lock); + arg->err = -err; + mysql_cond_signal (&arg->cond); + mysql_mutex_unlock (&arg->lock); //! @note arg is unusable after that. + + if (proc.pipe() && !err) + { +wait_signal: + out= my_fgets (out_buf, out_len, proc.pipe()); + + if (out) + { + const char magic_flush[]= "flush tables"; + const char magic_cont[]= "continue"; + const char magic_done[]= "done"; + + if (!strcasecmp (out, magic_flush)) + { + err= sst_flush_tables (thd.ptr); + if (!err) + { + sst_disallow_writes (thd.ptr, true); + locked= true; + goto wait_signal; + } + } + else if (!strcasecmp (out, magic_cont)) + { + if (locked) + { + sst_disallow_writes (thd.ptr, false); + thd.ptr->global_read_lock.unlock_global_read_lock (thd.ptr); + locked= false; + } + err= 0; + goto wait_signal; + } + else if (!strncasecmp (out, magic_done, strlen(magic_done))) + { + err= sst_scan_uuid_seqno (out + strlen(magic_done) + 1, + &ret_uuid, &ret_seqno); + } + else + { + WSREP_WARN("Received unknown signal: '%s'", out); + } + } + else + { + WSREP_ERROR("Failed to read from: %s", proc.cmd()); + proc.wait(); + } + if (!err && proc.error()) err= proc.error(); + } + else + { + WSREP_ERROR("Failed to execute: %s : %d (%s)", + proc.cmd(), err, strerror(err)); + } + + if (locked) // don't forget to unlock server before return + { + sst_disallow_writes (thd.ptr, false); + thd.ptr->global_read_lock.unlock_global_read_lock (thd.ptr); + } + + // signal to donor that SST is over + struct wsrep_gtid const state_id = { + ret_uuid, err ? WSREP_SEQNO_UNDEFINED : ret_seqno + }; + wsrep->sst_sent (wsrep, &state_id, -err); + proc.wait(); + + return NULL; +} + + + +static int sst_donate_other (const char* method, + const char* addr, + const char* uuid, + wsrep_seqno_t seqno, + bool bypass) +{ + ssize_t cmd_len = 4096; + char cmd_str[cmd_len]; + const char* binlog_opt= ""; + char* binlog_opt_val= NULL; + + int ret; + if ((ret= generate_binlog_opt_val(&binlog_opt_val))) + { + WSREP_ERROR("sst_donate_other(): generate_binlog_opt_val() failed: %d",ret); + return ret; + } + if (strlen(binlog_opt_val)) binlog_opt= WSREP_SST_OPT_BINLOG; + + ret= snprintf (cmd_str, cmd_len, + "wsrep_sst_%s " + WSREP_SST_OPT_ROLE" 'donor' " + WSREP_SST_OPT_ADDR" '%s' " + WSREP_SST_OPT_AUTH" '%s' " + WSREP_SST_OPT_SOCKET" '%s' " + WSREP_SST_OPT_DATA" '%s' " + WSREP_SST_OPT_CONF" '%s' " + " %s '%s' " + WSREP_SST_OPT_GTID" '%s:%lld'" + "%s", + method, addr, sst_auth_real, mysqld_unix_port, + mysql_real_data_home, wsrep_defaults_file, + binlog_opt, binlog_opt_val, + uuid, (long long) seqno, + bypass ? " "WSREP_SST_OPT_BYPASS : ""); + my_free(binlog_opt_val); + + if (ret < 0 || ret >= cmd_len) + { + WSREP_ERROR("sst_donate_other(): snprintf() failed: %d", ret); + return (ret < 0 ? ret : -EMSGSIZE); + } + + if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(FALSE); + + pthread_t tmp; + sst_thread_arg arg(cmd_str); + mysql_mutex_lock (&arg.lock); + ret = pthread_create (&tmp, NULL, sst_donor_thread, &arg); + if (ret) + { + WSREP_ERROR("sst_donate_other(): pthread_create() failed: %d (%s)", + ret, strerror(ret)); + return ret; + } + mysql_cond_wait (&arg.cond, &arg.lock); + + WSREP_INFO("sst_donor_thread signaled with %d", arg.err); + return arg.err; +} + +wsrep_cb_status_t wsrep_sst_donate_cb (void* app_ctx, void* recv_ctx, + const void* msg, size_t msg_len, + const wsrep_gtid_t* current_gtid, + const char* state, size_t state_len, + bool bypass) +{ + /* This will be reset when sync callback is called. + * Should we set wsrep_ready to FALSE here too? */ +// wsrep_notify_status(WSREP_MEMBER_DONOR); + local_status.set(WSREP_MEMBER_DONOR); + + const char* method = (char*)msg; + size_t method_len = strlen (method); + const char* data = method + method_len + 1; + + char uuid_str[37]; + wsrep_uuid_print (¤t_gtid->uuid, uuid_str, sizeof(uuid_str)); + + int ret; + if (!strcmp (WSREP_SST_MYSQLDUMP, method)) + { + ret = sst_donate_mysqldump(data, ¤t_gtid->uuid, uuid_str, + current_gtid->seqno, bypass); + } + else + { + ret = sst_donate_other(method, data, uuid_str, current_gtid->seqno,bypass); + } + + return (ret > 0 ? WSREP_CB_SUCCESS : WSREP_CB_FAILURE); +} + +void wsrep_SE_init_grab() +{ + if (mysql_mutex_lock (&LOCK_wsrep_sst_init)) abort(); +} + +void wsrep_SE_init_wait() +{ + while (SE_initialized == false) + { + mysql_cond_wait (&COND_wsrep_sst_init, &LOCK_wsrep_sst_init); + } + mysql_mutex_unlock (&LOCK_wsrep_sst_init); +} + +void wsrep_SE_init_done() +{ + mysql_cond_signal (&COND_wsrep_sst_init); + mysql_mutex_unlock (&LOCK_wsrep_sst_init); +} + +void wsrep_SE_initialized() +{ + SE_initialized = true; +} diff --git a/sql/wsrep_sst.h b/sql/wsrep_sst.h new file mode 100644 index 00000000000..d85fed97fca --- /dev/null +++ b/sql/wsrep_sst.h @@ -0,0 +1,68 @@ +/* Copyright (C) 2013 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + +#if !defined(WSREP_SST_H) && defined(WITH_WSREP) +#define WSREP_SST_H + +#include // my_bool + +#define WSREP_SST_OPT_ROLE "--role" +#define WSREP_SST_OPT_ADDR "--address" +#define WSREP_SST_OPT_AUTH "--auth" +#define WSREP_SST_OPT_DATA "--datadir" +#define WSREP_SST_OPT_CONF "--defaults-file" +#define WSREP_SST_OPT_PARENT "--parent" +#define WSREP_SST_OPT_BINLOG "--binlog" + +// mysqldump-specific options +#define WSREP_SST_OPT_USER "--user" +#define WSREP_SST_OPT_PSWD "--password" +#define WSREP_SST_OPT_HOST "--host" +#define WSREP_SST_OPT_PORT "--port" +#define WSREP_SST_OPT_LPORT "--local-port" + +// donor-specific +#define WSREP_SST_OPT_SOCKET "--socket" +#define WSREP_SST_OPT_GTID "--gtid" +#define WSREP_SST_OPT_BYPASS "--bypass" + +#define WSREP_SST_MYSQLDUMP "mysqldump" +#define WSREP_SST_RSYNC "rsync" +#define WSREP_SST_SKIP "skip" +#define WSREP_SST_DEFAULT WSREP_SST_RSYNC +#define WSREP_SST_ADDRESS_AUTO "AUTO" +#define WSREP_SST_AUTH_MASK "********" + +/* system variables */ +extern const char* wsrep_sst_method; +extern const char* wsrep_sst_receive_address; +extern const char* wsrep_sst_donor; +extern char* wsrep_sst_auth; +extern my_bool wsrep_sst_donor_rejects_queries; + +/*! Synchronizes applier thread start with init thread */ +extern void wsrep_sst_grab(); +/*! Init thread waits for SST completion */ +extern bool wsrep_sst_wait(); +/*! Signals wsrep that initialization is complete, writesets can be applied */ +extern void wsrep_sst_continue(); +extern void wsrep_sst_auth_free(); + +extern void wsrep_SE_init_grab(); /*! grab init critical section */ +extern void wsrep_SE_init_wait(); /*! wait for SE init to complete */ +extern void wsrep_SE_init_done(); /*! signal that SE init is complte */ +extern void wsrep_SE_initialized(); /*! mark SE initialization complete */ + +#endif /* WSREP_SST_H */ diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc new file mode 100644 index 00000000000..fabced2d11a --- /dev/null +++ b/sql/wsrep_thd.cc @@ -0,0 +1,602 @@ +/* Copyright (C) 2013 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + +#include "wsrep_thd.h" + +#include "transaction.h" +#include "rpl_rli.h" +#include "log_event.h" +#include "sql_parse.h" +//#include "global_threads.h" // LOCK_thread_count, etc. +#include "sql_base.h" // close_thread_tables() +#include "mysqld.h" // start_wsrep_THD(); + +#include "slave.h" // opt_log_slave_updates +#include "rpl_filter.h" +#include "rpl_rli.h" +#include "rpl_mi.h" + +#if (__LP64__) +static volatile int64 wsrep_bf_aborts_counter(0); +#define WSREP_ATOMIC_LOAD_LONG my_atomic_load64 +#define WSREP_ATOMIC_ADD_LONG my_atomic_add64 +#else +static volatile int32 wsrep_bf_aborts_counter(0); +#define WSREP_ATOMIC_LOAD_LONG my_atomic_load32 +#define WSREP_ATOMIC_ADD_LONG my_atomic_add32 +#endif + +int wsrep_show_bf_aborts (THD *thd, SHOW_VAR *var, char *buff) +{ + wsrep_local_bf_aborts = WSREP_ATOMIC_LOAD_LONG(&wsrep_bf_aborts_counter); + var->type = SHOW_LONGLONG; + var->value = (char*)&wsrep_local_bf_aborts; + return 0; +} + +/* must have (&thd->LOCK_wsrep_thd) */ +void wsrep_client_rollback(THD *thd) +{ + WSREP_DEBUG("client rollback due to BF abort for (%ld), query: %s", + thd->thread_id, thd->query()); + + WSREP_ATOMIC_ADD_LONG(&wsrep_bf_aborts_counter, 1); + + thd->wsrep_conflict_state= ABORTING; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + trans_rollback(thd); + + if (thd->locked_tables_mode && thd->lock) + { + WSREP_DEBUG("unlocking tables for BF abort (%ld)", thd->thread_id); + thd->locked_tables_list.unlock_locked_tables(thd); + thd->variables.option_bits&= ~(OPTION_TABLE_LOCK); + } + + if (thd->global_read_lock.is_acquired()) + { + WSREP_DEBUG("unlocking GRL for BF abort (%ld)", thd->thread_id); + thd->global_read_lock.unlock_global_read_lock(thd); + } + + /* Release transactional metadata locks. */ + thd->mdl_context.release_transactional_locks(); + + /* release explicit MDL locks */ + thd->mdl_context.release_explicit_locks(); + + if (thd->get_binlog_table_maps()) + { + WSREP_DEBUG("clearing binlog table map for BF abort (%ld)", thd->thread_id); + thd->clear_binlog_table_maps(); + } + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + thd->wsrep_conflict_state= ABORTED; +} + +#define NUMBER_OF_FIELDS_TO_IDENTIFY_COORDINATOR 1 +#define NUMBER_OF_FIELDS_TO_IDENTIFY_WORKER 2 +//#include "rpl_info_factory.h" + +static Relay_log_info* wsrep_relay_log_init(const char* log_fname) +{ + + /* MySQL 5.6 version has rli factory: */ +#ifdef MYSQL_56 + uint rli_option = INFO_REPOSITORY_DUMMY; + Relay_log_info *rli= NULL; + rli = Rpl_info_factory::create_rli(rli_option, false); + rli->set_rli_description_event( + new Format_description_log_event(BINLOG_VERSION)); +#endif + Relay_log_info* rli= new Relay_log_info(false); + rli->sql_driver_thd= current_thd; + + rli->no_storage= true; + rli->relay_log.description_event_for_exec= + new Format_description_log_event(4); + + return rli; +} + +class Master_info; + +static rpl_group_info* wsrep_relay_group_init(const char* log_fname) +{ + Relay_log_info* rli= new Relay_log_info(false); + + rli->no_storage= true; + if (!rli->relay_log.description_event_for_exec) + { + rli->relay_log.description_event_for_exec= + new Format_description_log_event(4); + } + static LEX_STRING dbname= { C_STRING_WITH_LEN("mysql") }; + + rli->mi = new Master_info( &dbname, false); + //rli->mi = new Master_info( &(C_STRING_WITH_LEN("wsrep")), false); + + rli->mi->rpl_filter = new Rpl_filter; + copy_filter_setting(rli->mi->rpl_filter, get_or_create_rpl_filter("", 0)); + + rli->sql_driver_thd= current_thd; + + struct rpl_group_info *rgi= new rpl_group_info(rli); + rgi->thd= current_thd; + + return rgi; +} + +static void wsrep_prepare_bf_thd(THD *thd, struct wsrep_thd_shadow* shadow) +{ + shadow->options = thd->variables.option_bits; + shadow->server_status = thd->server_status; + shadow->wsrep_exec_mode = thd->wsrep_exec_mode; + shadow->vio = thd->net.vio; + + if (opt_log_slave_updates) + thd->variables.option_bits|= OPTION_BIN_LOG; + else + thd->variables.option_bits&= ~(OPTION_BIN_LOG); + + //if (!thd->wsrep_rli) thd->wsrep_rli= wsrep_relay_log_init("wsrep_relay"); + if (!thd->wsrep_rgi) thd->wsrep_rgi= wsrep_relay_group_init("wsrep_relay"); + // thd->wsrep_rli->info_thd = thd; + + thd->wsrep_exec_mode= REPL_RECV; + thd->net.vio= 0; + thd->clear_error(); + + shadow->tx_isolation = thd->variables.tx_isolation; + thd->variables.tx_isolation = ISO_READ_COMMITTED; + thd->tx_isolation = ISO_READ_COMMITTED; + + shadow->db = thd->db; + shadow->db_length = thd->db_length; + thd->reset_db(NULL, 0); +} + +static void wsrep_return_from_bf_mode(THD *thd, struct wsrep_thd_shadow* shadow) +{ + thd->variables.option_bits = shadow->options; + thd->server_status = shadow->server_status; + thd->wsrep_exec_mode = shadow->wsrep_exec_mode; + thd->net.vio = shadow->vio; + thd->variables.tx_isolation = shadow->tx_isolation; + thd->reset_db(shadow->db, shadow->db_length); + + delete thd->wsrep_rgi->rli->mi->rpl_filter; + delete thd->wsrep_rgi->rli->mi; + delete thd->wsrep_rgi->rli; + delete thd->wsrep_rgi; + thd->wsrep_rgi = NULL; +; +} + +void wsrep_replay_transaction(THD *thd) +{ + /* checking if BF trx must be replayed */ + if (thd->wsrep_conflict_state== MUST_REPLAY) { + DBUG_ASSERT(wsrep_thd_trx_seqno(thd)); + if (thd->wsrep_exec_mode!= REPL_RECV) { + if (thd->get_stmt_da()->is_sent()) + { + WSREP_ERROR("replay issue, thd has reported status already"); + } + thd->get_stmt_da()->reset_diagnostics_area(); + + thd->wsrep_conflict_state= REPLAYING; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + + mysql_reset_thd_for_next_command(thd); + thd->killed= NOT_KILLED; + close_thread_tables(thd); + if (thd->locked_tables_mode && thd->lock) + { + WSREP_DEBUG("releasing table lock for replaying (%ld)", + thd->thread_id); + thd->locked_tables_list.unlock_locked_tables(thd); + thd->variables.option_bits&= ~(OPTION_TABLE_LOCK); + } + thd->mdl_context.release_transactional_locks(); + /* + Replaying will call MYSQL_START_STATEMENT when handling + BEGIN Query_log_event so end statement must be called before + replaying. + */ + MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da()); + thd->m_statement_psi= NULL; + thd_proc_info(thd, "wsrep replaying trx"); + WSREP_DEBUG("replay trx: %s %lld", + thd->query() ? thd->query() : "void", + (long long)wsrep_thd_trx_seqno(thd)); + struct wsrep_thd_shadow shadow; + wsrep_prepare_bf_thd(thd, &shadow); + + /* From trans_begin() */ + thd->variables.option_bits|= OPTION_BEGIN; + thd->server_status|= SERVER_STATUS_IN_TRANS; + + int rcode = wsrep->replay_trx(wsrep, + &thd->wsrep_ws_handle, + (void *)thd); + + wsrep_return_from_bf_mode(thd, &shadow); + if (thd->wsrep_conflict_state!= REPLAYING) + WSREP_WARN("lost replaying mode: %d", thd->wsrep_conflict_state ); + + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + + switch (rcode) + { + case WSREP_OK: + thd->wsrep_conflict_state= NO_CONFLICT; + wsrep->post_commit(wsrep, &thd->wsrep_ws_handle); + WSREP_DEBUG("trx_replay successful for: %ld %llu", + thd->thread_id, (long long)thd->real_id); + if (thd->get_stmt_da()->is_sent()) + { + WSREP_WARN("replay ok, thd has reported status"); + } + else if (thd->get_stmt_da()->is_set()) + { + if (thd->get_stmt_da()->status() != Diagnostics_area::DA_OK) + { + WSREP_WARN("replay ok, thd has error status %d", + thd->get_stmt_da()->status()); + } + } + else + { + my_ok(thd); + } + break; + case WSREP_TRX_FAIL: + if (thd->get_stmt_da()->is_sent()) + { + WSREP_ERROR("replay failed, thd has reported status"); + } + else + { + WSREP_DEBUG("replay failed, rolling back"); + //my_error(ER_LOCK_DEADLOCK, MYF(0), "wsrep aborted transaction"); + } + thd->wsrep_conflict_state= ABORTED; + wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle); + break; + default: + WSREP_ERROR("trx_replay failed for: %d, query: %s", + rcode, thd->query() ? thd->query() : "void"); + /* we're now in inconsistent state, must abort */ + unireg_abort(1); + break; + } + + wsrep_cleanup_transaction(thd); + + mysql_mutex_lock(&LOCK_wsrep_replaying); + wsrep_replaying--; + WSREP_DEBUG("replaying decreased: %d, thd: %lu", + wsrep_replaying, thd->thread_id); + mysql_cond_broadcast(&COND_wsrep_replaying); + mysql_mutex_unlock(&LOCK_wsrep_replaying); + } + } +} + +static void wsrep_replication_process(THD *thd) +{ + int rcode; + DBUG_ENTER("wsrep_replication_process"); + + struct wsrep_thd_shadow shadow; + wsrep_prepare_bf_thd(thd, &shadow); + + /* From trans_begin() */ + thd->variables.option_bits|= OPTION_BEGIN; + thd->server_status|= SERVER_STATUS_IN_TRANS; + + rcode = wsrep->recv(wsrep, (void *)thd); + DBUG_PRINT("wsrep",("wsrep_repl returned: %d", rcode)); + + WSREP_INFO("applier thread exiting (code:%d)", rcode); + + switch (rcode) { + case WSREP_OK: + case WSREP_NOT_IMPLEMENTED: + case WSREP_CONN_FAIL: + /* provider does not support slave operations / disconnected from group, + * just close applier thread */ + break; + case WSREP_NODE_FAIL: + /* data inconsistency => SST is needed */ + /* Note: we cannot just blindly restart replication here, + * SST might require server restart if storage engines must be + * initialized after SST */ + WSREP_ERROR("node consistency compromised, aborting"); + wsrep_kill_mysql(thd); + break; + case WSREP_WARNING: + case WSREP_TRX_FAIL: + case WSREP_TRX_MISSING: + /* these suggests a bug in provider code */ + WSREP_WARN("bad return from recv() call: %d", rcode); + /* fall through to node shutdown */ + case WSREP_FATAL: + /* Cluster connectivity is lost. + * + * If applier was killed on purpose (KILL_CONNECTION), we + * avoid mysql shutdown. This is because the killer will then handle + * shutdown processing (or replication restarting) + */ + if (thd->killed != KILL_CONNECTION) + { + wsrep_kill_mysql(thd); + } + break; + } + + mysql_mutex_lock(&LOCK_thread_count); + wsrep_close_applier(thd); + mysql_cond_broadcast(&COND_thread_count); + mysql_mutex_unlock(&LOCK_thread_count); + + TABLE *tmp; + while ((tmp = thd->temporary_tables)) + { + WSREP_WARN("Applier %lu, has temporary tables at exit: %s.%s", + thd->thread_id, + (tmp->s) ? tmp->s->db.str : "void", + (tmp->s) ? tmp->s->table_name.str : "void"); + } + wsrep_return_from_bf_mode(thd, &shadow); + DBUG_VOID_RETURN; +} + +void wsrep_create_appliers(long threads) +{ + if (!wsrep_connected) + { + /* see wsrep_replication_start() for the logic */ + if (wsrep_cluster_address && strlen(wsrep_cluster_address) && + wsrep_provider && strcasecmp(wsrep_provider, "none")) + { + WSREP_ERROR("Trying to launch slave threads before creating " + "connection at '%s'", wsrep_cluster_address); + assert(0); + } + return; + } + + long wsrep_threads=0; + pthread_t hThread; + while (wsrep_threads++ < threads) { + if (pthread_create( + &hThread, &connection_attrib, + start_wsrep_THD, (void*)wsrep_replication_process)) + WSREP_WARN("Can't create thread to manage wsrep replication"); + } +} + +static void wsrep_rollback_process(THD *thd) +{ + DBUG_ENTER("wsrep_rollback_process"); + + mysql_mutex_lock(&LOCK_wsrep_rollback); + wsrep_aborting_thd= NULL; + + while (thd->killed == NOT_KILLED) { + thd_proc_info(thd, "wsrep aborter idle"); + thd->mysys_var->current_mutex= &LOCK_wsrep_rollback; + thd->mysys_var->current_cond= &COND_wsrep_rollback; + + mysql_cond_wait(&COND_wsrep_rollback,&LOCK_wsrep_rollback); + + WSREP_DEBUG("WSREP rollback thread wakes for signal"); + + mysql_mutex_lock(&thd->mysys_var->mutex); + thd_proc_info(thd, "wsrep aborter active"); + thd->mysys_var->current_mutex= 0; + thd->mysys_var->current_cond= 0; + mysql_mutex_unlock(&thd->mysys_var->mutex); + + /* check for false alarms */ + if (!wsrep_aborting_thd) + { + WSREP_DEBUG("WSREP rollback thread has empty abort queue"); + } + /* process all entries in the queue */ + while (wsrep_aborting_thd) { + THD *aborting; + wsrep_aborting_thd_t next = wsrep_aborting_thd->next; + aborting = wsrep_aborting_thd->aborting_thd; + my_free(wsrep_aborting_thd); + wsrep_aborting_thd= next; + /* + * must release mutex, appliers my want to add more + * aborting thds in our work queue, while we rollback + */ + mysql_mutex_unlock(&LOCK_wsrep_rollback); + + mysql_mutex_lock(&aborting->LOCK_wsrep_thd); + if (aborting->wsrep_conflict_state== ABORTED) + { + WSREP_DEBUG("WSREP, thd already aborted: %llu state: %d", + (long long)aborting->real_id, + aborting->wsrep_conflict_state); + + mysql_mutex_unlock(&aborting->LOCK_wsrep_thd); + mysql_mutex_lock(&LOCK_wsrep_rollback); + continue; + } + aborting->wsrep_conflict_state= ABORTING; + + mysql_mutex_unlock(&aborting->LOCK_wsrep_thd); + + set_current_thd(aborting); + aborting->store_globals(); + + mysql_mutex_lock(&aborting->LOCK_wsrep_thd); + wsrep_client_rollback(aborting); + WSREP_DEBUG("WSREP rollbacker aborted thd: (%lu %llu)", + aborting->thread_id, (long long)aborting->real_id); + mysql_mutex_unlock(&aborting->LOCK_wsrep_thd); + + set_current_thd(thd); + thd->store_globals(); + + mysql_mutex_lock(&LOCK_wsrep_rollback); + } + } + + mysql_mutex_unlock(&LOCK_wsrep_rollback); + sql_print_information("WSREP: rollbacker thread exiting"); + + DBUG_PRINT("wsrep",("wsrep rollbacker thread exiting")); + DBUG_VOID_RETURN; +} + +void wsrep_create_rollbacker() +{ + if (wsrep_provider && strcasecmp(wsrep_provider, "none")) + { + pthread_t hThread; + /* create rollbacker */ + if (pthread_create( &hThread, &connection_attrib, + start_wsrep_THD, (void*)wsrep_rollback_process)) + WSREP_WARN("Can't create thread to manage wsrep rollback"); + } +} + +void wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe) +{ + if (thd_ptr) + { + THD* thd = (THD*)thd_ptr; + thd->wsrep_PA_safe = safe; + } +} + +int wsrep_thd_conflict_state(void *thd_ptr, my_bool sync) +{ + int state = -1; + if (thd_ptr) + { + THD* thd = (THD*)thd_ptr; + if (sync) mysql_mutex_lock(&thd->LOCK_wsrep_thd); + + state = thd->wsrep_conflict_state; + if (sync) mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } + return state; +} + +my_bool wsrep_thd_is_wsrep(void *thd_ptr) +{ + my_bool status = FALSE; + if (thd_ptr) + { + THD* thd = (THD*)thd_ptr; + + status = (WSREP(thd) && WSREP_PROVIDER_EXISTS); + } + return status; +} + +my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync) +{ + my_bool status = FALSE; + if (thd_ptr) + { + THD* thd = (THD*)thd_ptr; + // THD can be BF only if provider exists + if (wsrep_thd_is_wsrep(thd_ptr)) + { + if (sync) + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + + status = ((thd->wsrep_exec_mode == REPL_RECV) || + (thd->wsrep_exec_mode == TOTAL_ORDER)); + if (sync) + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } + } + return status; +} + +extern "C" +my_bool wsrep_thd_is_BF_or_commit(void *thd_ptr, my_bool sync) +{ + bool status = FALSE; + if (thd_ptr) + { + THD* thd = (THD*)thd_ptr; + if (sync) mysql_mutex_lock(&thd->LOCK_wsrep_thd); + + status = ((thd->wsrep_exec_mode == REPL_RECV) || + (thd->wsrep_exec_mode == TOTAL_ORDER) || + (thd->wsrep_exec_mode == LOCAL_COMMIT)); + if (sync) mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } + return status; +} + +extern "C" +my_bool wsrep_thd_is_local(void *thd_ptr, my_bool sync) +{ + bool status = FALSE; + if (thd_ptr) + { + THD* thd = (THD*)thd_ptr; + if (sync) mysql_mutex_lock(&thd->LOCK_wsrep_thd); + + status = (thd->wsrep_exec_mode == LOCAL_STATE); + if (sync) mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } + return status; +} + +int wsrep_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr, my_bool signal) +{ + THD *victim_thd = (THD *) victim_thd_ptr; + THD *bf_thd = (THD *) bf_thd_ptr; + DBUG_ENTER("wsrep_abort_thd"); + + if ( (WSREP(bf_thd) || + ( (WSREP_ON || wsrep_OSU_method_options == WSREP_OSU_RSU) && + bf_thd->wsrep_exec_mode == TOTAL_ORDER) ) && + victim_thd) + { + WSREP_DEBUG("wsrep_abort_thd, by: %llu, victim: %llu", (bf_thd) ? + (long long)bf_thd->real_id : 0, (long long)victim_thd->real_id); + ha_abort_transaction(bf_thd, victim_thd, signal); + } + else + { + WSREP_DEBUG("wsrep_abort_thd not effective: %p %p", bf_thd, victim_thd); + } + + DBUG_RETURN(1); +} + +extern "C" +int wsrep_thd_in_locking_session(void *thd_ptr) +{ + if (thd_ptr && ((THD *)thd_ptr)->in_lock_tables) { + return 1; + } + return 0; +} + diff --git a/sql/wsrep_thd.h b/sql/wsrep_thd.h new file mode 100644 index 00000000000..c5a497bb428 --- /dev/null +++ b/sql/wsrep_thd.h @@ -0,0 +1,40 @@ +/* Copyright (C) 2013 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + +#if !defined(WSREP_THD_H) && defined(WITH_WSREP) +#define WSREP_THD_H + +#include "sql_class.h" + +int wsrep_show_bf_aborts (THD *thd, SHOW_VAR *var, char *buff); +void wsrep_client_rollback(THD *thd); +void wsrep_replay_transaction(THD *thd); +void wsrep_create_appliers(long threads); +void wsrep_create_rollbacker(); + +int wsrep_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr, + my_bool signal); + +extern void wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe); +extern my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync); +extern my_bool wsrep_thd_is_wsrep(void *thd_ptr); + +extern int wsrep_thd_conflict_state(void *thd_ptr, my_bool sync); +//extern "C" my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync); +extern "C" my_bool wsrep_thd_is_BF_or_commit(void *thd_ptr, my_bool sync); +extern "C" my_bool wsrep_thd_is_local(void *thd_ptr, my_bool sync); +extern "C" int wsrep_thd_in_locking_session(void *thd_ptr); + +#endif /* WSREP_THD_H */ diff --git a/sql/wsrep_utils.cc b/sql/wsrep_utils.cc new file mode 100644 index 00000000000..cdee1c2cece --- /dev/null +++ b/sql/wsrep_utils.cc @@ -0,0 +1,524 @@ +/* Copyright 2010 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//! @file some utility functions and classes not directly related to replication + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE // POSIX_SPAWN_USEVFORK flag +#endif + +#include "wsrep_utils.h" +#include "wsrep_mysqld.h" + +#include + +#include // posix_spawn() +#include // pipe() +#include // errno +#include // strerror() +#include // waitpid() +#include +#include +#include // getaddrinfo() + +extern char** environ; // environment variables + +static wsp::string wsrep_PATH; + +void +wsrep_prepend_PATH (const char* path) +{ + int count = 0; + + while (environ[count]) + { + if (strncmp (environ[count], "PATH=", 5)) + { + count++; + continue; + } + + char* const old_path (environ[count]); + + if (strstr (old_path, path)) return; // path already there + + size_t const new_path_len(strlen(old_path) + strlen(":") + + strlen(path) + 1); + + char* const new_path (reinterpret_cast(malloc(new_path_len))); + + if (new_path) + { + snprintf (new_path, new_path_len, "PATH=%s:%s", path, + old_path + strlen("PATH=")); + + wsrep_PATH.set (new_path); + environ[count] = new_path; + } + else + { + WSREP_ERROR ("Failed to allocate 'PATH' environment variable " + "buffer of size %zu.", new_path_len); + } + + return; + } + + WSREP_ERROR ("Failed to find 'PATH' environment variable. " + "State snapshot transfer may not be working."); +} + +namespace wsp +{ + +#define PIPE_READ 0 +#define PIPE_WRITE 1 +#define STDIN_FD 0 +#define STDOUT_FD 1 + +#ifndef POSIX_SPAWN_USEVFORK +# define POSIX_SPAWN_USEVFORK 0 +#endif + +process::process (const char* cmd, const char* type) + : str_(cmd ? strdup(cmd) : strdup("")), io_(NULL), err_(EINVAL), pid_(0) +{ + if (0 == str_) + { + WSREP_ERROR ("Can't allocate command line of size: %zu", strlen(cmd)); + err_ = ENOMEM; + return; + } + + if (0 == strlen(str_)) + { + WSREP_ERROR ("Can't start a process: null or empty command line."); + return; + } + + if (NULL == type || (strcmp (type, "w") && strcmp(type, "r"))) + { + WSREP_ERROR ("type argument should be either \"r\" or \"w\"."); + return; + } + + int pipe_fds[2] = { -1, }; + if (::pipe(pipe_fds)) + { + err_ = errno; + WSREP_ERROR ("pipe() failed: %d (%s)", err_, strerror(err_)); + return; + } + + // which end of pipe will be returned to parent + int const parent_end (strcmp(type,"w") ? PIPE_READ : PIPE_WRITE); + int const child_end (parent_end == PIPE_READ ? PIPE_WRITE : PIPE_READ); + int const close_fd (parent_end == PIPE_READ ? STDOUT_FD : STDIN_FD); + + char* const pargv[4] = { strdup("sh"), strdup("-c"), strdup(str_), NULL }; + if (!(pargv[0] && pargv[1] && pargv[2])) + { + err_ = ENOMEM; + WSREP_ERROR ("Failed to allocate pargv[] array."); + goto cleanup_pipe; + } + + posix_spawnattr_t attr; + err_ = posix_spawnattr_init (&attr); + if (err_) + { + WSREP_ERROR ("posix_spawnattr_init() failed: %d (%s)", + err_, strerror(err_)); + goto cleanup_pipe; + } + + err_ = posix_spawnattr_setflags (&attr, POSIX_SPAWN_SETSIGDEF | + POSIX_SPAWN_USEVFORK); + if (err_) + { + WSREP_ERROR ("posix_spawnattr_setflags() failed: %d (%s)", + err_, strerror(err_)); + goto cleanup_attr; + } + + posix_spawn_file_actions_t fact; + err_ = posix_spawn_file_actions_init (&fact); + if (err_) + { + WSREP_ERROR ("posix_spawn_file_actions_init() failed: %d (%s)", + err_, strerror(err_)); + goto cleanup_attr; + } + + // close child's stdout|stdin depending on what we returning + err_ = posix_spawn_file_actions_addclose (&fact, close_fd); + if (err_) + { + WSREP_ERROR ("posix_spawn_file_actions_addclose() failed: %d (%s)", + err_, strerror(err_)); + goto cleanup_fact; + } + + // substitute our pipe descriptor in place of the closed one + err_ = posix_spawn_file_actions_adddup2 (&fact, + pipe_fds[child_end], close_fd); + if (err_) + { + WSREP_ERROR ("posix_spawn_file_actions_addup2() failed: %d (%s)", + err_, strerror(err_)); + goto cleanup_fact; + } + + err_ = posix_spawnp (&pid_, pargv[0], &fact, &attr, pargv, environ); + if (err_) + { + WSREP_ERROR ("posix_spawnp(%s) failed: %d (%s)", + pargv[2], err_, strerror(err_)); + pid_ = 0; // just to make sure it was not messed up in the call + goto cleanup_fact; + } + + io_ = fdopen (pipe_fds[parent_end], type); + + if (io_) + { + pipe_fds[parent_end] = -1; // skip close on cleanup + } + else + { + err_ = errno; + WSREP_ERROR ("fdopen() failed: %d (%s)", err_, strerror(err_)); + } + +cleanup_fact: + int err; // to preserve err_ code + err = posix_spawn_file_actions_destroy (&fact); + if (err) + { + WSREP_ERROR ("posix_spawn_file_actions_destroy() failed: %d (%s)\n", + err, strerror(err)); + } + +cleanup_attr: + err = posix_spawnattr_destroy (&attr); + if (err) + { + WSREP_ERROR ("posix_spawnattr_destroy() failed: %d (%s)", + err, strerror(err)); + } + +cleanup_pipe: + if (pipe_fds[0] >= 0) close (pipe_fds[0]); + if (pipe_fds[1] >= 0) close (pipe_fds[1]); + + free (pargv[0]); + free (pargv[1]); + free (pargv[2]); +} + +process::~process () +{ + if (io_) + { + assert (pid_); + assert (str_); + + WSREP_WARN("Closing pipe to child process: %s, PID(%ld) " + "which might still be running.", str_, (long)pid_); + + if (fclose (io_) == -1) + { + err_ = errno; + WSREP_ERROR("fclose() failed: %d (%s)", err_, strerror(err_)); + } + } + + if (str_) free (const_cast(str_)); +} + +int +process::wait () +{ + if (pid_) + { + int status; + if (-1 == waitpid(pid_, &status, 0)) + { + err_ = errno; assert (err_); + WSREP_ERROR("Waiting for process failed: %s, PID(%ld): %d (%s)", + str_, (long)pid_, err_, strerror (err_)); + } + else + { // command completed, check exit status + if (WIFEXITED (status)) { + err_ = WEXITSTATUS (status); + } + else { // command didn't complete with exit() + WSREP_ERROR("Process was aborted."); + err_ = errno ? errno : ECHILD; + } + + if (err_) { + switch (err_) /* Translate error codes to more meaningful */ + { + case 126: err_ = EACCES; break; /* Permission denied */ + case 127: err_ = ENOENT; break; /* No such file or directory */ + } + WSREP_ERROR("Process completed with error: %s: %d (%s)", + str_, err_, strerror(err_)); + } + + pid_ = 0; + if (io_) fclose (io_); + io_ = NULL; + } + } + else { + assert (NULL == io_); + WSREP_ERROR("Command did not run: %s", str_); + } + + return err_; +} + +thd::thd (my_bool won) : init(), ptr(new THD) +{ + if (ptr) + { + ptr->thread_stack= (char*) &ptr; + ptr->store_globals(); + ptr->variables.option_bits&= ~OPTION_BIN_LOG; // disable binlog + ptr->variables.wsrep_on = won; + ptr->security_ctx->master_access= ~(ulong)0; + lex_start(ptr); + } +} + +thd::~thd () +{ + if (ptr) + { + delete ptr; + my_pthread_setspecific_ptr (THR_THD, 0); + } +} + +} // namespace wsp + +/* Returns INADDR_NONE, INADDR_ANY, INADDR_LOOPBACK or something else */ +unsigned int wsrep_check_ip (const char* const addr) +{ +#if 0 + if (addr && 0 == strcasecmp(addr, MY_BIND_ALL_ADDRESSES)) return INADDR_ANY; +#endif + + unsigned int ret = INADDR_NONE; + struct addrinfo *res, hints; + + memset (&hints, 0, sizeof(hints)); + hints.ai_flags= AI_PASSIVE/*|AI_ADDRCONFIG*/; + hints.ai_socktype= SOCK_STREAM; + hints.ai_family= AF_UNSPEC; + + int gai_ret = getaddrinfo(addr, NULL, &hints, &res); + if (0 == gai_ret) + { + if (AF_INET == res->ai_family) /* IPv4 */ + { + struct sockaddr_in* a= (struct sockaddr_in*)res->ai_addr; + ret= htonl(a->sin_addr.s_addr); + } + else /* IPv6 */ + { + struct sockaddr_in6* a= (struct sockaddr_in6*)res->ai_addr; + if (IN6_IS_ADDR_UNSPECIFIED(&a->sin6_addr)) + ret= INADDR_ANY; + else if (IN6_IS_ADDR_LOOPBACK(&a->sin6_addr)) + ret= INADDR_LOOPBACK; + else + ret= 0xdeadbeef; + } + freeaddrinfo (res); + } + else { + WSREP_ERROR ("getaddrinfo() failed on '%s': %d (%s)", + addr, gai_ret, gai_strerror(gai_ret)); + } + + // uint8_t* b= (uint8_t*)&ret; + // fprintf (stderr, "########## wsrep_check_ip returning: %hhu.%hhu.%hhu.%hhu\n", + // b[0], b[1], b[2], b[3]); + + return ret; +} + +extern char* my_bind_addr_str; + +size_t wsrep_guess_ip (char* buf, size_t buf_len) +{ + size_t ip_len = 0; + + if (my_bind_addr_str && strlen(my_bind_addr_str)) + { + unsigned int const ip_type= wsrep_check_ip(my_bind_addr_str); + + if (INADDR_NONE == ip_type) { + WSREP_ERROR("Networking not configured, cannot receive state transfer."); + return 0; + } + + if (INADDR_ANY != ip_type) {; + strncpy (buf, my_bind_addr_str, buf_len); + return strlen(buf); + } + } + + // mysqld binds to all interfaces - try IP from wsrep_node_address + if (wsrep_node_address && wsrep_node_address[0] != '\0') { + const char* const colon_ptr = strchr(wsrep_node_address, ':'); + + if (colon_ptr) + ip_len = colon_ptr - wsrep_node_address; + else + ip_len = strlen(wsrep_node_address); + + if (ip_len >= buf_len) { + WSREP_WARN("default_ip(): buffer too short: %zu <= %zd", buf_len, ip_len); + return 0; + } + + memcpy (buf, wsrep_node_address, ip_len); + buf[ip_len] = '\0'; + return ip_len; + } + + // try to find the address of the first one +#if (TARGET_OS_LINUX == 1) + const char cmd[] = "/sbin/ifconfig | " +// "grep -m1 -1 -E '^[a-z]?eth[0-9]' | tail -n 1 | " + "grep -E '^[[:space:]]+inet addr:' | grep -m1 -v 'inet addr:127' | " + "sed 's/:/ /' | awk '{ print $3 }'"; +#elif defined(__sun__) + const char cmd[] = "/sbin/ifconfig -a | " + "/usr/gnu/bin/grep -m1 -1 -E 'net[0-9]:' | tail -n 1 | awk '{ print $2 }'"; +#elif defined(__APPLE__) || defined(__FreeBSD__) + const char cmd[] = "/sbin/route -nv get 8.8.8.8 | tail -n1 | awk '{print $(NF)}'"; +#else + char *cmd; +#error "OS not supported" +#endif + wsp::process proc (cmd, "r"); + + if (NULL != proc.pipe()) { + char* ret; + + ret = fgets (buf, buf_len, proc.pipe()); + + if (proc.wait()) return 0; + + if (NULL == ret) { + WSREP_ERROR("Failed to read output of: '%s'", cmd); + return 0; + } + } + else { + WSREP_ERROR("Failed to execute: '%s'", cmd); + return 0; + } + + // clear possible \n at the end of ip string left by fgets() + ip_len = strlen (buf); + if (ip_len > 0 && '\n' == buf[ip_len - 1]) { + ip_len--; + buf[ip_len] = '\0'; + } + + if (INADDR_NONE == inet_addr(buf)) { + if (strlen(buf) != 0) { + WSREP_WARN("Shell command returned invalid address: '%s'", buf); + } + return 0; + } + + return ip_len; +} + +size_t wsrep_guess_address(char* buf, size_t buf_len) +{ + size_t addr_len = wsrep_guess_ip (buf, buf_len); + + if (addr_len && addr_len < buf_len) { + addr_len += snprintf (buf + addr_len, buf_len - addr_len, + ":%u", mysqld_port); + } + + return addr_len; +} + +/* + * WSREPXid + */ + +#define WSREP_XID_PREFIX "WSREPXid" +#define WSREP_XID_PREFIX_LEN MYSQL_XID_PREFIX_LEN +#define WSREP_XID_UUID_OFFSET 8 +#define WSREP_XID_SEQNO_OFFSET (WSREP_XID_UUID_OFFSET + sizeof(wsrep_uuid_t)) +#define WSREP_XID_GTRID_LEN (WSREP_XID_SEQNO_OFFSET + sizeof(wsrep_seqno_t)) + +void wsrep_xid_init(XID* xid, const wsrep_uuid_t* uuid, wsrep_seqno_t seqno) +{ + xid->formatID= 1; + xid->gtrid_length= WSREP_XID_GTRID_LEN; + xid->bqual_length= 0; + memset(xid->data, 0, sizeof(xid->data)); + memcpy(xid->data, WSREP_XID_PREFIX, WSREP_XID_PREFIX_LEN); + memcpy(xid->data + WSREP_XID_UUID_OFFSET, uuid, sizeof(wsrep_uuid_t)); + memcpy(xid->data + WSREP_XID_SEQNO_OFFSET, &seqno, sizeof(wsrep_seqno_t)); +} + +const wsrep_uuid_t* wsrep_xid_uuid(const XID* xid) +{ + if (wsrep_is_wsrep_xid(xid)) + return reinterpret_cast(xid->data + + WSREP_XID_UUID_OFFSET); + else + return &WSREP_UUID_UNDEFINED; +} + +wsrep_seqno_t wsrep_xid_seqno(const XID* xid) +{ + + if (wsrep_is_wsrep_xid(xid)) + { + wsrep_seqno_t seqno; + memcpy(&seqno, xid->data + WSREP_XID_SEQNO_OFFSET, sizeof(wsrep_seqno_t)); + return seqno; + } + else + { + return WSREP_SEQNO_UNDEFINED; + } +} + +extern +int wsrep_is_wsrep_xid(const void* xid_ptr) +{ + const XID* xid= reinterpret_cast(xid_ptr); + return (xid->formatID == 1 && + xid->gtrid_length == WSREP_XID_GTRID_LEN && + xid->bqual_length == 0 && + !memcmp(xid->data, WSREP_XID_PREFIX, WSREP_XID_PREFIX_LEN)); +} diff --git a/sql/wsrep_utils.h b/sql/wsrep_utils.h new file mode 100644 index 00000000000..337678238f8 --- /dev/null +++ b/sql/wsrep_utils.h @@ -0,0 +1,208 @@ +/* Copyright (C) 2013 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + +#ifndef WSREP_UTILS_H +#define WSREP_UTILS_H + +#include "wsrep_priv.h" + +unsigned int wsrep_check_ip (const char* addr); +size_t wsrep_guess_ip (char* buf, size_t buf_len); +size_t wsrep_guess_address(char* buf, size_t buf_len); + +namespace wsp { +class node_status +{ +public: + node_status() : status(WSREP_MEMBER_UNDEFINED) {} + void set(wsrep_member_status_t new_status, + const wsrep_view_info_t* view = 0) + { + if (status != new_status || 0 != view) + { + wsrep_notify_status(new_status, view); + status = new_status; + } + } + wsrep_member_status_t get() const { return status; } +private: + wsrep_member_status_t status; +}; +} /* namespace wsp */ + +extern wsp::node_status local_status; + +namespace wsp { +/* A small class to run external programs. */ +class process +{ +private: + const char* const str_; + FILE* io_; + int err_; + pid_t pid_; + +public: +/*! @arg type is a pointer to a null-terminated string which must contain + either the letter 'r' for reading or the letter 'w' for writing. + */ + process (const char* cmd, const char* type); + ~process (); + + FILE* pipe () { return io_; } + int error() { return err_; } + int wait (); + const char* cmd() { return str_; } +}; + +class thd +{ + class thd_init + { + public: + thd_init() { my_thread_init(); } + ~thd_init() { my_thread_end(); } + } + init; + + thd (const thd&); + thd& operator= (const thd&); + +public: + + thd(my_bool wsrep_on); + ~thd(); + THD* const ptr; +}; + +class string +{ +public: + string() : string_(0) {} + void set(char* str) { if (string_) free (string_); string_ = str; } + ~string() { set (0); } +private: + char* string_; +}; + +#ifdef REMOVED +class lock +{ + pthread_mutex_t* const mtx_; + +public: + + lock (pthread_mutex_t* mtx) : mtx_(mtx) + { + int err = pthread_mutex_lock (mtx_); + + if (err) + { + WSREP_ERROR("Mutex lock failed: %s", strerror(err)); + abort(); + } + } + + virtual ~lock () + { + int err = pthread_mutex_unlock (mtx_); + + if (err) + { + WSREP_ERROR("Mutex unlock failed: %s", strerror(err)); + abort(); + } + } + + inline void wait (pthread_cond_t* cond) + { + pthread_cond_wait (cond, mtx_); + } + +private: + + lock (const lock&); + lock& operator=(const lock&); + +}; + +class monitor +{ + int mutable refcnt; + pthread_mutex_t mutable mtx; + pthread_cond_t mutable cond; + +public: + + monitor() : refcnt(0) + { + pthread_mutex_init (&mtx, NULL); + pthread_cond_init (&cond, NULL); + } + + ~monitor() + { + pthread_mutex_destroy (&mtx); + pthread_cond_destroy (&cond); + } + + void enter() const + { + lock l(&mtx); + + while (refcnt) + { + l.wait(&cond); + } + refcnt++; + } + + void leave() const + { + lock l(&mtx); + + refcnt--; + if (refcnt == 0) + { + pthread_cond_signal (&cond); + } + } + +private: + + monitor (const monitor&); + monitor& operator= (const monitor&); +}; + +class critical +{ + const monitor& mon; + +public: + + critical(const monitor& m) : mon(m) { mon.enter(); } + + ~critical() { mon.leave(); } + +private: + + critical (const critical&); + critical& operator= (const critical&); +}; +#endif + +} // namespace wsrep + +#endif /* WSREP_UTILS_H */ diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc new file mode 100644 index 00000000000..2272945535d --- /dev/null +++ b/sql/wsrep_var.cc @@ -0,0 +1,602 @@ +/* Copyright 2008 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "wsrep_var.h" + +#include +#include +#include +#include +#include +#include "wsrep_priv.h" +#include "wsrep_thd.h" +#include +#include +#include + +const char* wsrep_provider = 0; +const char* wsrep_provider_options = 0; +const char* wsrep_cluster_address = 0; +const char* wsrep_cluster_name = 0; +const char* wsrep_node_name = 0; +const char* wsrep_node_address = 0; +const char* wsrep_node_incoming_address = 0; +const char* wsrep_start_position = 0; +ulong wsrep_OSU_method_options; + +int wsrep_init_vars() +{ + wsrep_provider = my_strdup(WSREP_NONE, MYF(MY_WME)); + wsrep_provider_options= my_strdup("", MYF(MY_WME)); + wsrep_cluster_address = my_strdup("", MYF(MY_WME)); + wsrep_cluster_name = my_strdup(WSREP_CLUSTER_NAME, MYF(MY_WME)); + wsrep_node_name = my_strdup("", MYF(MY_WME)); + wsrep_node_address = my_strdup("", MYF(MY_WME)); + wsrep_node_incoming_address= my_strdup(WSREP_NODE_INCOMING_AUTO, MYF(MY_WME)); + wsrep_start_position = my_strdup(WSREP_START_POSITION_ZERO, MYF(MY_WME)); + + global_system_variables.binlog_format=BINLOG_FORMAT_ROW; + return 0; +} + +bool wsrep_on_update (sys_var *self, THD* thd, enum_var_type var_type) +{ + if (var_type == OPT_GLOBAL) { + // FIXME: this variable probably should be changed only per session + thd->variables.wsrep_on = global_system_variables.wsrep_on; + } + return false; +} + +bool wsrep_causal_reads_update (sys_var *self, THD* thd, enum_var_type var_type) +{ + // global setting should not affect session setting. + // if (var_type == OPT_GLOBAL) { + // thd->variables.wsrep_causal_reads = global_system_variables.wsrep_causal_reads; + // } + if (thd->variables.wsrep_causal_reads) { + thd->variables.wsrep_sync_wait |= WSREP_SYNC_WAIT_BEFORE_READ; + } else { + thd->variables.wsrep_sync_wait &= ~WSREP_SYNC_WAIT_BEFORE_READ; + } + return false; +} + +bool wsrep_sync_wait_update (sys_var* self, THD* thd, enum_var_type var_type) +{ + // global setting should not affect session setting. + // if (var_type == OPT_GLOBAL) { + // thd->variables.wsrep_sync_wait = global_system_variables.wsrep_sync_wait; + // } + thd->variables.wsrep_causal_reads = thd->variables.wsrep_sync_wait & + WSREP_SYNC_WAIT_BEFORE_READ; + return false; +} + +static int wsrep_start_position_verify (const char* start_str) +{ + size_t start_len; + wsrep_uuid_t uuid; + ssize_t uuid_len; + + start_len = strlen (start_str); + if (start_len < 34) + return 1; + + uuid_len = wsrep_uuid_scan (start_str, start_len, &uuid); + if (uuid_len < 0 || (start_len - uuid_len) < 2) + return 1; + + if (start_str[uuid_len] != ':') // separator should follow UUID + return 1; + + char* endptr; + wsrep_seqno_t const seqno __attribute__((unused)) // to avoid GCC warnings + (strtoll(&start_str[uuid_len + 1], &endptr, 10)); + + if (*endptr == '\0') return 0; // remaining string was seqno + + return 1; +} + +bool wsrep_start_position_check (sys_var *self, THD* thd, set_var* var) +{ + char start_pos_buf[FN_REFLEN]; + + if ((! var->save_result.string_value.str) || + (var->save_result.string_value.length > (FN_REFLEN - 1))) // safety + goto err; + + memcpy(start_pos_buf, var->save_result.string_value.str, + var->save_result.string_value.length); + start_pos_buf[var->save_result.string_value.length]= 0; + + if (!wsrep_start_position_verify(start_pos_buf)) return 0; + +err: + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, + var->save_result.string_value.str ? + var->save_result.string_value.str : "NULL"); + return 1; +} + +void wsrep_set_local_position (const char* value) +{ + size_t value_len = strlen (value); + size_t uuid_len = wsrep_uuid_scan (value, value_len, &local_uuid); + + local_seqno = strtoll (value + uuid_len + 1, NULL, 10); + + XID xid; + wsrep_xid_init(&xid, &local_uuid, local_seqno); + wsrep_set_SE_checkpoint(&xid); + WSREP_INFO ("wsrep_start_position var submitted: '%s'", wsrep_start_position); +} + +bool wsrep_start_position_update (sys_var *self, THD* thd, enum_var_type type) +{ + // since this value passed wsrep_start_position_check, don't check anything + // here + wsrep_set_local_position (wsrep_start_position); + + if (wsrep) { + wsrep_sst_received (wsrep, &local_uuid, local_seqno, NULL, 0); + } + + return 0; +} + +void wsrep_start_position_init (const char* val) +{ + if (NULL == val || wsrep_start_position_verify (val)) + { + WSREP_ERROR("Bad initial value for wsrep_start_position: %s", + (val ? val : "")); + return; + } + + wsrep_set_local_position (val); +} + +static bool refresh_provider_options() +{ + WSREP_DEBUG("refresh_provider_options: %s", + (wsrep_provider_options) ? wsrep_provider_options : "null"); + char* opts= wsrep->options_get(wsrep); + if (opts) + { + if (wsrep_provider_options) my_free((void *)wsrep_provider_options); + wsrep_provider_options = (char*)my_memdup(opts, strlen(opts) + 1, + MYF(MY_WME)); + } + else + { + WSREP_ERROR("Failed to get provider options"); + return true; + } + return false; +} + +static int wsrep_provider_verify (const char* provider_str) +{ + MY_STAT f_stat; + char path[FN_REFLEN]; + + if (!provider_str || strlen(provider_str)== 0) + return 1; + + if (!strcmp(provider_str, WSREP_NONE)) + return 0; + + if (!unpack_filename(path, provider_str)) + return 1; + + /* check that provider file exists */ + bzero(&f_stat, sizeof(MY_STAT)); + if (!my_stat(path, &f_stat, MYF(0))) + { + return 1; + } + return 0; +} + +bool wsrep_provider_check (sys_var *self, THD* thd, set_var* var) +{ + char wsrep_provider_buf[FN_REFLEN]; + + if ((! var->save_result.string_value.str) || + (var->save_result.string_value.length > (FN_REFLEN - 1))) // safety + goto err; + + memcpy(wsrep_provider_buf, var->save_result.string_value.str, + var->save_result.string_value.length); + wsrep_provider_buf[var->save_result.string_value.length]= 0; + + if (!wsrep_provider_verify(wsrep_provider_buf)) return 0; + +err: + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, + var->save_result.string_value.str ? + var->save_result.string_value.str : "NULL"); + return 1; +} + +bool wsrep_provider_update (sys_var *self, THD* thd, enum_var_type type) +{ + bool rcode= false; + + bool wsrep_on_saved= thd->variables.wsrep_on; + thd->variables.wsrep_on= false; + + WSREP_DEBUG("wsrep_provider_update: %s", wsrep_provider); + + /* stop replication is heavy operation, and includes closing all client + connections. Closing clients may need to get LOCK_global_system_variables + at least in MariaDB. + + Note: releasing LOCK_global_system_variables may cause race condition, if + there can be several concurrent clients changing wsrep_provider + */ + mysql_mutex_unlock(&LOCK_global_system_variables); + wsrep_stop_replication(thd); + mysql_mutex_lock(&LOCK_global_system_variables); + + if (wsrep_inited == 1) + wsrep_deinit(false); + + char* tmp= strdup(wsrep_provider); // wsrep_init() rewrites provider + //when fails + if (wsrep_init()) + { + my_error(ER_CANT_OPEN_LIBRARY, MYF(0), tmp); + rcode = true; + } + free(tmp); + + // we sure don't want to use old address with new provider + wsrep_cluster_address_init(NULL); + wsrep_provider_options_init(NULL); + + thd->variables.wsrep_on= wsrep_on_saved; + + refresh_provider_options(); + + return rcode; +} + +void wsrep_provider_init (const char* value) +{ + WSREP_DEBUG("wsrep_provider_init: %s -> %s", + (wsrep_provider) ? wsrep_provider : "null", + (value) ? value : "null"); + if (NULL == value || wsrep_provider_verify (value)) + { + WSREP_ERROR("Bad initial value for wsrep_provider: %s", + (value ? value : "")); + return; + } + + if (wsrep_provider) my_free((void *)wsrep_provider); + wsrep_provider = my_strdup(value, MYF(0)); +} + +bool wsrep_provider_options_check(sys_var *self, THD* thd, set_var* var) +{ + return 0; +} + +bool wsrep_provider_options_update(sys_var *self, THD* thd, enum_var_type type) +{ + wsrep_status_t ret= wsrep->options_set(wsrep, wsrep_provider_options); + if (ret != WSREP_OK) + { + WSREP_ERROR("Set options returned %d", ret); + refresh_provider_options(); + return true; + } + return refresh_provider_options(); +} + +void wsrep_provider_options_init(const char* value) +{ + if (wsrep_provider_options && wsrep_provider_options != value) + my_free((void *)wsrep_provider_options); + wsrep_provider_options = (value) ? my_strdup(value, MYF(0)) : NULL; +} + +static int wsrep_cluster_address_verify (const char* cluster_address_str) +{ + /* There is no predefined address format, it depends on provider. */ + return 0; +} + +bool wsrep_cluster_address_check (sys_var *self, THD* thd, set_var* var) +{ + char addr_buf[FN_REFLEN]; + + if ((! var->save_result.string_value.str) || + (var->save_result.string_value.length > (FN_REFLEN - 1))) // safety + goto err; + + memcpy(addr_buf, var->save_result.string_value.str, + var->save_result.string_value.length); + addr_buf[var->save_result.string_value.length]= 0; + + if (!wsrep_cluster_address_verify(addr_buf)) return 0; + + err: + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, + var->save_result.string_value.str ? + var->save_result.string_value.str : "NULL"); + return 1; +} + +bool wsrep_cluster_address_update (sys_var *self, THD* thd, enum_var_type type) +{ + bool wsrep_on_saved= thd->variables.wsrep_on; + thd->variables.wsrep_on= false; + + /* stop replication is heavy operation, and includes closing all client + connections. Closing clients may need to get LOCK_global_system_variables + at least in MariaDB. + + Note: releasing LOCK_global_system_variables may cause race condition, if + there can be several concurrent clients changing wsrep_provider + */ + mysql_mutex_unlock(&LOCK_global_system_variables); + wsrep_stop_replication(thd); + mysql_mutex_lock(&LOCK_global_system_variables); + + if (wsrep_start_replication()) + { + wsrep_create_rollbacker(); + wsrep_create_appliers(wsrep_slave_threads); + } + + thd->variables.wsrep_on= wsrep_on_saved; + + return false; +} + +void wsrep_cluster_address_init (const char* value) +{ + WSREP_DEBUG("wsrep_cluster_address_init: %s -> %s", + (wsrep_cluster_address) ? wsrep_cluster_address : "null", + (value) ? value : "null"); + + if (wsrep_cluster_address) my_free ((void*)wsrep_cluster_address); + wsrep_cluster_address = (value) ? my_strdup(value, MYF(0)) : NULL; +} + +/* wsrep_cluster_name cannot be NULL or an empty string. */ +bool wsrep_cluster_name_check (sys_var *self, THD* thd, set_var* var) +{ + if (!var->save_result.string_value.str || + (var->save_result.string_value.length == 0)) + { + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, + (var->save_result.string_value.str ? + var->save_result.string_value.str : "NULL")); + return 1; + } + return 0; +} + +bool wsrep_cluster_name_update (sys_var *self, THD* thd, enum_var_type type) +{ + return 0; +} + +bool wsrep_node_name_check (sys_var *self, THD* thd, set_var* var) +{ + // TODO: for now 'allow' 0-length string to be valid (default) + if (!var->save_result.string_value.str) + { + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, + (var->save_result.string_value.str ? + var->save_result.string_value.str : "NULL")); + return 1; + } + return 0; +} + +bool wsrep_node_name_update (sys_var *self, THD* thd, enum_var_type type) +{ + return 0; +} + +// TODO: do something more elaborate, like checking connectivity +bool wsrep_node_address_check (sys_var *self, THD* thd, set_var* var) +{ + char addr_buf[FN_REFLEN]; + + if ((! var->save_result.string_value.str) || + (var->save_result.string_value.length > (FN_REFLEN - 1))) // safety + goto err; + + memcpy(addr_buf, var->save_result.string_value.str, + var->save_result.string_value.length); + addr_buf[var->save_result.string_value.length]= 0; + + // TODO: for now 'allow' 0-length string to be valid (default) + return 0; + +err: + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, + var->save_result.string_value.str ? + var->save_result.string_value.str : "NULL"); + return 1; +} + +bool wsrep_node_address_update (sys_var *self, THD* thd, enum_var_type type) +{ + return 0; +} + +void wsrep_node_address_init (const char* value) +{ + if (wsrep_node_address && strcmp(wsrep_node_address, value)) + my_free ((void*)wsrep_node_address); + + wsrep_node_address = (value) ? my_strdup(value, MYF(0)) : NULL; +} + +bool wsrep_slave_threads_check (sys_var *self, THD* thd, set_var* var) +{ + mysql_mutex_lock(&LOCK_wsrep_slave_threads); + wsrep_slave_count_change += (var->save_result.ulonglong_value - + wsrep_slave_threads); + mysql_mutex_unlock(&LOCK_wsrep_slave_threads); + + return 0; +} + +bool wsrep_slave_threads_update (sys_var *self, THD* thd, enum_var_type type) +{ + if (wsrep_slave_count_change > 0) + { + wsrep_create_appliers(wsrep_slave_count_change); + wsrep_slave_count_change = 0; + } + return false; +} + +bool wsrep_desync_check (sys_var *self, THD* thd, set_var* var) +{ + bool new_wsrep_desync= (bool) var->save_result.ulonglong_value; + if (wsrep_desync == new_wsrep_desync) { + if (new_wsrep_desync) { + push_warning (thd, Sql_condition::WARN_LEVEL_WARN, + ER_WRONG_VALUE_FOR_VAR, + "'wsrep_desync' is already ON."); + } else { + push_warning (thd, Sql_condition::WARN_LEVEL_WARN, + ER_WRONG_VALUE_FOR_VAR, + "'wsrep_desync' is already OFF."); + } + } + return 0; +} + +bool wsrep_desync_update (sys_var *self, THD* thd, enum_var_type type) +{ + wsrep_status_t ret(WSREP_WARNING); + if (wsrep_desync) { + ret = wsrep->desync (wsrep); + if (ret != WSREP_OK) { + WSREP_WARN ("SET desync failed %d for %s", ret, thd->query()); + my_error (ER_CANNOT_USER, MYF(0), "'desync'", thd->query()); + return true; + } + } else { + ret = wsrep->resync (wsrep); + if (ret != WSREP_OK) { + WSREP_WARN ("SET resync failed %d for %s", ret, thd->query()); + my_error (ER_CANNOT_USER, MYF(0), "'resync'", thd->query()); + return true; + } + } + return false; +} + +/* + * Status variables stuff below + */ +static inline void +wsrep_assign_to_mysql (SHOW_VAR* mysql, wsrep_stats_var* wsrep) +{ + mysql->name = wsrep->name; + switch (wsrep->type) { + case WSREP_VAR_INT64: + mysql->value = (char*) &wsrep->value._int64; + mysql->type = SHOW_LONGLONG; + break; + case WSREP_VAR_STRING: + mysql->value = (char*) &wsrep->value._string; + mysql->type = SHOW_CHAR_PTR; + break; + case WSREP_VAR_DOUBLE: + mysql->value = (char*) &wsrep->value._double; + mysql->type = SHOW_DOUBLE; + break; + } +} + +#if DYNAMIC +// somehow this mysql status thing works only with statically allocated arrays. +static SHOW_VAR* mysql_status_vars = NULL; +static int mysql_status_len = -1; +#else +static SHOW_VAR mysql_status_vars[512 + 1]; +static const int mysql_status_len = 512; +#endif + +static void export_wsrep_status_to_mysql(THD* thd) +{ + int wsrep_status_len, i; + + thd->wsrep_status_vars = wsrep->stats_get(wsrep); + + if (!thd->wsrep_status_vars) { + return; + } + + for (wsrep_status_len = 0; + thd->wsrep_status_vars[wsrep_status_len].name != NULL; + wsrep_status_len++); + +#if DYNAMIC + if (wsrep_status_len != mysql_status_len) { + void* tmp = realloc (mysql_status_vars, + (wsrep_status_len + 1) * sizeof(SHOW_VAR)); + if (!tmp) { + + sql_print_error ("Out of memory for wsrep status variables." + "Number of variables: %d", wsrep_status_len); + return; + } + + mysql_status_len = wsrep_status_len; + mysql_status_vars = (SHOW_VAR*)tmp; + } + /* @TODO: fix this: */ +#else + if (mysql_status_len < wsrep_status_len) wsrep_status_len= mysql_status_len; +#endif + + for (i = 0; i < wsrep_status_len; i++) + wsrep_assign_to_mysql (mysql_status_vars + i, thd->wsrep_status_vars + i); + + mysql_status_vars[wsrep_status_len].name = NullS; + mysql_status_vars[wsrep_status_len].value = NullS; + mysql_status_vars[wsrep_status_len].type = SHOW_LONG; +} + +int wsrep_show_status (THD *thd, SHOW_VAR *var, char *buff) +{ + export_wsrep_status_to_mysql(thd); + var->type= SHOW_ARRAY; + var->value= (char *) &mysql_status_vars; + return 0; +} + +void wsrep_free_status (THD* thd) +{ + if (thd->wsrep_status_vars) + { + wsrep->stats_free (wsrep, thd->wsrep_status_vars); + thd->wsrep_status_vars = 0; + } +} diff --git a/sql/wsrep_var.h b/sql/wsrep_var.h new file mode 100644 index 00000000000..58d0374baa5 --- /dev/null +++ b/sql/wsrep_var.h @@ -0,0 +1,86 @@ +/* Copyright (C) 2013 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + +#if !defined (WSREP_VAR_H) && defined(WITH_WSREP) +#define WSREP_VAR_H + +#define WSREP_CLUSTER_NAME "my_wsrep_cluster" +#define WSREP_NODE_INCOMING_AUTO "AUTO" +#define WSREP_START_POSITION_ZERO "00000000-0000-0000-0000-000000000000:-1" + +// MySQL variables funcs + +#include "sql_priv.h" +class sys_var; +class set_var; +class THD; + +int wsrep_init_vars(); + +#define CHECK_ARGS (sys_var *self, THD* thd, set_var *var) +#define UPDATE_ARGS (sys_var *self, THD* thd, enum_var_type type) +#define DEFAULT_ARGS (THD* thd, enum_var_type var_type) +#define INIT_ARGS (const char* opt) + +extern bool wsrep_on_update UPDATE_ARGS; +extern bool wsrep_causal_reads_update UPDATE_ARGS; +extern bool wsrep_sync_wait_update UPDATE_ARGS; +extern bool wsrep_start_position_check CHECK_ARGS; +extern bool wsrep_start_position_update UPDATE_ARGS; +extern void wsrep_start_position_init INIT_ARGS; + +extern bool wsrep_provider_check CHECK_ARGS; +extern bool wsrep_provider_update UPDATE_ARGS; +extern void wsrep_provider_init INIT_ARGS; + +extern bool wsrep_provider_options_check CHECK_ARGS; +extern bool wsrep_provider_options_update UPDATE_ARGS; +extern void wsrep_provider_options_init INIT_ARGS; + +extern bool wsrep_cluster_address_check CHECK_ARGS; +extern bool wsrep_cluster_address_update UPDATE_ARGS; +extern void wsrep_cluster_address_init INIT_ARGS; + +extern bool wsrep_cluster_name_check CHECK_ARGS; +extern bool wsrep_cluster_name_update UPDATE_ARGS; + +extern bool wsrep_node_name_check CHECK_ARGS; +extern bool wsrep_node_name_update UPDATE_ARGS; + +extern bool wsrep_node_address_check CHECK_ARGS; +extern bool wsrep_node_address_update UPDATE_ARGS; +extern void wsrep_node_address_init INIT_ARGS; + +extern bool wsrep_sst_method_check CHECK_ARGS; +extern bool wsrep_sst_method_update UPDATE_ARGS; +extern void wsrep_sst_method_init INIT_ARGS; + +extern bool wsrep_sst_receive_address_check CHECK_ARGS; +extern bool wsrep_sst_receive_address_update UPDATE_ARGS; + +extern bool wsrep_sst_auth_check CHECK_ARGS; +extern bool wsrep_sst_auth_update UPDATE_ARGS; +extern void wsrep_sst_auth_init INIT_ARGS; + +extern bool wsrep_sst_donor_check CHECK_ARGS; +extern bool wsrep_sst_donor_update UPDATE_ARGS; + +extern bool wsrep_slave_threads_check CHECK_ARGS; +extern bool wsrep_slave_threads_update UPDATE_ARGS; + +extern bool wsrep_desync_check CHECK_ARGS; +extern bool wsrep_desync_update UPDATE_ARGS; + +#endif /* WSREP_VAR_H */ diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt index 622fff87536..12d43bba5bc 100644 --- a/storage/innobase/CMakeLists.txt +++ b/storage/innobase/CMakeLists.txt @@ -251,6 +251,27 @@ ENDIF() INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/storage/innobase/include ${CMAKE_SOURCE_DIR}/storage/innobase/handler) +IF(WITH_WSREP) + # ssl include directory + INCLUDE_DIRECTORIES(${SSL_INCLUDE_DIRS} + ${CMAKE_SOURCE_DIR}/storage/innobase/wsrep) + + IF(SSL_DEFINES) + ADD_DEFINITIONS(${SSL_DEFINES}) + ENDIF() + + LINK_LIBRARIES(${SSL_LIBRARIES}) + + # We do RESTRICT_SYMBOL_EXPORTS(yassl) elsewhere. + # In order to get correct symbol visibility, these files + # must be compiled with "-fvisibility=hidden" + IF(WITH_SSL STREQUAL "bundled" AND HAVE_VISIBILITY_HIDDEN) + SET_SOURCE_FILES_PROPERTIES( + {CMAKE_CURRENT_SOURCE_DIR}/wsrep/md5.cc + PROPERTIES COMPILE_FLAGS "-fvisibility=hidden") + ENDIF() +ENDIF() + # Sun Studio bug with -xO2 IF(CMAKE_CXX_COMPILER_ID MATCHES "SunPro" AND CMAKE_CXX_FLAGS_RELEASE MATCHES "O2" @@ -397,6 +418,10 @@ SET(INNOBASE_SOURCES ut/ut0vec.cc ut/ut0wqueue.cc) +IF(WITH_WSREP) + SET(INNOBASE_SOURCES ${INNOBASE_SOURCES} wsrep/md5.cc) +ENDIF() + IF(WITH_INNODB) # Legacy option SET(WITH_INNOBASE_STORAGE_ENGINE TRUE) diff --git a/storage/innobase/buf/buf0rea.cc b/storage/innobase/buf/buf0rea.cc index ec76c9923fe..9e81d010d0f 100644 --- a/storage/innobase/buf/buf0rea.cc +++ b/storage/innobase/buf/buf0rea.cc @@ -1,7 +1,6 @@ /***************************************************************************** Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2013, 2014, SkySQL Ab. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -185,14 +184,15 @@ buf_read_page_low( *err = fil_io(OS_FILE_READ | wake_later | ignore_nonexistent_pages, sync, space, zip_size, offset, 0, zip_size, - bpage->zip.data, bpage, &bpage->write_size); + bpage->zip.data, bpage, &bpage->write_size); } else { ut_a(buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE); *err = fil_io(OS_FILE_READ | wake_later | ignore_nonexistent_pages, sync, space, 0, offset, 0, UNIV_PAGE_SIZE, - ((buf_block_t*) bpage)->frame, bpage, 0); + ((buf_block_t*) bpage)->frame, bpage, + &bpage->write_size); } if (sync) { diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 0c83089478a..72a0f39e19e 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -3237,7 +3237,29 @@ dict_foreign_find_index( return(NULL); } - +#ifdef WITH_WSREP +dict_index_t* +wsrep_dict_foreign_find_index( +/*====================*/ + dict_table_t* table, /*!< in: table */ + const char** col_names, /*!< in: column names, or NULL + to use table->col_names */ + const char** columns,/*!< in: array of column names */ + ulint n_cols, /*!< in: number of columns */ + dict_index_t* types_idx, /*!< in: NULL or an index to whose types the + column types must match */ + ibool check_charsets, + /*!< in: whether to check charsets. + only has an effect if types_idx != NULL */ + ulint check_null) + /*!< in: nonzero if none of the columns must + be declared NOT NULL */ +{ + return dict_foreign_find_index( + table, col_names, columns, n_cols, types_idx, check_charsets, + check_null); +} +#endif /* WITH_WSREP */ /**********************************************************************//** Report an error in a foreign key definition. */ static diff --git a/storage/innobase/fil/fil0pagecompress.cc b/storage/innobase/fil/fil0pagecompress.cc index a81a982db6c..f324631dff1 100644 --- a/storage/innobase/fil/fil0pagecompress.cc +++ b/storage/innobase/fil/fil0pagecompress.cc @@ -490,7 +490,9 @@ fil_decompress_page( ulint actual_size = 0; ulint compression_alg = 0; byte *in_buf; +#ifdef HAVE_LZO ulint olen=0; +#endif ulint ptype; ut_ad(buf); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index ead86fd3085..970127a7420 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -117,6 +117,46 @@ this program; if not, write to the Free Software Foundation, Inc., # define MYSQL_PLUGIN_IMPORT /* nothing */ # endif /* MYSQL_PLUGIN_IMPORT */ +#ifdef WITH_WSREP +#include "dict0priv.h" +#include "../storage/innobase/include/ut0byte.h" +#include +#include + +extern my_bool wsrep_certify_nonPK; +class binlog_trx_data; +extern handlerton *binlog_hton; + +extern MYSQL_PLUGIN_IMPORT MYSQL_BIN_LOG mysql_bin_log; +extern MYSQL_PLUGIN_IMPORT mysql_mutex_t LOCK_wsrep_rollback; +extern MYSQL_PLUGIN_IMPORT mysql_cond_t COND_wsrep_rollback; +extern MYSQL_PLUGIN_IMPORT wsrep_aborting_thd_t wsrep_aborting_thd; + +static inline wsrep_ws_handle_t* +wsrep_ws_handle(THD* thd, const trx_t* trx) { + return wsrep_ws_handle_for_trx(wsrep_thd_ws_handle(thd), + (wsrep_trx_id_t)trx->id); +} + +extern bool wsrep_prepare_key_for_innodb(const uchar *cache_key, + size_t cache_key_len, + const uchar* row_id, + size_t row_id_len, + wsrep_buf_t* key, + size_t* key_len); + +extern handlerton * wsrep_hton; +extern TC_LOG* tc_log; +extern void wsrep_cleanup_transaction(THD *thd); +static int +wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd, + my_bool signal); +static void +wsrep_fake_trx_id(handlerton* hton, THD *thd); +static int innobase_wsrep_set_checkpoint(handlerton* hton, const XID* xid); +static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid); +#endif /* WITH_WSREP */ + /** to protect innobase_open_files */ static mysql_mutex_t innobase_share_mutex; /** to force correct commit order in binlog */ @@ -1253,6 +1293,10 @@ innobase_srv_conc_enter_innodb( /*===========================*/ trx_t* trx) /*!< in: transaction handle */ { +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd) && + wsrep_thd_is_BF(trx->mysql_thd, FALSE)) return; +#endif /* WITH_WSREP */ if (srv_thread_concurrency) { if (trx->n_tickets_to_enter_innodb > 0) { @@ -1287,6 +1331,10 @@ innobase_srv_conc_exit_innodb( #ifdef UNIV_SYNC_DEBUG ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch)); #endif /* UNIV_SYNC_DEBUG */ +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd) && + wsrep_thd_is_BF(trx->mysql_thd, FALSE)) return; +#endif /* WITH_WSREP */ /* This is to avoid making an unnecessary function call. */ if (trx->declared_to_be_inside_innodb @@ -1407,6 +1455,15 @@ thd_to_trx( { return(*(trx_t**) thd_ha_data(thd, innodb_hton_ptr)); } +#ifdef WITH_WSREP +ulonglong +thd_to_trx_id( +/*=======*/ + THD* thd) /*!< in: MySQL thread */ +{ + return(thd_to_trx(thd)->id); +} +#endif /* WITH_WSREP */ /********************************************************************//** Call this function when mysqld passes control to the client. That is to @@ -1892,6 +1949,9 @@ int innobase_mysql_tmpfile(void) /*========================*/ { +#ifdef WITH_INNODB_DISALLOW_WRITES + os_event_wait(srv_allow_writes_event); +#endif /* WITH_INNODB_DISALLOW_WRITES */ int fd2 = -1; File fd; @@ -2957,6 +3017,12 @@ innobase_init( innobase_hton->release_temporary_latches = innobase_release_temporary_latches; +#ifdef WITH_WSREP + innobase_hton->abort_transaction=wsrep_abort_transaction; + innobase_hton->set_checkpoint=innobase_wsrep_set_checkpoint; + innobase_hton->get_checkpoint=innobase_wsrep_get_checkpoint; + innobase_hton->fake_trx_id=wsrep_fake_trx_id; +#endif /* WITH_WSREP */ innobase_hton->kill_query = innobase_kill_query; if (srv_file_per_table) @@ -3615,10 +3681,30 @@ innobase_commit_low( /*================*/ trx_t* trx) /*!< in: transaction handle */ { +#ifdef WITH_WSREP + THD* thd = (THD*)trx->mysql_thd; + const char* tmp = 0; + if (wsrep_on((void*)thd)) { +#ifdef WSREP_PROC_INFO + char info[64]; + info[sizeof(info) - 1] = '\0'; + snprintf(info, sizeof(info) - 1, + "innobase_commit_low():trx_commit_for_mysql(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); + tmp = thd_proc_info(thd, info); + +#else + tmp = thd_proc_info(thd, "innobase_commit_low()"); +#endif /* WSREP_PROC_INFO */ + } +#endif /* WITH_WSREP */ if (trx_is_started(trx)) { trx_commit_for_mysql(trx); } +#ifdef WITH_WSREP + if (wsrep_on((void*)thd)) { thd_proc_info(thd, tmp); } +#endif /* WITH_WSREP */ } /*****************************************************************//** @@ -4343,6 +4429,20 @@ innobase_kill_query( DBUG_ENTER("innobase_kill_query"); DBUG_ASSERT(hton == innodb_hton_ptr); +#ifdef WITH_WSREP + wsrep_thd_LOCK(thd); + if (wsrep_thd_conflict_state(thd) != NO_CONFLICT) { + /* if victim has been signaled by BF thread and/or aborting + is already progressing, following query aborting is not necessary + any more. + Also, BF thread should own trx mutex for the victim, which would + conflict with trx_mutex_enter() below + */ + wsrep_thd_UNLOCK(thd); + DBUG_VOID_RETURN; + } + wsrep_thd_UNLOCK(thd); +#endif /* WITH_WSREP */ trx = thd_to_trx(thd); if (trx) @@ -4513,7 +4613,11 @@ ha_innobase::max_supported_key_length() const case 8192: return(1536); default: +#ifdef WITH_WSREP return(3500); +#else + return(3500); +#endif } } @@ -5620,6 +5724,117 @@ get_field_offset( return((uint) (field->ptr - table->record[0])); } +#ifdef WITH_WSREP +UNIV_INTERN +int +wsrep_innobase_mysql_sort( +/*===============*/ + /* out: str contains sort string */ + int mysql_type, /* in: MySQL type */ + uint charset_number, /* in: number of the charset */ + unsigned char* str, /* in: data field */ + unsigned int str_length, /* in: data field length, + not UNIV_SQL_NULL */ + unsigned int buf_length) /* in: total str buffer length */ + +{ + CHARSET_INFO* charset; + enum_field_types mysql_tp; + int ret_length = str_length; + + DBUG_ASSERT(str_length != UNIV_SQL_NULL); + + mysql_tp = (enum_field_types) mysql_type; + + switch (mysql_tp) { + + case MYSQL_TYPE_BIT: + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_VARCHAR: + { + uchar tmp_str[REC_VERSION_56_MAX_INDEX_COL_LEN] = {'\0'}; + uint tmp_length = REC_VERSION_56_MAX_INDEX_COL_LEN; + + /* Use the charset number to pick the right charset struct for + the comparison. Since the MySQL function get_charset may be + slow before Bar removes the mutex operation there, we first + look at 2 common charsets directly. */ + + if (charset_number == default_charset_info->number) { + charset = default_charset_info; + } else if (charset_number == my_charset_latin1.number) { + charset = &my_charset_latin1; + } else { + charset = get_charset(charset_number, MYF(MY_WME)); + + if (charset == NULL) { + sql_print_error("InnoDB needs charset %lu for doing " + "a comparison, but MySQL cannot " + "find that charset.", + (ulong) charset_number); + ut_a(0); + } + } + + ut_a(str_length <= tmp_length); + memcpy(tmp_str, str, str_length); + + tmp_length = charset->coll->strnxfrm(charset, str, str_length, + str_length, tmp_str, + tmp_length, 0); + DBUG_ASSERT(tmp_length <= str_length); + if (wsrep_protocol_version < 3) { + tmp_length = charset->coll->strnxfrm( + charset, str, str_length, + str_length, tmp_str, tmp_length, 0); + DBUG_ASSERT(tmp_length <= str_length); + } else { + /* strnxfrm will expand the destination string, + protocols < 3 truncated the sorted sring + protocols >= 3 gets full sorted sring + */ + tmp_length = charset->coll->strnxfrm( + charset, str, buf_length, + str_length, tmp_str, str_length, 0); + DBUG_ASSERT(tmp_length <= buf_length); + ret_length = tmp_length; + } + + break; + } + case MYSQL_TYPE_DECIMAL : + case MYSQL_TYPE_TINY : + case MYSQL_TYPE_SHORT : + case MYSQL_TYPE_LONG : + case MYSQL_TYPE_FLOAT : + case MYSQL_TYPE_DOUBLE : + case MYSQL_TYPE_NULL : + case MYSQL_TYPE_TIMESTAMP : + case MYSQL_TYPE_LONGLONG : + case MYSQL_TYPE_INT24 : + case MYSQL_TYPE_DATE : + case MYSQL_TYPE_TIME : + case MYSQL_TYPE_DATETIME : + case MYSQL_TYPE_YEAR : + case MYSQL_TYPE_NEWDATE : + case MYSQL_TYPE_NEWDECIMAL : + case MYSQL_TYPE_ENUM : + case MYSQL_TYPE_SET : + case MYSQL_TYPE_GEOMETRY : + break; + default: + break; + } + + return ret_length; +} +#endif /* WITH_WSREP */ + /*************************************************************//** InnoDB uses this function to compare two data fields for which the data type is such that we must use MySQL code to compare them. NOTE that the prototype @@ -6120,11 +6335,313 @@ innobase_read_from_2_little_endian( return((uint) ((ulint)(buf[0]) + 256 * ((ulint)(buf[1])))); } +#ifdef WITH_WSREP /*******************************************************************//** Stores a key value for a row to a buffer. @return key value length as stored in buff */ UNIV_INTERN uint +wsrep_store_key_val_for_row( +/*===============================*/ + THD* thd, + TABLE* table, + uint keynr, /*!< in: key number */ + char* buff, /*!< in/out: buffer for the key value (in MySQL + format) */ + uint buff_len,/*!< in: buffer length */ + const uchar* record, + ibool* key_is_null)/*!< out: full key was null */ +{ + KEY* key_info = table->key_info + keynr; + KEY_PART_INFO* key_part = key_info->key_part; + KEY_PART_INFO* end = key_part + key_info->user_defined_key_parts; + char* buff_start = buff; + enum_field_types mysql_type; + Field* field; + uint buff_space = buff_len; + + DBUG_ENTER("wsrep_store_key_val_for_row"); + + memset(buff, 0, buff_len); + *key_is_null = TRUE; + + for (; key_part != end; key_part++) { + + uchar sorted[REC_VERSION_56_MAX_INDEX_COL_LEN] = {'\0'}; + ibool part_is_null = FALSE; + + if (key_part->null_bit) { + if (buff_space > 0) { + if (record[key_part->null_offset] + & key_part->null_bit) { + *buff = 1; + part_is_null = TRUE; + } else { + *buff = 0; + } + buff++; + buff_space--; + } else { + fprintf (stderr, "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); + } + } + if (!part_is_null) *key_is_null = FALSE; + + field = key_part->field; + mysql_type = field->type(); + + if (mysql_type == MYSQL_TYPE_VARCHAR) { + /* >= 5.0.3 true VARCHAR */ + ulint lenlen; + ulint len; + const byte* data; + ulint key_len; + ulint true_len; + const CHARSET_INFO* cs; + int error=0; + + key_len = key_part->length; + + if (part_is_null) { + true_len = key_len + 2; + if (true_len > buff_space) { + fprintf (stderr, + "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); + true_len = buff_space; + } + buff += true_len; + buff_space -= true_len; + continue; + } + cs = field->charset(); + + lenlen = (ulint) + (((Field_varstring*)field)->length_bytes); + + data = row_mysql_read_true_varchar(&len, + (byte*) (record + + (ulint)get_field_offset(table, field)), + lenlen); + + true_len = len; + + /* For multi byte character sets we need to calculate + the true length of the key */ + + if (len > 0 && cs->mbmaxlen > 1) { + true_len = (ulint) cs->cset->well_formed_len(cs, + (const char *) data, + (const char *) data + len, + (uint) (key_len / + cs->mbmaxlen), + &error); + } + + /* In a column prefix index, we may need to truncate + the stored value: */ + + if (true_len > key_len) { + true_len = key_len; + } + + memcpy(sorted, data, true_len); + true_len = wsrep_innobase_mysql_sort( + mysql_type, cs->number, sorted, true_len, + REC_VERSION_56_MAX_INDEX_COL_LEN); + + if (wsrep_protocol_version > 1) { + /* Note that we always reserve the maximum possible + length of the true VARCHAR in the key value, though + only len first bytes after the 2 length bytes contain + actual data. The rest of the space was reset to zero + in the bzero() call above. */ + if (true_len > buff_space) { + fprintf (stderr, + "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); + true_len = buff_space; + } + memcpy(buff, sorted, true_len); + buff += true_len; + buff_space -= true_len; + } else { + buff += key_len; + } + } else if (mysql_type == MYSQL_TYPE_TINY_BLOB + || mysql_type == MYSQL_TYPE_MEDIUM_BLOB + || mysql_type == MYSQL_TYPE_BLOB + || mysql_type == MYSQL_TYPE_LONG_BLOB + /* MYSQL_TYPE_GEOMETRY data is treated + as BLOB data in innodb. */ + || mysql_type == MYSQL_TYPE_GEOMETRY) { + + const CHARSET_INFO* cs; + ulint key_len; + ulint true_len; + int error=0; + ulint blob_len; + const byte* blob_data; + + ut_a(key_part->key_part_flag & HA_PART_KEY_SEG); + + key_len = key_part->length; + + if (part_is_null) { + true_len = key_len + 2; + if (true_len > buff_space) { + fprintf (stderr, + "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); + true_len = buff_space; + } + buff += true_len; + buff_space -= true_len; + + continue; + } + + cs = field->charset(); + + blob_data = row_mysql_read_blob_ref(&blob_len, + (byte*) (record + + (ulint)get_field_offset(table, field)), + (ulint) field->pack_length()); + + true_len = blob_len; + + ut_a(get_field_offset(table, field) + == key_part->offset); + + /* For multi byte character sets we need to calculate + the true length of the key */ + + if (blob_len > 0 && cs->mbmaxlen > 1) { + true_len = (ulint) cs->cset->well_formed_len(cs, + (const char *) blob_data, + (const char *) blob_data + + blob_len, + (uint) (key_len / + cs->mbmaxlen), + &error); + } + + /* All indexes on BLOB and TEXT are column prefix + indexes, and we may need to truncate the data to be + stored in the key value: */ + + if (true_len > key_len) { + true_len = key_len; + } + + memcpy(sorted, blob_data, true_len); + true_len = wsrep_innobase_mysql_sort( + mysql_type, cs->number, sorted, true_len, + REC_VERSION_56_MAX_INDEX_COL_LEN); + + + /* Note that we always reserve the maximum possible + length of the BLOB prefix in the key value. */ + if (wsrep_protocol_version > 1) { + if (true_len > buff_space) { + fprintf (stderr, + "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); + true_len = buff_space; + } + buff += true_len; + buff_space -= true_len; + } else { + buff += key_len; + } + memcpy(buff, sorted, true_len); + } else { + /* Here we handle all other data types except the + true VARCHAR, BLOB and TEXT. Note that the column + value we store may be also in a column prefix + index. */ + + const CHARSET_INFO* cs = NULL; + ulint true_len; + ulint key_len; + const uchar* src_start; + int error=0; + enum_field_types real_type; + + key_len = key_part->length; + + if (part_is_null) { + true_len = key_len; + if (true_len > buff_space) { + fprintf (stderr, + "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); + true_len = buff_space; + } + buff += true_len; + buff_space -= true_len; + + continue; + } + + src_start = record + key_part->offset; + real_type = field->real_type(); + true_len = key_len; + + /* Character set for the field is defined only + to fields whose type is string and real field + type is not enum or set. For these fields check + if character set is multi byte. */ + + if (real_type != MYSQL_TYPE_ENUM + && real_type != MYSQL_TYPE_SET + && ( mysql_type == MYSQL_TYPE_VAR_STRING + || mysql_type == MYSQL_TYPE_STRING)) { + + cs = field->charset(); + + /* For multi byte character sets we need to + calculate the true length of the key */ + + if (key_len > 0 && cs->mbmaxlen > 1) { + + true_len = (ulint) + cs->cset->well_formed_len(cs, + (const char *)src_start, + (const char *)src_start + + key_len, + (uint) (key_len / + cs->mbmaxlen), + &error); + } + memcpy(sorted, src_start, true_len); + true_len = wsrep_innobase_mysql_sort( + mysql_type, cs->number, sorted, true_len, + REC_VERSION_56_MAX_INDEX_COL_LEN); + + if (true_len > buff_space) { + fprintf (stderr, + "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); + true_len = buff_space; + } + memcpy(buff, sorted, true_len); + } else { + memcpy(buff, src_start, true_len); + } + buff += true_len; + buff_space -= true_len; + } + } + + ut_a(buff <= buff_start + buff_len); + + DBUG_RETURN((uint)(buff - buff_start)); +} +#endif /* WITH_WSREP */ +UNIV_INTERN +uint ha_innobase::store_key_val_for_row( /*===============================*/ uint keynr, /*!< in: key number */ @@ -6965,6 +7482,9 @@ ha_innobase::write_row( dberr_t error; int error_result= 0; ibool auto_inc_used= FALSE; +#ifdef WITH_WSREP + ibool auto_inc_inserted= FALSE; /* if NULL was inserted */ +#endif ulint sql_command; trx_t* trx = thd_to_trx(user_thd); @@ -6998,8 +7518,20 @@ ha_innobase::write_row( if ((sql_command == SQLCOM_ALTER_TABLE || sql_command == SQLCOM_OPTIMIZE || sql_command == SQLCOM_CREATE_INDEX +#ifdef WITH_WSREP + || (wsrep_on(user_thd) && wsrep_load_data_splitting && + sql_command == SQLCOM_LOAD && + !thd_test_options( + user_thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) +#endif /* WITH_WSREP */ || sql_command == SQLCOM_DROP_INDEX) && num_write_row >= 10000) { +#ifdef WITH_WSREP + if (wsrep_on(user_thd) && sql_command == SQLCOM_LOAD) { + WSREP_DEBUG("forced trx split for LOAD: %s", + wsrep_thd_query(user_thd)); + } +#endif /* WITH_WSREP */ /* ALTER TABLE is COMMITted at every 10000 copied rows. The IX table lock for the original table has to be re-issued. As this method will be called on a temporary table where the @@ -7033,6 +7565,21 @@ no_commit: */ ; } else if (src_table == prebuilt->table) { +#ifdef WITH_WSREP + switch (wsrep_run_wsrep_commit(user_thd, wsrep_hton, 1)) + { + case WSREP_TRX_OK: + break; + case WSREP_TRX_SIZE_EXCEEDED: + case WSREP_TRX_CERT_FAIL: + case WSREP_TRX_ERROR: + DBUG_RETURN(1); + } + + if (binlog_hton->commit(binlog_hton, user_thd, 1)) + DBUG_RETURN(1); + wsrep_post_commit(user_thd, TRUE); +#endif /* WITH_WSREP */ /* Source table is not in InnoDB format: no need to re-acquire locks on it. */ @@ -7043,6 +7590,21 @@ no_commit: /* We will need an IX lock on the destination table. */ prebuilt->sql_stat_start = TRUE; } else { +#ifdef WITH_WSREP + switch (wsrep_run_wsrep_commit(user_thd, wsrep_hton, 1)) + { + case WSREP_TRX_OK: + break; + case WSREP_TRX_SIZE_EXCEEDED: + case WSREP_TRX_CERT_FAIL: + case WSREP_TRX_ERROR: + DBUG_RETURN(1); + } + + if (binlog_hton->commit(binlog_hton, user_thd, 1)) + DBUG_RETURN(1); + wsrep_post_commit(user_thd, TRUE); +#endif /* WITH_WSREP */ /* Ensure that there are no other table locks than LOCK_IX and LOCK_AUTO_INC on the destination table. */ @@ -7072,6 +7634,10 @@ no_commit: innobase_get_auto_increment(). */ prebuilt->autoinc_error = DB_SUCCESS; +#ifdef WITH_WSREP + auto_inc_inserted= (table->next_number_field->val_int() == 0); +#endif + if ((error_result = update_auto_increment())) { /* We don't want to mask autoinc overflow errors. */ @@ -7150,6 +7716,33 @@ no_commit: case SQLCOM_REPLACE_SELECT: goto set_max_autoinc; +#ifdef WITH_WSREP + /* workaround for LP bug #355000, retrying the insert */ + case SQLCOM_INSERT: + if (wsrep_on(current_thd) && + auto_inc_inserted && + wsrep_drupal_282555_workaround && + wsrep_thd_retry_counter(current_thd) == 0 && + !thd_test_options(current_thd, + OPTION_NOT_AUTOCOMMIT | + OPTION_BEGIN)) { + WSREP_DEBUG( + "retrying insert: %s", + (*wsrep_thd_query(current_thd)) ? + wsrep_thd_query(current_thd) : + (char *)"void"); + error= DB_SUCCESS; + wsrep_thd_set_conflict_state( + current_thd, MUST_ABORT); + innobase_srv_conc_exit_innodb( + prebuilt->trx); + /* jump straight to func exit over + * later wsrep hooks */ + goto func_exit; + } + break; +#endif /* WITH_WSREP */ + default: break; } @@ -7209,6 +7802,21 @@ report_error: prebuilt->table->flags, user_thd); +#ifdef WITH_WSREP + if (!error_result && wsrep_thd_exec_mode(user_thd) == LOCAL_STATE && + wsrep_on(user_thd) && !wsrep_consistency_check(user_thd) && + (sql_command != SQLCOM_LOAD || + thd_binlog_format(user_thd) == BINLOG_FORMAT_ROW)) { + + if (wsrep_append_keys(user_thd, false, record, NULL)) { + DBUG_PRINT("wsrep", ("row key failed")); + error_result = HA_ERR_INTERNAL_ERROR; + goto wsrep_error; + } + } +wsrep_error: +#endif /* WITH_WSREP */ + if (error_result == HA_FTS_INVALID_DOCID) { my_error(HA_FTS_INVALID_DOCID, MYF(0)); } @@ -7496,6 +8104,87 @@ calc_row_difference( return(DB_SUCCESS); } +#ifdef WITH_WSREP +static +int +wsrep_calc_row_hash( +/*================*/ + byte* digest, /*!< in/out: md5 sum */ + const uchar* row, /*!< in: row in MySQL format */ + TABLE* table, /*!< in: table in MySQL data + dictionary */ + row_prebuilt_t* prebuilt, /*!< in: InnoDB prebuilt struct */ + THD* thd) /*!< in: user thread */ +{ + Field* field; + enum_field_types field_mysql_type; + uint n_fields; + ulint len; + const byte* ptr; + ulint col_type; + uint i; + + void *ctx = wsrep_md5_init(); + + n_fields = table->s->fields; + + for (i = 0; i < n_fields; i++) { + byte null_byte=0; + byte true_byte=1; + + field = table->field[i]; + + ptr = (const byte*) row + get_field_offset(table, field); + len = field->pack_length(); + + field_mysql_type = field->type(); + + col_type = prebuilt->table->cols[i].mtype; + + switch (col_type) { + + case DATA_BLOB: + ptr = row_mysql_read_blob_ref(&len, ptr, len); + + break; + + case DATA_VARCHAR: + case DATA_BINARY: + case DATA_VARMYSQL: + if (field_mysql_type == MYSQL_TYPE_VARCHAR) { + /* This is a >= 5.0.3 type true VARCHAR where + the real payload data length is stored in + 1 or 2 bytes */ + + ptr = row_mysql_read_true_varchar( + &len, ptr, + (ulint) + (((Field_varstring*)field)->length_bytes)); + + } + + break; + default: + ; + } + /* + if (field->null_ptr && + field_in_record_is_null(table, field, (char*) row)) { + */ + + if (field->is_null_in_record(row)) { + wsrep_md5_update(ctx, (char*)&null_byte, 1); + } else { + wsrep_md5_update(ctx, (char*)&true_byte, 1); + wsrep_md5_update(ctx, (char*)ptr, len); + } + } + + wsrep_compute_md5_hash((char*)digest, ctx); + + return(0); +} +#endif /* WITH_WSREP */ /**********************************************************************//** Updates a row given as a parameter to a new value. Note that we are given whole rows, not just the fields which are updated: this incurs some @@ -7633,6 +8322,24 @@ func_exit: innobase_active_small(); +#ifdef WITH_WSREP + if (error == DB_SUCCESS && + wsrep_thd_exec_mode(user_thd) == LOCAL_STATE && + wsrep_on(user_thd)) { + + DBUG_PRINT("wsrep", ("update row key")); + + if (wsrep_append_keys(user_thd, false, old_row, new_row)) { + WSREP_DEBUG("WSREP: UPDATE_ROW_KEY FAILED"); + DBUG_PRINT("wsrep", ("row key failed")); + err = HA_ERR_INTERNAL_ERROR; + goto wsrep_error; + } + } +wsrep_error: +#endif /* WITH_WSREP */ + + DBUG_RETURN(err); } @@ -7680,6 +8387,19 @@ ha_innobase::delete_row( innobase_active_small(); +#ifdef WITH_WSREP + if (error == DB_SUCCESS && + wsrep_thd_exec_mode(user_thd) == LOCAL_STATE && + wsrep_on(user_thd)) { + + if (wsrep_append_keys(user_thd, false, record, NULL)) { + DBUG_PRINT("wsrep", ("delete fail")); + error = (dberr_t)HA_ERR_INTERNAL_ERROR; + goto wsrep_error; + } + } +wsrep_error: +#endif DBUG_RETURN(convert_error_code_to_mysql( error, prebuilt->table->flags, user_thd)); } @@ -8840,6 +9560,394 @@ ha_innobase::ft_end() rnd_end(); } +#ifdef WITH_WSREP +extern dict_index_t* +wsrep_dict_foreign_find_index( + dict_table_t* table, + const char** col_names, + const char** columns, + ulint n_cols, + dict_index_t* types_idx, + ibool check_charsets, + ulint check_null); + + +extern dberr_t +wsrep_append_foreign_key( +/*===========================*/ + trx_t* trx, /*!< in: trx */ + dict_foreign_t* foreign, /*!< in: foreign key constraint */ + const rec_t* rec, /*!mysql_thd; + ulint rcode = DB_SUCCESS; + char cache_key[513] = {'\0'}; + int cache_key_len; + bool const copy = true; + + if (!wsrep_on(trx->mysql_thd) || + wsrep_thd_exec_mode(thd) != LOCAL_STATE) + return DB_SUCCESS; + + if (!thd || !foreign || + (!foreign->referenced_table && !foreign->foreign_table)) + { + WSREP_INFO("FK: %s missing in: %s", + (!thd) ? "thread" : + ((!foreign) ? "constraint" : + ((!foreign->referenced_table) ? + "referenced table" : "foreign table")), + (thd && wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + return DB_ERROR; + } + + if ( !((referenced) ? + foreign->referenced_table : foreign->foreign_table)) + { + WSREP_DEBUG("pulling %s table into cache", + (referenced) ? "referenced" : "foreign"); + mutex_enter(&(dict_sys->mutex)); + if (referenced) + { + foreign->referenced_table = + dict_table_get_low( + foreign->referenced_table_name_lookup); + if (foreign->referenced_table) + { + foreign->referenced_index = + wsrep_dict_foreign_find_index( + foreign->referenced_table, NULL, + foreign->referenced_col_names, + foreign->n_fields, + foreign->foreign_index, + TRUE, FALSE); + } + } + else + { + foreign->foreign_table = + dict_table_get_low( + foreign->foreign_table_name_lookup); + if (foreign->foreign_table) + { + foreign->foreign_index = + wsrep_dict_foreign_find_index( + foreign->foreign_table, NULL, + foreign->foreign_col_names, + foreign->n_fields, + foreign->referenced_index, + TRUE, FALSE); + } + } + mutex_exit(&(dict_sys->mutex)); + } + + if ( !((referenced) ? + foreign->referenced_table : foreign->foreign_table)) + { + WSREP_WARN("FK: %s missing in query: %s", + (!foreign->referenced_table) ? + "referenced table" : "foreign table", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + return DB_ERROR; + } + byte key[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + ulint len = WSREP_MAX_SUPPORTED_KEY_LENGTH; + + dict_index_t *idx_target = (referenced) ? + foreign->referenced_index : index; + dict_index_t *idx = (referenced) ? + UT_LIST_GET_FIRST(foreign->referenced_table->indexes) : + UT_LIST_GET_FIRST(foreign->foreign_table->indexes); + int i = 0; + while (idx != NULL && idx != idx_target) { + if (innobase_strcasecmp (idx->name, innobase_index_reserve_name) != 0) { + i++; + } + idx = UT_LIST_GET_NEXT(indexes, idx); + } + ut_a(idx); + key[0] = (char)i; + + rcode = wsrep_rec_get_foreign_key( + &key[1], &len, rec, index, idx, + wsrep_protocol_version > 1); + if (rcode != DB_SUCCESS) { + WSREP_ERROR( + "FK key set failed: %lu (%lu %lu), index: %s %s, %s", + rcode, referenced, shared, + (index && index->name) ? index->name : + "void index", + (index && index->table_name) ? index->table_name : + "void table", + wsrep_thd_query(thd)); + return DB_ERROR; + } + strncpy(cache_key, + (wsrep_protocol_version > 1) ? + ((referenced) ? + foreign->referenced_table->name : + foreign->foreign_table->name) : + foreign->foreign_table->name, sizeof(cache_key) - 1); + cache_key_len = strlen(cache_key); +#ifdef WSREP_DEBUG_PRINT + ulint j; + fprintf(stderr, "FK parent key, table: %s %s len: %lu ", + cache_key, (shared) ? "shared" : "exclusive", len+1); + for (j=0; jreferenced_table->name, + foreign->foreign_table->name); + } + + wsrep_buf_t wkey_part[3]; + wsrep_key_t wkey = {wkey_part, 3}; + if (!wsrep_prepare_key_for_innodb( + (const uchar*)cache_key, + cache_key_len + 1, + (const uchar*)key, len+1, + wkey_part, + (size_t*)&wkey.key_parts_num)) { + WSREP_WARN("key prepare failed for cascaded FK: %s", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + return DB_ERROR; + } + rcode = (int)wsrep->append_key( + wsrep, + wsrep_ws_handle(thd, trx), + &wkey, + 1, + shared ? WSREP_KEY_SHARED : WSREP_KEY_EXCLUSIVE, + copy); + if (rcode) { + DBUG_PRINT("wsrep", ("row key failed: %lu", rcode)); + WSREP_ERROR("Appending cascaded fk row key failed: %s, %lu", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void", rcode); + return DB_ERROR; + } + + return DB_SUCCESS; +} + +static int +wsrep_append_key( +/*==================*/ + THD *thd, + trx_t *trx, + TABLE_SHARE *table_share, + TABLE *table, + const char* key, + uint16_t key_len, + bool shared +) +{ + DBUG_ENTER("wsrep_append_key"); + bool const copy = true; +#ifdef WSREP_DEBUG_PRINT + fprintf(stderr, "%s conn %ld, trx %llu, keylen %d, table %s ", + (shared) ? "Shared" : "Exclusive", + wsrep_thd_thread_id(thd), (long long)trx->id, key_len, + table_share->table_name.str); + for (int i=0; itable_cache_key.str, + table_share->table_cache_key.length, + (const uchar*)key, key_len, + wkey_part, + (size_t*)&wkey.key_parts_num)) { + WSREP_WARN("key prepare failed for: %s", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + } + + int rcode = (int)wsrep->append_key( + wsrep, + wsrep_ws_handle(thd, trx), + &wkey, + 1, + shared ? WSREP_KEY_SHARED : WSREP_KEY_EXCLUSIVE, + copy); + if (rcode) { + DBUG_PRINT("wsrep", ("row key failed: %d", rcode)); + WSREP_WARN("Appending row key failed: %s, %d", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void", rcode); + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + } + DBUG_RETURN(0); +} + +extern void compute_md5_hash(char *digest, const char *buf, int len); +#define MD5_HASH compute_md5_hash + +int +ha_innobase::wsrep_append_keys( +/*==================*/ + THD *thd, + bool shared, + const uchar* record0, /* in: row in MySQL format */ + const uchar* record1) /* in: row in MySQL format */ +{ + int rcode; + DBUG_ENTER("wsrep_append_keys"); + + bool key_appended = false; + trx_t *trx = thd_to_trx(thd); + + if (table_share && table_share->tmp_table != NO_TMP_TABLE) { + WSREP_DEBUG("skipping tmp table DML: THD: %lu tmp: %d SQL: %s", + wsrep_thd_thread_id(thd), + table_share->tmp_table, + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + DBUG_RETURN(0); + } + + if (wsrep_protocol_version == 0) { + uint len; + char keyval[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + char *key = &keyval[0]; + ibool is_null; + + len = wsrep_store_key_val_for_row( + thd, table, 0, key, WSREP_MAX_SUPPORTED_KEY_LENGTH, + record0, &is_null); + + if (!is_null) { + rcode = wsrep_append_key( + thd, trx, table_share, table, keyval, + len, shared); + if (rcode) DBUG_RETURN(rcode); + } + else + { + WSREP_DEBUG("NULL key skipped (proto 0): %s", + wsrep_thd_query(thd)); + } + } else { + ut_a(table->s->keys <= 256); + uint i; + bool hasPK= false; + + for (i=0; is->keys; ++i) { + KEY* key_info = table->key_info + i; + if (key_info->flags & HA_NOSAME) { + hasPK = true; + } + } + + for (i=0; is->keys; ++i) { + uint len; + char keyval0[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + char keyval1[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + char* key0 = &keyval0[1]; + char* key1 = &keyval1[1]; + KEY* key_info = table->key_info + i; + ibool is_null; + + dict_index_t* idx = innobase_get_index(i); + dict_table_t* tab = (idx) ? idx->table : NULL; + + keyval0[0] = (char)i; + keyval1[0] = (char)i; + + if (!tab) { + WSREP_WARN("MySQL-InnoDB key mismatch %s %s", + table->s->table_name.str, + key_info->name); + } + /* !hasPK == table with no PK, must append all non-unique keys */ + if (!hasPK || key_info->flags & HA_NOSAME || + ((tab && + dict_table_get_referenced_constraint(tab, idx)) || + (!tab && referenced_by_foreign_key()))) { + + len = wsrep_store_key_val_for_row( + thd, table, i, key0, + WSREP_MAX_SUPPORTED_KEY_LENGTH, + record0, &is_null); + if (!is_null) { + rcode = wsrep_append_key( + thd, trx, table_share, table, + keyval0, len+1, shared); + if (rcode) DBUG_RETURN(rcode); + + if (key_info->flags & HA_NOSAME || shared) + key_appended = true; + } + else + { + WSREP_DEBUG("NULL key skipped: %s", + wsrep_thd_query(thd)); + } + if (record1) { + len = wsrep_store_key_val_for_row( + thd, table, i, key1, + WSREP_MAX_SUPPORTED_KEY_LENGTH, + record1, &is_null); + if (!is_null && memcmp(key0, key1, len)) { + rcode = wsrep_append_key( + thd, trx, table_share, + table, + keyval1, len+1, shared); + if (rcode) DBUG_RETURN(rcode); + } + } + } + } + } + + /* if no PK, calculate hash of full row, to be the key value */ + if (!key_appended && wsrep_certify_nonPK) { + uchar digest[16]; + int rcode; + + wsrep_calc_row_hash(digest, record0, table, prebuilt, thd); + if ((rcode = wsrep_append_key(thd, trx, table_share, table, + (const char*) digest, 16, + shared))) { + DBUG_RETURN(rcode); + } + + if (record1) { + wsrep_calc_row_hash( + digest, record1, table, prebuilt, thd); + if ((rcode = wsrep_append_key(thd, trx, table_share, + table, + (const char*) digest, + 16, shared))) { + DBUG_RETURN(rcode); + } + } + DBUG_RETURN(0); + } + + DBUG_RETURN(0); +} +#endif /* WITH_WSREP */ /*********************************************************************//** Stores a reference to the current row to 'ref' field of the handle. Note @@ -12699,11 +13807,18 @@ ha_innobase::external_lock( /* used by test case */ DBUG_EXECUTE_IF("no_innodb_binlog_errors", skip = true;); if (!skip) { +#ifdef WITH_WSREP + if (!wsrep_on(thd) || wsrep_thd_exec_mode(thd) == LOCAL_STATE) + { +#endif /* WITH_WSREP */ my_error(ER_BINLOG_STMT_MODE_AND_ROW_ENGINE, MYF(0), " InnoDB is limited to row-logging when " "transaction isolation level is " "READ COMMITTED or READ UNCOMMITTED."); DBUG_RETURN(HA_ERR_LOGGING_IMPOSSIBLE); +#ifdef WITH_WSREP + } +#endif /* WITH_WSREP */ } } @@ -14157,6 +15272,9 @@ innobase_xa_prepare( to the session variable take effect only in the next transaction */ if (!trx->support_xa) { +#ifdef WITH_WSREP + thd_get_xid(thd, (MYSQL_XID*) &trx->xid); +#endif // WITH_WSREP return(0); } @@ -16225,6 +17343,305 @@ static SHOW_VAR innodb_status_variables_export[]= { static struct st_mysql_storage_engine innobase_storage_engine= { MYSQL_HANDLERTON_INTERFACE_VERSION }; +#ifdef WITH_WSREP +void +wsrep_abort_slave_trx(wsrep_seqno_t bf_seqno, wsrep_seqno_t victim_seqno) +{ + WSREP_ERROR("Trx %lld tries to abort slave trx %lld. This could be " + "caused by:\n\t" + "1) unsupported configuration options combination, please check documentation.\n\t" + "2) a bug in the code.\n\t" + "3) a database corruption.\n Node consistency compromized, " + "need to abort. Restart the node to resync with cluster.", + (long long)bf_seqno, (long long)victim_seqno); + abort(); +} +/*******************************************************************//** +This function is used to kill one transaction in BF. */ + +int +wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, + const trx_t * const bf_trx, + trx_t *victim_trx, ibool signal) +{ + ut_ad(lock_mutex_own()); + ut_ad(trx_mutex_own(victim_trx)); + ut_ad(bf_thd_ptr); + ut_ad(victim_trx); + + DBUG_ENTER("wsrep_innobase_kill_one_trx"); + THD *bf_thd = bf_thd_ptr ? (THD*) bf_thd_ptr : NULL; + THD *thd = (THD *) victim_trx->mysql_thd; + int64_t bf_seqno = (bf_thd) ? wsrep_thd_trx_seqno(bf_thd) : 0; + + if (!thd) { + DBUG_PRINT("wsrep", ("no thd for conflicting lock")); + WSREP_WARN("no THD for trx: %lu", victim_trx->id); + DBUG_RETURN(1); + } + if (!bf_thd) { + DBUG_PRINT("wsrep", ("no BF thd for conflicting lock")); + WSREP_WARN("no BF THD for trx: %lu", (bf_trx) ? bf_trx->id : 0); + DBUG_RETURN(1); + } + + WSREP_LOG_CONFLICT(bf_thd, thd, TRUE); + + WSREP_DEBUG("BF kill (%lu, seqno: %lld), victim: (%lu) trx: %lu", + signal, (long long)bf_seqno, + wsrep_thd_thread_id(thd), + victim_trx->id); + + WSREP_DEBUG("Aborting query: %s", + (thd && wsrep_thd_query(thd)) ? wsrep_thd_query(thd) : "void"); + + wsrep_thd_LOCK(thd); + + if (wsrep_thd_query_state(thd) == QUERY_EXITING) { + WSREP_DEBUG("kill trx EXITING for %lu", victim_trx->id); + wsrep_thd_UNLOCK(thd); + DBUG_RETURN(0); + } + if(wsrep_thd_exec_mode(thd) != LOCAL_STATE) { + WSREP_DEBUG("withdraw for BF trx: %lu, state: %d", + victim_trx->id, + wsrep_thd_conflict_state(thd)); + } + + switch (wsrep_thd_conflict_state(thd)) { + case NO_CONFLICT: + wsrep_thd_set_conflict_state(thd, MUST_ABORT); + break; + case MUST_ABORT: + WSREP_DEBUG("victim %lu in MUST ABORT state", + victim_trx->id); + wsrep_thd_UNLOCK(thd); + wsrep_thd_awake(thd, signal); + DBUG_RETURN(0); + break; + case ABORTED: + case ABORTING: // fall through + default: + WSREP_DEBUG("victim %lu in state %d", + victim_trx->id, wsrep_thd_conflict_state(thd)); + wsrep_thd_UNLOCK(thd); + DBUG_RETURN(0); + break; + } + + switch (wsrep_thd_query_state(thd)) { + case QUERY_COMMITTING: + enum wsrep_status rcode; + + WSREP_DEBUG("kill query for: %ld", + wsrep_thd_thread_id(thd)); + WSREP_DEBUG("kill trx QUERY_COMMITTING for %lu", + victim_trx->id); + + if (wsrep_thd_exec_mode(thd) == REPL_RECV) { + wsrep_abort_slave_trx(bf_seqno, + wsrep_thd_trx_seqno(thd)); + } else { + rcode = wsrep->abort_pre_commit( + wsrep, bf_seqno, + (wsrep_trx_id_t)victim_trx->id + ); + + switch (rcode) { + case WSREP_WARNING: + WSREP_DEBUG("cancel commit warning: %lu", + victim_trx->id); + wsrep_thd_UNLOCK(thd); + wsrep_thd_awake(thd, signal); + DBUG_RETURN(1); + break; + case WSREP_OK: + break; + default: + WSREP_ERROR( + "cancel commit bad exit: %d %lu", + rcode, + victim_trx->id); + /* unable to interrupt, must abort */ + /* note: kill_mysql() will block, if we cannot. + * kill the lock holder first. + */ + abort(); + break; + } + } + wsrep_thd_UNLOCK(thd); + wsrep_thd_awake(thd, signal); + break; + case QUERY_EXEC: + /* it is possible that victim trx is itself waiting for some + * other lock. We need to cancel this waiting + */ + WSREP_DEBUG("kill trx QUERY_EXEC for %lu", victim_trx->id); + + victim_trx->lock.was_chosen_as_deadlock_victim= TRUE; + if (victim_trx->lock.wait_lock) { + WSREP_DEBUG("victim has wait flag: %ld", + wsrep_thd_thread_id(thd)); + lock_t* wait_lock = victim_trx->lock.wait_lock; + if (wait_lock) { + WSREP_DEBUG("canceling wait lock"); + victim_trx->lock.was_chosen_as_deadlock_victim= TRUE; + lock_cancel_waiting_and_release(wait_lock); + } + + wsrep_thd_UNLOCK(thd); + wsrep_thd_awake(thd, signal); + } else { + /* abort currently executing query */ + DBUG_PRINT("wsrep",("sending KILL_QUERY to: %ld", + wsrep_thd_thread_id(thd))); + WSREP_DEBUG("kill query for: %ld", + wsrep_thd_thread_id(thd)); + /* Note that innobase_kill_connection will take lock_mutex + and trx_mutex */ + wsrep_thd_UNLOCK(thd); + wsrep_thd_awake(thd, signal); + + /* for BF thd, we need to prevent him from committing */ + if (wsrep_thd_exec_mode(thd) == REPL_RECV) { + wsrep_abort_slave_trx(bf_seqno, + wsrep_thd_trx_seqno(thd)); + } + } + break; + case QUERY_IDLE: + { + bool skip_abort= false; + wsrep_aborting_thd_t abortees; + + WSREP_DEBUG("kill IDLE for %lu", victim_trx->id); + + if (wsrep_thd_exec_mode(thd) == REPL_RECV) { + WSREP_DEBUG("kill BF IDLE, seqno: %lld", + (long long)wsrep_thd_trx_seqno(thd)); + wsrep_thd_UNLOCK(thd); + wsrep_abort_slave_trx(bf_seqno, + wsrep_thd_trx_seqno(thd)); + DBUG_RETURN(0); + } + /* This will lock thd from proceeding after net_read() */ + wsrep_thd_set_conflict_state(thd, ABORTING); + + mysql_mutex_lock(&LOCK_wsrep_rollback); + + abortees = wsrep_aborting_thd; + while (abortees && !skip_abort) { + /* check if we have a kill message for this already */ + if (abortees->aborting_thd == thd) { + skip_abort = true; + WSREP_WARN("duplicate thd aborter %lu", + wsrep_thd_thread_id(thd)); + } + abortees = abortees->next; + } + if (!skip_abort) { + wsrep_aborting_thd_t aborting = (wsrep_aborting_thd_t) + my_malloc(sizeof(struct wsrep_aborting_thd), + MYF(0)); + aborting->aborting_thd = thd; + aborting->next = wsrep_aborting_thd; + wsrep_aborting_thd = aborting; + DBUG_PRINT("wsrep",("enqueuing trx abort for %lu", + wsrep_thd_thread_id(thd))); + WSREP_DEBUG("enqueuing trx abort for (%lu)", + wsrep_thd_thread_id(thd)); + } + + DBUG_PRINT("wsrep",("signalling wsrep rollbacker")); + WSREP_DEBUG("signaling aborter"); + mysql_cond_signal(&COND_wsrep_rollback); + mysql_mutex_unlock(&LOCK_wsrep_rollback); + wsrep_thd_UNLOCK(thd); + + break; + } + default: + WSREP_WARN("bad wsrep query state: %d", + wsrep_thd_query_state(thd)); + wsrep_thd_UNLOCK(thd); + break; + } + + DBUG_RETURN(0); +} + +static +int +wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd, + my_bool signal) +{ + DBUG_ENTER("wsrep_innobase_abort_thd"); + trx_t* victim_trx = thd_to_trx(victim_thd); + trx_t* bf_trx = (bf_thd) ? thd_to_trx(bf_thd) : NULL; + WSREP_DEBUG("abort transaction: BF: %s victim: %s", + wsrep_thd_query(bf_thd), + wsrep_thd_query(victim_thd)); + + if (victim_trx) + { + lock_mutex_enter(); + trx_mutex_enter(victim_trx); + int rcode = wsrep_innobase_kill_one_trx(bf_thd, bf_trx, + victim_trx, signal); + trx_mutex_exit(victim_trx); + lock_mutex_exit(); + wsrep_srv_conc_cancel_wait(victim_trx); + + DBUG_RETURN(rcode); + } else { + WSREP_DEBUG("victim does not have transaction"); + wsrep_thd_LOCK(victim_thd); + wsrep_thd_set_conflict_state(victim_thd, MUST_ABORT); + wsrep_thd_UNLOCK(victim_thd); + wsrep_thd_awake(victim_thd, signal); + } + DBUG_RETURN(-1); +} + +static int innobase_wsrep_set_checkpoint(handlerton* hton, const XID* xid) +{ + DBUG_ASSERT(hton == innodb_hton_ptr); + if (wsrep_is_wsrep_xid(xid)) { + mtr_t mtr; + mtr_start(&mtr); + trx_sysf_t* sys_header = trx_sysf_get(&mtr); + trx_sys_update_wsrep_checkpoint(xid, sys_header, &mtr); + mtr_commit(&mtr); + innobase_flush_logs(hton); + return 0; + } else { + return 1; + } +} + +static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid) +{ + DBUG_ASSERT(hton == innodb_hton_ptr); + trx_sys_read_wsrep_checkpoint(xid); + return 0; +} + +static void +wsrep_fake_trx_id( +/*==================*/ + handlerton *hton, + THD *thd) /*!< in: user thread handle */ +{ + mutex_enter(&trx_sys->mutex); + trx_id_t trx_id = trx_sys_get_new_trx_id(); + mutex_exit(&trx_sys->mutex); + + (void *)wsrep_ws_handle_for_trx(wsrep_thd_ws_handle(thd), trx_id); +} + +#endif /* WITH_WSREP */ + /* plugin options */ static MYSQL_SYSVAR_ENUM(checksum_algorithm, srv_checksum_algorithm, @@ -16957,6 +18374,40 @@ static MYSQL_SYSVAR_BOOL(disable_background_merge, NULL, NULL, FALSE); #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ +#ifdef WITH_INNODB_DISALLOW_WRITES +/******************************************************* + * innobase_disallow_writes variable definition * + *******************************************************/ + +/* Must always init to FALSE. */ +static my_bool innobase_disallow_writes = FALSE; + +/************************************************************************** +An "update" method for innobase_disallow_writes variable. */ +static +void +innobase_disallow_writes_update( +/*============================*/ + THD* thd, /* in: thread handle */ + st_mysql_sys_var* var, /* in: pointer to system + variable */ + void* var_ptr, /* out: pointer to dynamic + variable */ + const void* save) /* in: temporary storage */ +{ + *(my_bool*)var_ptr = *(my_bool*)save; + ut_a(srv_allow_writes_event); + if (*(my_bool*)var_ptr) + os_event_reset(srv_allow_writes_event); + else + os_event_set(srv_allow_writes_event); +} + +static MYSQL_SYSVAR_BOOL(disallow_writes, innobase_disallow_writes, + PLUGIN_VAR_NOCMDOPT, + "Tell InnoDB to stop any writes to disk", + NULL, innobase_disallow_writes_update, FALSE); +#endif /* WITH_INNODB_DISALLOW_WRITES */ static MYSQL_SYSVAR_BOOL(random_read_ahead, srv_random_read_ahead, PLUGIN_VAR_NOCMDARG, "Whether to use read ahead for random access within an extent.", @@ -17218,6 +18669,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(change_buffering_debug), MYSQL_SYSVAR(disable_background_merge), #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ +#ifdef WITH_INNODB_DISALLOW_WRITES + MYSQL_SYSVAR(disallow_writes), +#endif /* WITH_INNODB_DISALLOW_WRITES */ MYSQL_SYSVAR(random_read_ahead), MYSQL_SYSVAR(read_ahead_threshold), MYSQL_SYSVAR(read_only), diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 912be30c0ec..1fa9fe139fb 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -119,6 +119,10 @@ class ha_innobase: public handler void innobase_initialize_autoinc(); dict_index_t* innobase_get_index(uint keynr); +#ifdef WITH_WSREP + int wsrep_append_keys(THD *thd, bool shared, + const uchar* record0, const uchar* record1); +#endif /* Init values for the class: */ public: ha_innobase(handlerton *hton, TABLE_SHARE *table_arg); @@ -466,7 +470,40 @@ __attribute__((nonnull)); */ extern void mysql_bin_log_commit_pos(THD *thd, ulonglong *out_pos, const char **out_file); -struct trx_t; +#ifdef WITH_WSREP +#include +//extern "C" int wsrep_trx_order_before(void *thd1, void *thd2); + +extern "C" bool wsrep_thd_is_wsrep_on(THD *thd); + +extern "C" enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd); +extern "C" enum wsrep_conflict_state wsrep_thd_conflict_state(THD *thd); +extern "C" enum wsrep_query_state wsrep_thd_query_state(THD *thd); +extern "C" const char * wsrep_thd_exec_mode_str(THD *thd); +extern "C" const char * wsrep_thd_conflict_state_str(THD *thd); +extern "C" const char * wsrep_thd_query_state_str(THD *thd); +extern "C" wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd); + +extern "C" void wsrep_thd_set_exec_mode(THD *thd, enum wsrep_exec_mode mode); +extern "C" void wsrep_thd_set_query_state( + THD *thd, enum wsrep_query_state state); +extern "C" void wsrep_thd_set_conflict_state( + THD *thd, enum wsrep_conflict_state state); + +extern "C" void wsrep_thd_set_trx_to_replay(THD *thd, uint64 trx_id); + +extern "C"void wsrep_thd_LOCK(THD *thd); +extern "C"void wsrep_thd_UNLOCK(THD *thd); +extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd); +extern "C" time_t wsrep_thd_query_start(THD *thd); +extern "C" my_thread_id wsrep_thd_thread_id(THD *thd); +extern "C" int64_t wsrep_thd_trx_seqno(THD *thd); +extern "C" query_id_t wsrep_thd_query_id(THD *thd); +extern "C" char * wsrep_thd_query(THD *thd); +extern "C" query_id_t wsrep_thd_wsrep_last_query_id(THD *thd); +extern "C" void wsrep_thd_set_wsrep_last_query_id(THD *thd, query_id_t id); +extern "C" void wsrep_thd_awake(THD* thd, my_bool signal); +#endif extern const struct _ft_vft ft_vft_result; @@ -504,6 +541,9 @@ innobase_index_name_is_reserved( __attribute__((nonnull, warn_unused_result)); /*****************************************************************//** +#ifdef WITH_WSREP +extern "C" int wsrep_trx_is_aborting(void *thd_ptr); +#endif Determines InnoDB table flags. @retval true if successful, false if error */ UNIV_INTERN diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index a621a59042e..0b13573abc6 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -49,6 +49,10 @@ Smart ALTER TABLE #include "pars0pars.h" #include "row0sel.h" #include "ha_innodb.h" +#ifdef WITH_WSREP +//#include "wsrep_api.h" +#include // PROCESS_ACL +#endif /** Operations for creating secondary indexes (no rebuild needed) */ static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_ONLINE_CREATE diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index b026210b214..b5e62e53a72 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -518,6 +518,9 @@ be REC_VERSION_56_MAX_INDEX_COL_LEN (3072) bytes */ /** Defines the maximum fixed length column size */ #define DICT_MAX_FIXED_COL_LEN DICT_ANTELOPE_MAX_INDEX_COL_LEN +#ifdef WITH_WSREP +#define WSREP_MAX_SUPPORTED_KEY_LENGTH 3500 +#endif /* WITH_WSREP */ /** Data structure for a field in an index */ struct dict_field_t{ diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h index a02b8f1893a..563a01f747d 100644 --- a/storage/innobase/include/ha_prototypes.h +++ b/storage/innobase/include/ha_prototypes.h @@ -286,6 +286,23 @@ innobase_casedn_str( /*================*/ char* a); /*!< in/out: string to put in lower case */ +#ifdef WITH_WSREP +UNIV_INTERN +int +wsrep_innobase_kill_one_trx(void *thd_ptr, + const trx_t *bf_trx, trx_t *victim_trx, ibool signal); +my_bool wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe); +int wsrep_thd_conflict_state(void *thd_ptr, my_bool sync); +my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync); +my_bool wsrep_thd_is_wsrep(void *thd_ptr); +int wsrep_trx_order_before(void *thd1, void *thd2); +int wsrep_innobase_mysql_sort(int mysql_type, uint charset_number, + unsigned char* str, unsigned int str_length, + unsigned int buf_length); +int +wsrep_on(void *thd_ptr); +extern "C" int wsrep_is_wsrep_xid(const void*); +#endif /* WITH_WSREP */ /**********************************************************************//** Determines the connection character set. @return connection character set */ diff --git a/storage/innobase/include/hash0hash.h b/storage/innobase/include/hash0hash.h index 6f9a628df5d..9a4077befb1 100644 --- a/storage/innobase/include/hash0hash.h +++ b/storage/innobase/include/hash0hash.h @@ -144,6 +144,33 @@ do {\ }\ } while (0) +#ifdef WITH_WSREP +/*******************************************************************//** +Inserts a struct to the head of hash table. */ + +#define HASH_PREPEND(TYPE, NAME, TABLE, FOLD, DATA) \ +do { \ + hash_cell_t* cell3333; \ + TYPE* struct3333; \ + \ + HASH_ASSERT_OWN(TABLE, FOLD) \ + \ + (DATA)->NAME = NULL; \ + \ + cell3333 = hash_get_nth_cell(TABLE, hash_calc_hash(FOLD, TABLE));\ + \ + if (cell3333->node == NULL) { \ + cell3333->node = DATA; \ + DATA->NAME = NULL; \ + } else { \ + struct3333 = (TYPE*) cell3333->node; \ + \ + DATA->NAME = struct3333; \ + \ + cell3333->node = DATA; \ + } \ +} while (0) +#endif /*WITH_WSREP */ #ifdef UNIV_HASH_DEBUG # define HASH_ASSERT_VALID(DATA) ut_a((void*) (DATA) != (void*) -1) # define HASH_INVALIDATE(DATA, NAME) *(void**) (&DATA->NAME) = (void*) -1 diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h index 6d5ed35d5d8..385853bdb68 100644 --- a/storage/innobase/include/lock0lock.h +++ b/storage/innobase/include/lock0lock.h @@ -972,6 +972,16 @@ extern lock_sys_t* lock_sys; mutex_exit(&lock_sys->wait_mutex); \ } while (0) +#ifdef WITH_WSREP +/*********************************************************************//** +Cancels a waiting lock request and releases possible other transactions +waiting behind it. */ +UNIV_INTERN +void +lock_cancel_waiting_and_release( +/*============================*/ + lock_t* lock); /*!< in/out: waiting lock request */ +#endif /* WITH_WSREP */ #ifndef UNIV_NONINL #include "lock0lock.ic" #endif diff --git a/storage/innobase/include/rem0rec.h b/storage/innobase/include/rem0rec.h index 8e7d5ff2d48..238cb04e1f8 100644 --- a/storage/innobase/include/rem0rec.h +++ b/storage/innobase/include/rem0rec.h @@ -981,6 +981,15 @@ are given in one byte (resp. two byte) format. */ two upmost bits in a two byte offset for special purposes */ #define REC_MAX_DATA_SIZE (16 * 1024) +#ifdef WITH_WSREP +int wsrep_rec_get_foreign_key( + byte *buf, /* out: extracted key */ + ulint *buf_len, /* in/out: length of buf */ + const rec_t* rec, /* in: physical record */ + dict_index_t* index_for, /* in: index for foreign table */ + dict_index_t* index_ref, /* in: index for referenced table */ + ibool new_protocol); /* in: protocol > 1 */ +#endif /* WITH_WSREP */ #ifndef UNIV_NONINL #include "rem0rec.ic" #endif diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 905d4a0afa7..a1da2ee03b1 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -304,6 +304,10 @@ extern ulong srv_flush_log_at_trx_commit; extern uint srv_flush_log_at_timeout; extern char srv_adaptive_flushing; +#ifdef WITH_INNODB_DISALLOW_WRITES +/* When this event is reset we do not allow any file writes to take place. */ +extern os_event_t srv_allow_writes_event; +#endif /* WITH_INNODB_DISALLOW_WRITES */ /* If this flag is TRUE, then we will load the indexes' (and tables') metadata even if they are marked as "corrupted". Mostly it is for DBA to process corrupted index and table */ @@ -955,5 +959,13 @@ struct srv_slot_t{ # define srv_start_raw_disk_in_use 0 # define srv_file_per_table 1 #endif /* !UNIV_HOTBACKUP */ +#ifdef WITH_WSREP +UNIV_INTERN +void +wsrep_srv_conc_cancel_wait( +/*==================*/ + trx_t* trx); /*!< in: transaction object associated with the + thread */ +#endif /* WITH_WSREP */ #endif diff --git a/storage/innobase/include/sync0sync.ic b/storage/innobase/include/sync0sync.ic index cb375cb4a4f..f34f3f90b63 100644 --- a/storage/innobase/include/sync0sync.ic +++ b/storage/innobase/include/sync0sync.ic @@ -204,7 +204,10 @@ mutex_enter_func( ulint line) /*!< in: line where locked */ { ut_ad(mutex_validate(mutex)); +#ifndef WITH_WSREP + /* this cannot be be granted when BF trx kills a trx in lock wait state */ ut_ad(!mutex_own(mutex)); +#endif /* WITH_WSREP */ /* Note that we do not peek at the value of lock_word before trying the atomic test_and_set; we could peek, and possibly save time. */ diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h index 70f214d1ac7..9ffc8d99a7f 100644 --- a/storage/innobase/include/trx0sys.h +++ b/storage/innobase/include/trx0sys.h @@ -42,6 +42,9 @@ Created 3/26/1996 Heikki Tuuri #include "read0types.h" #include "page0types.h" #include "ut0bh.h" +#ifdef WITH_WSREP +#include "trx0xa.h" +#endif /* WITH_WSREP */ typedef UT_LIST_BASE_NODE_T(trx_t) trx_list_t; @@ -293,6 +296,9 @@ trx_sys_update_mysql_binlog_offset( ib_int64_t offset, /*!< in: position in that log file */ ulint field, /*!< in: offset of the MySQL log info field in the trx sys header */ +#ifdef WITH_WSREP + trx_sysf_t* sys_header, /*!< in: trx sys header */ +#endif /* WITH_WSREP */ mtr_t* mtr); /*!< in: mtr */ /*****************************************************************//** Prints to stderr the MySQL binlog offset info in the trx system header if @@ -301,6 +307,19 @@ UNIV_INTERN void trx_sys_print_mysql_binlog_offset(void); /*===================================*/ +#ifdef WITH_WSREP +/** Update WSREP checkpoint XID in sys header. */ +void +trx_sys_update_wsrep_checkpoint( + const XID* xid, /*!< in: WSREP XID */ + trx_sysf_t* sys_header, /*!< in: sys_header */ + mtr_t* mtr); /*!< in: mtr */ + +void +/** Read WSREP checkpoint XID from sys header. */ +trx_sys_read_wsrep_checkpoint( + XID* xid); /*!< out: WSREP XID */ +#endif /* WITH_WSREP */ /*****************************************************************//** Prints to stderr the MySQL master log offset info in the trx system header if the magic number shows it valid. */ @@ -529,6 +548,20 @@ this contains the same fields as TRX_SYS_MYSQL_LOG_INFO below */ within that file */ #define TRX_SYS_MYSQL_LOG_NAME 12 /*!< MySQL log file name */ +#ifdef WITH_WSREP +/* The offset to WSREP XID headers */ +#define TRX_SYS_WSREP_XID_INFO (UNIV_PAGE_SIZE - 3500) +#define TRX_SYS_WSREP_XID_MAGIC_N_FLD 0 +#define TRX_SYS_WSREP_XID_MAGIC_N 0x77737265 + +/* XID field: formatID, gtrid_len, bqual_len, xid_data */ +#define TRX_SYS_WSREP_XID_LEN (4 + 4 + 4 + XIDDATASIZE) +#define TRX_SYS_WSREP_XID_FORMAT 4 +#define TRX_SYS_WSREP_XID_GTRID_LEN 8 +#define TRX_SYS_WSREP_XID_BQUAL_LEN 12 +#define TRX_SYS_WSREP_XID_DATA 16 +#endif /* WITH_WSREP*/ + /** Doublewrite buffer */ /* @{ */ /** The offset of the doublewrite buffer header on the trx system header page */ diff --git a/storage/innobase/include/trx0sys.ic b/storage/innobase/include/trx0sys.ic index e097e29b551..7265a97ae25 100644 --- a/storage/innobase/include/trx0sys.ic +++ b/storage/innobase/include/trx0sys.ic @@ -445,7 +445,10 @@ trx_id_t trx_sys_get_new_trx_id(void) /*========================*/ { +#ifndef WITH_WSREP + /* wsrep_fake_trx_id violates this assert */ ut_ad(mutex_own(&trx_sys->mutex)); +#endif /* WITH_WSREP */ /* VERY important: after the database is started, max_trx_id value is divisible by TRX_SYS_TRX_ID_WRITE_MARGIN, and the following if diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 34e4c0067e2..a30bbdbebb2 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -1004,6 +1004,9 @@ struct trx_t{ /*------------------------------*/ char detailed_error[256]; /*!< detailed error message for last error, or empty. */ +#ifdef WITH_WSREP + os_event_t wsrep_event; /* event waited for in srv_conc_slot */ +#endif /* WITH_WSREP */ }; /* Transaction isolation levels (trx->isolation_level) */ diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index e4db2c30751..ce107dda077 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -50,6 +50,11 @@ Created 5/7/1996 Heikki Tuuri #include "dict0boot.h" #include +#ifdef WITH_WSREP +extern my_bool wsrep_debug; +extern my_bool wsrep_log_conflicts; +#include "ha_prototypes.h" +#endif /* Restricts the length of search we will do in the waits-for graph of transactions */ #define LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK 1000000 @@ -945,6 +950,9 @@ UNIV_INLINE ibool lock_rec_has_to_wait( /*=================*/ +#ifdef WITH_WSREP + ibool for_locking, /*!< is caller locking or releasing */ +#endif /* WITH_WSREP */ const trx_t* trx, /*!< in: trx of new lock */ ulint type_mode,/*!< in: precise mode of the new lock to set: LOCK_S or LOCK_X, possibly @@ -1015,6 +1023,50 @@ lock_rec_has_to_wait( return(FALSE); } +#ifdef WITH_WSREP + /* if BF thread is locking and has conflict with another BF + thread, we need to look at trx ordering and lock types */ + if (for_locking && + wsrep_thd_is_BF(trx->mysql_thd, FALSE) && + wsrep_thd_is_BF(lock2->trx->mysql_thd, TRUE)) { + + if (wsrep_debug) { + fprintf(stderr, "\n BF-BF lock conflict \n"); + lock_rec_print(stderr, lock2); + } + + if (wsrep_trx_order_before(trx->mysql_thd, + lock2->trx->mysql_thd) && + (type_mode & LOCK_MODE_MASK) == LOCK_X && + (lock2->type_mode & LOCK_MODE_MASK) == LOCK_X) + { + /* exclusive lock conflicts are not accepted */ + fprintf(stderr, "BF-BF X lock conflict," + "type_mode: %lu supremum: %lu\n", + type_mode, lock_is_on_supremum); + fprintf(stderr, "conflicts states: my %d locked %d\n", + wsrep_thd_conflict_state(trx->mysql_thd, FALSE), + wsrep_thd_conflict_state(lock2->trx->mysql_thd, FALSE) ); + lock_rec_print(stderr, lock2); + return FALSE; + //abort(); + } else { + /* if lock2->index->n_uniq <= + lock2->index->n_user_defined_cols + operation is on uniq index + */ + if (wsrep_debug) fprintf(stderr, + "BF conflict, modes: %lu %lu, " + "idx: %s-%s n_uniq %u n_user %u\n", + type_mode, lock2->type_mode, + lock2->index->name, + lock2->index->table_name, + lock2->index->n_uniq, + lock2->index->n_user_defined_cols); + return FALSE; + } + } +#endif /* WITH_WSREP */ return(TRUE); } @@ -1045,7 +1097,11 @@ lock_has_to_wait( /* If this lock request is for a supremum record then the second bit on the lock bitmap is set */ +#ifdef WITH_WSREP + return(lock_rec_has_to_wait(FALSE, lock1->trx, +#else return(lock_rec_has_to_wait(lock1->trx, +#endif /* WITH_WSREP */ lock1->type_mode, lock2, lock_rec_get_nth_bit( lock1, 1))); @@ -1514,6 +1570,11 @@ lock_rec_has_expl( return(NULL); } +#ifdef WITH_WSREP +static +void +lock_rec_discard(lock_t* in_lock); +#endif #ifdef UNIV_DEBUG /*********************************************************************//** Checks if some other transaction has a lock request in the queue. @@ -1562,6 +1623,69 @@ lock_rec_other_has_expl_req( } #endif /* UNIV_DEBUG */ +#ifdef WITH_WSREP +static +void +wsrep_kill_victim( + const trx_t * const trx, + const lock_t *lock) +{ + ut_ad(lock_mutex_own()); + ut_ad(trx_mutex_own(lock->trx)); + my_bool bf_this = wsrep_thd_is_BF(trx->mysql_thd, FALSE); + my_bool bf_other = wsrep_thd_is_BF(lock->trx->mysql_thd, TRUE); + + if ((bf_this && !bf_other) || + (bf_this && bf_other && wsrep_trx_order_before( + trx->mysql_thd, lock->trx->mysql_thd))) { + + if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { + if (wsrep_debug) { + fprintf(stderr, "WSREP: BF victim waiting\n"); + } + /* cannot release lock, until our lock + is in the queue*/ + } else if (lock->trx != trx) { + if (wsrep_log_conflicts) { + mutex_enter(&trx_sys->mutex); + if (bf_this) { + fputs("\n*** Priority TRANSACTION:\n", + stderr); + } else { + fputs("\n*** Victim TRANSACTION:\n", + stderr); + } + + trx_print_latched(stderr, trx, 3000); + + if (bf_other) { + fputs("\n*** Priority TRANSACTION:\n", + stderr); + } else { + fputs("\n*** Victim TRANSACTION:\n", + stderr); + } + + trx_print_latched(stderr, lock->trx, 3000); + + mutex_exit(&trx_sys->mutex); + + fputs("*** WAITING FOR THIS LOCK TO BE GRANTED:\n", + stderr); + + if (lock_get_type(lock) == LOCK_REC) { + lock_rec_print(stderr, lock); + } else { + lock_table_print(stderr, lock); + } + } + + wsrep_innobase_kill_one_trx(trx->mysql_thd, + (const trx_t*) trx, lock->trx, TRUE); + } + } +} +#endif /*********************************************************************//** Checks if some other transaction has a conflicting explicit lock request in the queue, so that we have to wait. @@ -1590,7 +1714,15 @@ lock_rec_other_has_conflicting( lock != NULL; lock = lock_rec_get_next_const(heap_no, lock)) { - if (lock_rec_has_to_wait(trx, mode, lock, is_supremum)) { +#ifdef WITH_WSREP + if (lock_rec_has_to_wait(TRUE, trx, mode, lock, is_supremum)) { + trx_mutex_enter(lock->trx); + wsrep_kill_victim(trx, lock); + trx_mutex_exit(lock->trx); +#else + if (lock_rec_has_to_wait(trx, mode, lock, is_supremum)) { +#endif /* WITH_WSREP */ + return(lock); } } @@ -1771,6 +1903,28 @@ lock_number_of_rows_locked( /*============== RECORD LOCK CREATION AND QUEUE MANAGEMENT =============*/ +#ifdef WITH_WSREP +static +void +wsrep_print_wait_locks( +/*============*/ + lock_t* c_lock) /* conflicting lock to print */ +{ + if (wsrep_debug && c_lock->trx->lock.wait_lock != c_lock) { + fprintf(stderr, "WSREP: c_lock != wait lock\n"); + if (lock_get_type_low(c_lock) & LOCK_TABLE) + lock_table_print(stderr, c_lock); + else + lock_rec_print(stderr, c_lock); + + if (lock_get_type_low(c_lock->trx->lock.wait_lock) & LOCK_TABLE) + lock_table_print(stderr, c_lock->trx->lock.wait_lock); + else + lock_rec_print(stderr, c_lock->trx->lock.wait_lock); + } +} +#endif /* WITH_WSREP */ + /*********************************************************************//** Creates a new record lock and inserts it to the lock queue. Does NOT check for deadlocks or lock compatibility! @@ -1779,6 +1933,10 @@ static lock_t* lock_rec_create( /*============*/ +#ifdef WITH_WSREP + lock_t* const c_lock, /* conflicting lock */ + que_thr_t* thr, +#endif ulint type_mode,/*!< in: lock mode and wait flag, type is ignored and replaced by LOCK_REC */ @@ -1850,8 +2008,91 @@ lock_rec_create( ut_ad(index->table->n_ref_count > 0 || !index->table->can_be_evicted); +#ifdef WITH_WSREP + if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + lock_t *hash = (lock_t *)c_lock->hash; + lock_t *prev = NULL; + + while (hash && + wsrep_thd_is_BF(((lock_t *)hash)->trx->mysql_thd, TRUE) && + wsrep_trx_order_before( + ((lock_t *)hash)->trx->mysql_thd, + trx->mysql_thd)) { + prev = hash; + hash = (lock_t *)hash->hash; + } + lock->hash = hash; + if (prev) { + prev->hash = lock; + } else { + c_lock->hash = lock; + } + /* + * delayed conflict resolution '...kill_one_trx' was not called, + * if victim was waiting for some other lock + */ + trx_mutex_enter(c_lock->trx); + if (c_lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { + + c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE; + + if (wsrep_debug) { + wsrep_print_wait_locks(c_lock); + } + + trx->lock.que_state = TRX_QUE_LOCK_WAIT; + lock_set_lock_and_trx_wait(lock, trx); + UT_LIST_ADD_LAST(trx_locks, trx->lock.trx_locks, lock); + + ut_ad(thr != NULL); + trx->lock.wait_thr = thr; + thr->state = QUE_THR_LOCK_WAIT; + + /* have to release trx mutex for the duration of + victim lock release. This will eventually call + lock_grant, which wants to grant trx mutex again + */ + if (caller_owns_trx_mutex) { + trx_mutex_exit(trx); + } + lock_cancel_waiting_and_release( + c_lock->trx->lock.wait_lock); + + if (caller_owns_trx_mutex) { + trx_mutex_enter(trx); + } + + /* trx might not wait for c_lock, but some other lock + does not matter if wait_lock was released above + */ + if (c_lock->trx->lock.wait_lock == c_lock) { + lock_reset_lock_and_trx_wait(lock); + } + + trx_mutex_exit(c_lock->trx); + + if (wsrep_debug) { + fprintf( + stderr, + "WSREP: c_lock canceled %llu\n", + (ulonglong) c_lock->trx->id); + } + + /* have to bail out here to avoid lock_set_lock... */ + return(lock); + } + trx_mutex_exit(c_lock->trx); + } else if (wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + HASH_PREPEND(lock_t, hash, lock_sys->rec_hash, + lock_rec_fold(space, page_no), lock); + } else { + HASH_INSERT(lock_t, hash, lock_sys->rec_hash, + lock_rec_fold(space, page_no), lock); + } +#else HASH_INSERT(lock_t, hash, lock_sys->rec_hash, lock_rec_fold(space, page_no), lock); +#endif /* WITH_WSREP */ if (!caller_owns_trx_mutex) { trx_mutex_enter(trx); @@ -1859,7 +2100,6 @@ lock_rec_create( ut_ad(trx_mutex_own(trx)); if (type_mode & LOCK_WAIT) { - lock_set_lock_and_trx_wait(lock, trx); } @@ -1871,7 +2111,6 @@ lock_rec_create( MONITOR_INC(MONITOR_RECLOCK_CREATED); MONITOR_INC(MONITOR_NUM_RECLOCK); - return(lock); } @@ -1886,6 +2125,9 @@ static dberr_t lock_rec_enqueue_waiting( /*=====================*/ +#ifdef WITH_WSREP + lock_t* c_lock, /* conflicting lock */ +#endif ulint type_mode,/*!< in: lock mode this transaction is requesting: LOCK_S or LOCK_X, possibly @@ -1943,6 +2185,9 @@ lock_rec_enqueue_waiting( /* Enqueue the lock request that will wait to be granted, note that we already own the trx mutex. */ lock = lock_rec_create( +#ifdef WITH_WSREP + c_lock, thr, +#endif /* WITH_WSREP */ type_mode | LOCK_WAIT, block, heap_no, index, trx, TRUE); /* Release the mutex to obey the latching order. @@ -2043,7 +2288,19 @@ lock_rec_add_to_queue( const lock_t* other_lock = lock_rec_other_has_expl_req(mode, 0, LOCK_WAIT, block, heap_no, trx); +#ifdef WITH_WSREP + /* this can potentionally assert with wsrep */ + if (wsrep_thd_is_wsrep(trx->mysql_thd)) { + if (wsrep_debug && other_lock) { + fprintf(stderr, + "WSREP: InnoDB assert ignored\n"); + } + } else { + ut_a(!other_lock); + } +#else ut_a(!other_lock); +#endif /* WITH_WSREP */ } #endif /* UNIV_DEBUG */ @@ -2071,7 +2328,16 @@ lock_rec_add_to_queue( if (lock_get_wait(lock) && lock_rec_get_nth_bit(lock, heap_no)) { - +#ifdef WITH_WSREP + if (wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + if (wsrep_debug) { + fprintf(stderr, + "BF skipping wait: %lu\n", + trx->id); + lock_rec_print(stderr, lock); + } + } else +#endif goto somebody_waits; } } @@ -2094,9 +2360,15 @@ lock_rec_add_to_queue( } somebody_waits: - return(lock_rec_create( +#ifdef WITH_WSREP + return(lock_rec_create(NULL, NULL, type_mode, block, heap_no, index, trx, caller_owns_trx_mutex)); +#else + return(lock_rec_create( + type_mode, block, heap_no, index, trx, + caller_owns_trx_mutex)); +#endif /* WITH_WSREP */ } /** Record locking request status */ @@ -2159,9 +2431,13 @@ lock_rec_lock_fast( if (lock == NULL) { if (!impl) { /* Note that we don't own the trx mutex. */ +#ifdef WITH_WSREP + lock = lock_rec_create(NULL, thr, + mode, block, heap_no, index, trx, FALSE); +#else lock = lock_rec_create( mode, block, heap_no, index, trx, FALSE); - +#endif /* WITH_WSREP */ } status = LOCK_REC_SUCCESS_CREATED; } else { @@ -2214,6 +2490,9 @@ lock_rec_lock_slow( que_thr_t* thr) /*!< in: query thread */ { trx_t* trx; +#ifdef WITH_WSREP + lock_t* c_lock(NULL); +#endif dberr_t err = DB_SUCCESS; ut_ad(lock_mutex_own()); @@ -2237,18 +2516,31 @@ lock_rec_lock_slow( /* The trx already has a strong enough lock on rec: do nothing */ - +#ifdef WITH_WSREP + } else if ((c_lock = (ib_lock_t*)lock_rec_other_has_conflicting( + static_cast(mode), + block, heap_no, trx))) { +#else } else if (lock_rec_other_has_conflicting( static_cast(mode), block, heap_no, trx)) { +#endif /* WITH_WSREP */ /* If another transaction has a non-gap conflicting request in the queue, as this transaction does not have a lock strong enough already granted on the record, we have to wait. */ +#ifdef WITH_WSREP + /* c_lock is NULL here if jump to enqueue_waiting happened + but it's ok because lock is not NULL in that case and c_lock + is not used. */ + err = lock_rec_enqueue_waiting(c_lock, + mode, block, heap_no, index, thr); +#else err = lock_rec_enqueue_waiting( mode, block, heap_no, index, thr); +#endif /* WITH_WSREP */ } else if (!impl) { /* Set the requested lock on the record, note that @@ -2354,7 +2646,13 @@ lock_rec_has_to_wait_in_queue( if (heap_no < lock_rec_get_n_bits(lock) && (p[bit_offset] & bit_mask) && lock_has_to_wait(wait_lock, lock)) { - +#ifdef WITH_WSREP + if (wsrep_thd_is_BF(wait_lock->trx->mysql_thd, FALSE) && + wsrep_thd_is_BF(lock->trx->mysql_thd, TRUE)) { + /* don't wait for another BF lock */ + continue; + } +#endif return(lock); } } @@ -3738,10 +4036,22 @@ lock_deadlock_select_victim( /* The joining transaction is 'smaller', choose it as the victim and roll it back. */ - return(ctx->start); +#ifdef WITH_WSREP + if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) { + return(ctx->wait_lock->trx); + } + else +#endif /* WITH_WSREP */ + return(ctx->start); } - return(ctx->wait_lock->trx); +#ifdef WITH_WSREP + if (wsrep_thd_is_BF(ctx->wait_lock->trx->mysql_thd, TRUE)) { + return(ctx->start); + } + else +#endif /* WITH_WSREP */ + return(ctx->wait_lock->trx); } /********************************************************************//** @@ -3870,8 +4180,14 @@ lock_deadlock_search( ctx->too_deep = TRUE; +#ifdef WITH_WSREP + if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) { + return(ctx->wait_lock->trx->id); + } + else +#endif /* WITH_WSREP */ /* Select the joining transaction as the victim. */ - return(ctx->start->id); + return(ctx->start->id); } else if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { @@ -3888,7 +4204,12 @@ lock_deadlock_search( ctx->too_deep = TRUE; - return(ctx->start->id); +#ifdef WITH_WSREP + if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) + return(lock->trx->id); + else +#endif /* WITH_WSREP */ + return(ctx->start->id); } ctx->wait_lock = lock->trx->lock.wait_lock; @@ -4006,9 +4327,18 @@ lock_deadlock_check_and_resolve( ut_a(trx == ctx.start); ut_a(victim_trx_id == trx->id); - if (!srv_read_only_mode) { - lock_deadlock_joining_trx_print(trx, lock); +#ifdef WITH_WSREP + if (!wsrep_thd_is_BF(ctx.start->mysql_thd, TRUE)) + { +#endif /* WITH_WSREP */ + if (!srv_read_only_mode) { + lock_deadlock_joining_trx_print(trx, lock); + } +#ifdef WITH_WSREP + } else { + /* BF processor */; } +#endif /* WITH_WSREP */ MONITOR_INC(MONITOR_DEADLOCK); @@ -4046,6 +4376,9 @@ UNIV_INLINE lock_t* lock_table_create( /*==============*/ +#ifdef WITH_WSREP + lock_t* c_lock, /*!< in: conflicting lock */ +#endif dict_table_t* table, /*!< in/out: database table in dictionary cache */ ulint type_mode,/*!< in: lock mode possibly ORed with @@ -4089,7 +4422,59 @@ lock_table_create( ut_ad(table->n_ref_count > 0 || !table->can_be_evicted); UT_LIST_ADD_LAST(trx_locks, trx->lock.trx_locks, lock); + +#ifdef WITH_WSREP + if (wsrep_thd_is_wsrep(trx->mysql_thd)) { + if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + UT_LIST_INSERT_AFTER( + un_member.tab_lock.locks, table->locks, c_lock, lock); + } else { + UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); + } + + if (c_lock) { + trx_mutex_enter(c_lock->trx); + } + + if (c_lock && c_lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { + + c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE; + + if (wsrep_debug) { + wsrep_print_wait_locks(c_lock); + wsrep_print_wait_locks(c_lock->trx->lock.wait_lock); + } + + /* have to release trx mutex for the duration of + victim lock release. This will eventually call + lock_grant, which wants to grant trx mutex again + */ + /* caller has trx_mutex, have to release for lock cancel */ + trx_mutex_exit(trx); + lock_cancel_waiting_and_release(c_lock->trx->lock.wait_lock); + trx_mutex_enter(trx); + + /* trx might not wait for c_lock, but some other lock + does not matter if wait_lock was released above + */ + if (c_lock->trx->lock.wait_lock == c_lock) { + lock_reset_lock_and_trx_wait(lock); + } + + if (wsrep_debug) { + fprintf(stderr, "WSREP: c_lock canceled %llu\n", + (ulonglong) c_lock->trx->id); + } + } + if (c_lock) { + trx_mutex_exit(c_lock->trx); + } + } else { + UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); + } +#else UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); +#endif /* WITH_WSREP */ if (UNIV_UNLIKELY(type_mode & LOCK_WAIT)) { @@ -4246,6 +4631,9 @@ static dberr_t lock_table_enqueue_waiting( /*=======================*/ +#ifdef WITH_WSREP + lock_t* c_lock, /*!< in: conflicting lock */ +#endif ulint mode, /*!< in: lock mode this transaction is requesting */ dict_table_t* table, /*!< in/out: table */ @@ -4290,7 +4678,14 @@ lock_table_enqueue_waiting( /* Enqueue the lock request that will wait to be granted */ - lock = lock_table_create(table, mode | LOCK_WAIT, trx); +#ifdef WITH_WSREP + if (trx->lock.was_chosen_as_deadlock_victim) { + return(DB_DEADLOCK); + } + lock = lock_table_create(c_lock, table, mode | LOCK_WAIT, trx); +#else + lock = lock_table_create(table, mode | LOCK_WAIT, trx); +#endif /* WITH_WSREP */ /* Release the mutex to obey the latching order. This is safe, because lock_deadlock_check_and_resolve() @@ -4362,6 +4757,18 @@ lock_table_other_has_incompatible( && !lock_mode_compatible(lock_get_mode(lock), mode) && (wait || !lock_get_wait(lock))) { +#ifdef WITH_WSREP + if(wsrep_thd_is_wsrep(trx->mysql_thd)) { + if (wsrep_debug) { + fprintf(stderr, "WSREP: trx %ld table lock abort\n", + trx->id); + } + trx_mutex_enter(lock->trx); + wsrep_kill_victim((trx_t *)trx, (lock_t *)lock); + trx_mutex_exit(lock->trx); + } +#endif + return(lock); } } @@ -4384,6 +4791,9 @@ lock_table( enum lock_mode mode, /*!< in: lock mode */ que_thr_t* thr) /*!< in: query thread */ { +#ifdef WITH_WSREP + lock_t *c_lock = NULL; +#endif trx_t* trx; dberr_t err; const lock_t* wait_for; @@ -4414,8 +4824,13 @@ lock_table( /* We have to check if the new lock is compatible with any locks other transactions have in the table lock queue. */ +#ifdef WITH_WSREP + wait_for = lock_table_other_has_incompatible( + trx, LOCK_WAIT, table, mode); +#else wait_for = lock_table_other_has_incompatible( trx, LOCK_WAIT, table, mode); +#endif trx_mutex_enter(trx); @@ -4423,9 +4838,17 @@ lock_table( mode: this trx may have to wait */ if (wait_for != NULL) { +#ifdef WITH_WSREP + err = lock_table_enqueue_waiting((ib_lock_t*)wait_for, mode | flags, table, thr); +#else err = lock_table_enqueue_waiting(mode | flags, table, thr); +#endif } else { +#ifdef WITH_WSREP + lock_table_create(c_lock, table, mode | flags, trx); +#else lock_table_create(table, mode | flags, trx); +#endif ut_a(!flags || mode == LOCK_S || mode == LOCK_X); @@ -4463,7 +4886,11 @@ lock_table_ix_resurrect( trx, LOCK_WAIT, table, LOCK_IX)); trx_mutex_enter(trx); +#ifdef WITH_WSREP + lock_table_create(NULL, table, LOCK_IX, trx); +#else lock_table_create(table, LOCK_IX, trx); +#endif lock_mutex_exit(); trx_mutex_exit(trx); } @@ -5594,15 +6021,19 @@ lock_rec_queue_validate( if (!lock_rec_get_gap(lock) && !lock_get_wait(lock)) { - enum lock_mode mode; +#ifndef WITH_WSREP + if (wsrep_thd_is_wsrep(lock->trx->mysql_thd)) { + enum lock_mode mode; - if (lock_get_mode(lock) == LOCK_S) { - mode = LOCK_X; - } else { - mode = LOCK_S; + if (lock_get_mode(lock) == LOCK_S) { + mode = LOCK_X; + } else { + mode = LOCK_S; + } + ut_a(!lock_rec_other_has_expl_req( + mode, 0, 0, block, heap_no, lock->trx)); } - ut_a(!lock_rec_other_has_expl_req( - mode, 0, 0, block, heap_no, lock->trx)); +#endif /* WITH_WSREP */ } else if (lock_get_wait(lock) && !lock_rec_get_gap(lock)) { @@ -5906,6 +6337,9 @@ lock_rec_insert_check_and_lock( lock_t* lock; dberr_t err; ulint next_rec_heap_no; +#ifdef WITH_WSREP + lock_t* c_lock=NULL; +#endif ut_ad(block->frame == page_align(rec)); ut_ad(!dict_index_is_online_ddl(index) @@ -5962,17 +6396,30 @@ lock_rec_insert_check_and_lock( had to wait for their insert. Both had waiting gap type lock requests on the successor, which produced an unnecessary deadlock. */ +#ifdef WITH_WSREP + if ((c_lock = (ib_lock_t*)lock_rec_other_has_conflicting( + static_cast( + LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION), + block, next_rec_heap_no, trx))) { +#else if (lock_rec_other_has_conflicting( static_cast( LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION), block, next_rec_heap_no, trx)) { +#endif /* WITH_WSREP */ /* Note that we may get DB_SUCCESS also here! */ trx_mutex_enter(trx); +#ifdef WITH_WSREP + err = lock_rec_enqueue_waiting(c_lock, + LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION, + block, next_rec_heap_no, index, thr); +#else err = lock_rec_enqueue_waiting( LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION, block, next_rec_heap_no, index, thr); +#endif /* WITH_WSREP */ trx_mutex_exit(trx); } else { diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index 45ca07bc7c4..fd9e60d123b 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -104,6 +104,12 @@ UNIV_INTERN os_ib_mutex_t os_file_seek_mutexes[OS_FILE_N_SEEK_MUTEXES]; /* In simulated aio, merge at most this many consecutive i/os */ #define OS_AIO_MERGE_N_CONSECUTIVE 64 +#ifdef WITH_INNODB_DISALLOW_WRITES +#define WAIT_ALLOW_WRITES() os_event_wait(srv_allow_writes_event) +#else +#define WAIT_ALLOW_WRITES() do { } while (0) +#endif /* WITH_INNODB_DISALLOW_WRITES */ + /********************************************************************** InnoDB AIO Implementation: @@ -927,7 +933,9 @@ os_file_create_tmpfile(void) /*========================*/ { FILE* file = NULL; - int fd = innobase_mysql_tmpfile(); + int fd; + WAIT_ALLOW_WRITES(); + fd = innobase_mysql_tmpfile(); ut_ad(!srv_read_only_mode); @@ -1253,6 +1261,7 @@ os_file_create_directory( return(TRUE); #else int rcode; + WAIT_ALLOW_WRITES(); rcode = mkdir(pathname, 0770); @@ -1379,6 +1388,8 @@ os_file_create_simple_func( #else /* __WIN__ */ int create_flag; + if (create_mode != OS_FILE_OPEN && create_mode != OS_FILE_OPEN_RAW) + WAIT_ALLOW_WRITES(); ut_a(!(create_mode & OS_FILE_ON_ERROR_SILENT)); ut_a(!(create_mode & OS_FILE_ON_ERROR_NO_EXIT)); @@ -1566,6 +1577,8 @@ os_file_create_simple_no_error_handling_func( int create_flag; ut_a(name); + if (create_mode != OS_FILE_OPEN && create_mode != OS_FILE_OPEN_RAW) + WAIT_ALLOW_WRITES(); ut_a(!(create_mode & OS_FILE_ON_ERROR_SILENT)); ut_a(!(create_mode & OS_FILE_ON_ERROR_NO_EXIT)); @@ -1894,6 +1907,8 @@ os_file_create_func( #else /* __WIN__ */ int create_flag; const char* mode_str = NULL; + if (create_mode != OS_FILE_OPEN && create_mode != OS_FILE_OPEN_RAW) + WAIT_ALLOW_WRITES(); on_error_no_exit = create_mode & OS_FILE_ON_ERROR_NO_EXIT ? TRUE : FALSE; @@ -2089,6 +2104,7 @@ loop: goto loop; #else int ret; + WAIT_ALLOW_WRITES(); ret = unlink(name); @@ -2153,6 +2169,7 @@ loop: goto loop; #else int ret; + WAIT_ALLOW_WRITES(); ret = unlink(name); @@ -2206,6 +2223,7 @@ os_file_rename_func( return(FALSE); #else int ret; + WAIT_ALLOW_WRITES(); ret = rename(oldpath, newpath); @@ -2440,6 +2458,7 @@ os_file_set_eof( HANDLE h = (HANDLE) _get_osfhandle(fileno(file)); return(SetEndOfFile(h)); #else /* __WIN__ */ + WAIT_ALLOW_WRITES(); return(!ftruncate(fileno(file), ftell(file))); #endif /* __WIN__ */ } @@ -2534,6 +2553,7 @@ os_file_flush_func( return(FALSE); #else int ret; + WAIT_ALLOW_WRITES(); #if defined(HAVE_DARWIN_THREADS) # ifndef F_FULLFSYNC @@ -3251,6 +3271,7 @@ retry: return(FALSE); #else ssize_t ret; + WAIT_ALLOW_WRITES(); ret = os_file_pwrite(file, buf, n, offset); diff --git a/storage/innobase/rem/rem0rec.cc b/storage/innobase/rem/rem0rec.cc index 0d7b7c16785..3ff71d5c59e 100644 --- a/storage/innobase/rem/rem0rec.cc +++ b/storage/innobase/rem/rem0rec.cc @@ -33,6 +33,9 @@ Created 5/30/1994 Heikki Tuuri #include "mtr0mtr.h" #include "mtr0log.h" #include "fts0fts.h" +#ifdef WITH_WSREP +#include +#endif /* WITH_WSREP */ /* PHYSICAL RECORD (OLD STYLE) =========================== @@ -1961,3 +1964,134 @@ rec_get_trx_id( } # endif /* UNIV_DEBUG */ #endif /* !UNIV_HOTBACKUP */ + +#ifdef WITH_WSREP +int +wsrep_rec_get_foreign_key( + byte *buf, /* out: extracted key */ + ulint *buf_len, /* in/out: length of buf */ + const rec_t* rec, /* in: physical record */ + dict_index_t* index_for, /* in: index in foreign table */ + dict_index_t* index_ref, /* in: index in referenced table */ + ibool new_protocol) /* in: protocol > 1 */ +{ + const byte* data; + ulint len; + ulint key_len = 0; + ulint i; + uint key_parts; + mem_heap_t* heap = NULL; + ulint offsets_[REC_OFFS_NORMAL_SIZE]; + const ulint* offsets; + + ut_ad(index_for); + ut_ad(index_ref); + + rec_offs_init(offsets_); + offsets = rec_get_offsets(rec, index_for, offsets_, + ULINT_UNDEFINED, &heap); + + ut_ad(rec_offs_validate(rec, NULL, offsets)); + + ut_ad(rec); + + key_parts = dict_index_get_n_unique_in_tree(index_for); + for (i = 0; + i < key_parts && + (index_for->type & DICT_CLUSTERED || i < key_parts - 1); + i++) { + dict_field_t* field_f = + dict_index_get_nth_field(index_for, i); + const dict_col_t* col_f = dict_field_get_col(field_f); + dict_field_t* field_r = + dict_index_get_nth_field(index_ref, i); + const dict_col_t* col_r = dict_field_get_col(field_r); + + data = rec_get_nth_field(rec, offsets, i, &len); + if (key_len + ((len != UNIV_SQL_NULL) ? len + 1 : 1) > + *buf_len) { + fprintf (stderr, + "WSREP: FK key len exceeded %lu %lu %lu\n", + key_len, len, *buf_len); + goto err_out; + } + + if (len == UNIV_SQL_NULL) { + ut_a(!(col_f->prtype & DATA_NOT_NULL)); + *buf++ = 1; + key_len++; + } else if (!new_protocol) { + if (!(col_r->prtype & DATA_NOT_NULL)) { + *buf++ = 0; + key_len++; + } + memcpy(buf, data, len); + *buf_len = wsrep_innobase_mysql_sort( + (int)(col_f->prtype & DATA_MYSQL_TYPE_MASK), + (uint)dtype_get_charset_coll(col_f->prtype), + buf, len, *buf_len); + } else { /* new protocol */ + if (!(col_r->prtype & DATA_NOT_NULL)) { + *buf++ = 0; + key_len++; + } + switch (col_f->mtype) { + case DATA_INT: { + byte* ptr = buf+len; + for (;;) { + ptr--; + *ptr = *data; + if (ptr == buf) { + break; + } + data++; + } + + if (!(col_f->prtype & DATA_UNSIGNED)) { + buf[len-1] = (byte) (buf[len-1] ^ 128); + } + + break; + } + case DATA_VARCHAR: + case DATA_VARMYSQL: + case DATA_CHAR: + case DATA_MYSQL: + /* Copy the actual data */ + ut_memcpy(buf, data, len); + len = wsrep_innobase_mysql_sort( + (int) + (col_f->prtype & DATA_MYSQL_TYPE_MASK), + (uint) + dtype_get_charset_coll(col_f->prtype), + buf, len, *buf_len); + break; + case DATA_BLOB: + case DATA_BINARY: + memcpy(buf, data, len); + break; + default: + break; + } + + key_len += len; + buf += len; + } + } + + rec_validate(rec, offsets); + + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); + } + + *buf_len = key_len; + return DB_SUCCESS; + + err_out: + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); + } + return DB_ERROR; +} +#endif // WITH_WSREP diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 65a6c433f5c..e6487730a77 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -918,6 +918,14 @@ row_ins_invalidate_query_cache( innobase_invalidate_query_cache(thr_get_trx(thr), buf, len); mem_free(buf); } +#ifdef WITH_WSREP +dberr_t wsrep_append_foreign_key(trx_t *trx, + dict_foreign_t* foreign, + const rec_t* clust_rec, + dict_index_t* clust_index, + ibool referenced, + ibool shared); +#endif /* WITH_WSREP */ /*********************************************************************//** Perform referential actions or checks when a parent row is deleted or updated @@ -1269,7 +1277,19 @@ row_ins_foreign_check_on_constraint( cascade->state = UPD_NODE_UPDATE_CLUSTERED; - err = row_update_cascade_for_mysql(thr, cascade, +#ifdef WITH_WSREP + err = wsrep_append_foreign_key( + thr_get_trx(thr), + foreign, + clust_rec, + clust_index, + FALSE, FALSE); + if (err != DB_SUCCESS) { + fprintf(stderr, + "WSREP: foreign key append failed: %d\n", err); + } else +#endif /* WITH_WSREP */ + err = row_update_cascade_for_mysql(thr, cascade, foreign->foreign_table); if (foreign->foreign_table->n_foreign_key_checks_running == 0) { @@ -1601,7 +1621,14 @@ run_again: if (check_ref) { err = DB_SUCCESS; - +#ifdef WITH_WSREP + err = wsrep_append_foreign_key( + thr_get_trx(thr), + foreign, + rec, + check_index, + check_ref, TRUE); +#endif /* WITH_WSREP */ goto end_scan; } else if (foreign->type != 0) { /* There is an ON UPDATE or ON DELETE diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index fb626519132..adced7059e4 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -51,6 +51,9 @@ Created 12/27/1996 Heikki Tuuri #include "pars0sym.h" #include "eval0eval.h" #include "buf0lru.h" +#ifdef WITH_WSREP +extern my_bool wsrep_debug; +#endif /* What kind of latch and lock can we assume when the control comes to @@ -170,6 +173,50 @@ func_exit: return(is_referenced); } +#ifdef WITH_WSREP +static +ibool +wsrep_row_upd_index_is_foreign( +/*========================*/ + dict_index_t* index, /*!< in: index */ + trx_t* trx) /*!< in: transaction */ +{ + dict_table_t* table = index->table; + dict_foreign_t* foreign; + ibool froze_data_dict = FALSE; + ibool is_referenced = FALSE; + + if (!UT_LIST_GET_FIRST(table->foreign_list)) { + + return(FALSE); + } + + if (trx->dict_operation_lock_mode == 0) { + row_mysql_freeze_data_dictionary(trx); + froze_data_dict = TRUE; + } + + foreign = UT_LIST_GET_FIRST(table->foreign_list); + + while (foreign) { + if (foreign->foreign_index == index) { + + is_referenced = TRUE; + goto func_exit; + } + + foreign = UT_LIST_GET_NEXT(foreign_list, foreign); + } + +func_exit: + if (froze_data_dict) { + row_mysql_unfreeze_data_dictionary(trx); + } + + return(is_referenced); +} +#endif /* WITH_WSREP */ + /*********************************************************************//** Checks if possible foreign key constraints hold after a delete of the record under pcur. @@ -287,7 +334,123 @@ run_again: } err = DB_SUCCESS; +func_exit: + if (got_s_lock) { + row_mysql_unfreeze_data_dictionary(trx); + } + mem_heap_free(heap); + + return(err); +} +#ifdef WITH_WSREP +static +dberr_t +wsrep_row_upd_check_foreign_constraints( +/*=================================*/ + upd_node_t* node, /*!< in: row update node */ + btr_pcur_t* pcur, /*!< in: cursor positioned on a record; NOTE: the + cursor position is lost in this function! */ + dict_table_t* table, /*!< in: table in question */ + dict_index_t* index, /*!< in: index of the cursor */ + ulint* offsets,/*!< in/out: rec_get_offsets(pcur.rec, index) */ + que_thr_t* thr, /*!< in: query thread */ + mtr_t* mtr) /*!< in: mtr */ +{ + dict_foreign_t* foreign; + mem_heap_t* heap; + dtuple_t* entry; + trx_t* trx; + const rec_t* rec; + ulint n_ext; + dberr_t err; + ibool got_s_lock = FALSE; + ibool opened = FALSE; + + if (UT_LIST_GET_FIRST(table->foreign_list) == NULL) { + + return(DB_SUCCESS); + } + + trx = thr_get_trx(thr); + + /* TODO: make native slave thread bail out here */ + + rec = btr_pcur_get_rec(pcur); + ut_ad(rec_offs_validate(rec, index, offsets)); + + heap = mem_heap_create(500); + + entry = row_rec_to_index_entry(rec, index, offsets, + &n_ext, heap); + + mtr_commit(mtr); + + mtr_start(mtr); + + if (trx->dict_operation_lock_mode == 0) { + got_s_lock = TRUE; + + row_mysql_freeze_data_dictionary(trx); + } + + foreign = UT_LIST_GET_FIRST(table->foreign_list); + + while (foreign) { + /* Note that we may have an update which updates the index + record, but does NOT update the first fields which are + referenced in a foreign key constraint. Then the update does + NOT break the constraint. */ + + if (foreign->foreign_index == index + && (node->is_delete + || row_upd_changes_first_fields_binary( + entry, index, node->update, + foreign->n_fields))) { + + if (foreign->referenced_table == NULL) { + foreign->referenced_table = + dict_table_open_on_name( + foreign->referenced_table_name_lookup, + FALSE, FALSE, DICT_ERR_IGNORE_NONE); + opened = TRUE; + } + + if (foreign->referenced_table) { + os_inc_counter(dict_sys->mutex, + foreign->referenced_table + ->n_foreign_key_checks_running); + } + + /* NOTE that if the thread ends up waiting for a lock + we will release dict_operation_lock temporarily! + But the counter on the table protects 'foreign' from + being dropped while the check is running. */ + + err = row_ins_check_foreign_constraint( + TRUE, foreign, table, entry, thr); + + if (foreign->referenced_table) { + os_dec_counter(dict_sys->mutex, + foreign->referenced_table + ->n_foreign_key_checks_running); + + if (opened == TRUE) { + dict_table_close(foreign->referenced_table, TRUE, FALSE); + opened = FALSE; + } + } + + if (err != DB_SUCCESS) { + + goto func_exit; + } + } + + foreign = UT_LIST_GET_NEXT(foreign_list, foreign); + } + + err = DB_SUCCESS; func_exit: if (got_s_lock) { row_mysql_unfreeze_data_dictionary(trx); @@ -299,6 +462,7 @@ func_exit: return(err); } +#endif /* WITH_WSREP */ /*********************************************************************//** Creates an update node for a query graph. @@ -1673,6 +1837,9 @@ row_upd_sec_index_entry( index = node->index; referenced = row_upd_index_is_referenced(index, trx); +#ifdef WITH_WSREP + ibool foreign = wsrep_row_upd_index_is_foreign(index, trx); +#endif /* WITH_WSREP */ heap = mem_heap_create(1024); @@ -1800,6 +1967,9 @@ row_upd_sec_index_entry( row_ins_sec_index_entry() below */ if (!rec_get_deleted_flag( rec, dict_table_is_comp(index->table))) { +#ifdef WITH_WSREP + que_node_t *parent = que_node_get_parent(node); +#endif /* WITH_WSREP */ err = btr_cur_del_mark_set_sec_rec( 0, btr_cur, TRUE, thr, &mtr); @@ -1817,6 +1987,37 @@ row_upd_sec_index_entry( node, &pcur, index->table, index, offsets, thr, &mtr); } +#ifdef WITH_WSREP + if (err == DB_SUCCESS && !referenced && + !(parent && que_node_get_type(parent) == + QUE_NODE_UPDATE && + ((upd_node_t*)parent)->cascade_node == node) && + foreign + ) { + ulint* offsets = + rec_get_offsets( + rec, index, NULL, ULINT_UNDEFINED, + &heap); + err = wsrep_row_upd_check_foreign_constraints( + node, &pcur, index->table, + index, offsets, thr, &mtr); + switch (err) { + case DB_SUCCESS: + case DB_NO_REFERENCED_ROW: + err = DB_SUCCESS; + break; + case DB_DEADLOCK: + if (wsrep_debug) fprintf (stderr, + "WSREP: sec index FK check fail for deadlock"); + break; + default: + fprintf (stderr, + "WSREP: referenced FK check fail: %d", + (int)err); + break; + } + } +#endif /* WITH_WSREP */ } break; } @@ -1971,6 +2172,9 @@ row_upd_clust_rec_by_insert( que_thr_t* thr, /*!< in: query thread */ ibool referenced,/*!< in: TRUE if index may be referenced in a foreign key constraint */ +#ifdef WITH_WSREP + ibool foreign, /*!< in: TRUE if index is foreign key index */ +#endif /* WITH_WSREP */ mtr_t* mtr) /*!< in/out: mtr; gets committed here */ { mem_heap_t* heap; @@ -1984,6 +2188,9 @@ row_upd_clust_rec_by_insert( rec_t* rec; ulint* offsets = NULL; +#ifdef WITH_WSREP + que_node_t *parent = que_node_get_parent(node); +#endif /* WITH_WSREP */ ut_ad(node); ut_ad(dict_index_is_clust(index)); @@ -2066,6 +2273,34 @@ err_exit: goto err_exit; } } +#ifdef WITH_WSREP + if (!referenced && + !(parent && que_node_get_type(parent) == QUE_NODE_UPDATE && + ((upd_node_t*)parent)->cascade_node == node) && + foreign + ) { + err = wsrep_row_upd_check_foreign_constraints( + node, pcur, table, index, offsets, thr, mtr); + switch (err) { + case DB_SUCCESS: + case DB_NO_REFERENCED_ROW: + err = DB_SUCCESS; + break; + case DB_DEADLOCK: + if (wsrep_debug) fprintf (stderr, + "WSREP: insert FK check fail for deadlock"); + break; + default: + fprintf (stderr, + "WSREP: referenced FK check fail: %d", + (int)err); + break; + } + if (err != DB_SUCCESS) { + goto err_exit; + } + } +#endif /* WITH_WSREP */ } mtr_commit(mtr); @@ -2258,11 +2493,18 @@ row_upd_del_mark_clust_rec( ibool referenced, /*!< in: TRUE if index may be referenced in a foreign key constraint */ +#ifdef WITH_WSREP + ibool foreign,/*!< in: TRUE if index is foreign key index */ +#endif /* WITH_WSREP */ mtr_t* mtr) /*!< in: mtr; gets committed here */ { btr_pcur_t* pcur; btr_cur_t* btr_cur; dberr_t err; +#ifdef WITH_WSREP + rec_t* rec; + que_node_t *parent = que_node_get_parent(node); +#endif /* WITH_WSREP */ ut_ad(node); ut_ad(dict_index_is_clust(index)); @@ -2279,8 +2521,16 @@ row_upd_del_mark_clust_rec( /* Mark the clustered index record deleted; we do not have to check locks, because we assume that we have an x-lock on the record */ +#ifdef WITH_WSREP + rec = btr_cur_get_rec(btr_cur); +#endif /* WITH_WSREP */ + err = btr_cur_del_mark_set_clust_rec( +#ifdef WITH_WSREP + btr_cur_get_block(btr_cur), rec, +#else btr_cur_get_block(btr_cur), btr_cur_get_rec(btr_cur), +#endif /* WITH_WSREP */ index, offsets, thr, mtr); if (err == DB_SUCCESS && referenced) { /* NOTE that the following call loses the position of pcur ! */ @@ -2288,6 +2538,32 @@ row_upd_del_mark_clust_rec( err = row_upd_check_references_constraints( node, pcur, index->table, index, offsets, thr, mtr); } +#ifdef WITH_WSREP + if (err == DB_SUCCESS && !referenced && + !(parent && que_node_get_type(parent) == QUE_NODE_UPDATE && + ((upd_node_t*)parent)->cascade_node == node) && + thr_get_trx(thr) && + foreign + ) { + err = wsrep_row_upd_check_foreign_constraints( + node, pcur, index->table, index, offsets, thr, mtr); + switch (err) { + case DB_SUCCESS: + case DB_NO_REFERENCED_ROW: + err = DB_SUCCESS; + break; + case DB_DEADLOCK: + if (wsrep_debug) fprintf (stderr, + "WSREP: clust rec FK check fail for deadlock"); + break; + default: + fprintf (stderr, + "WSREP: clust rec referenced FK check fail: %d", + (int)err); + break; + } + } +#endif /* WITH_WSREP */ mtr_commit(mtr); @@ -2320,6 +2596,10 @@ row_upd_clust_step( index = dict_table_get_first_index(node->table); referenced = row_upd_index_is_referenced(index, thr_get_trx(thr)); +#ifdef WITH_WSREP + ibool foreign = wsrep_row_upd_index_is_foreign( + index, thr_get_trx(thr)); +#endif /* WITH_WSREP */ pcur = node->pcur; @@ -2414,7 +2694,11 @@ row_upd_clust_step( if (node->is_delete) { err = row_upd_del_mark_clust_rec( +#ifdef WITH_WSREP + node, index, offsets, thr, referenced, foreign, &mtr); +#else node, index, offsets, thr, referenced, &mtr); +#endif /* WITH_WSREP */ if (err == DB_SUCCESS) { node->state = UPD_NODE_UPDATE_ALL_SEC; @@ -2459,7 +2743,11 @@ row_upd_clust_step( externally! */ err = row_upd_clust_rec_by_insert( +#ifdef WITH_WSREP + node, index, thr, referenced, foreign, &mtr); +#else node, index, thr, referenced, &mtr); +#endif /* WITH_WSREP */ if (err != DB_SUCCESS) { diff --git a/storage/innobase/srv/srv0conc.cc b/storage/innobase/srv/srv0conc.cc index dc3c0b1dd88..cbf81f8e8f7 100644 --- a/storage/innobase/srv/srv0conc.cc +++ b/storage/innobase/srv/srv0conc.cc @@ -42,6 +42,10 @@ Created 2011/04/18 Sunny Bains #include "trx0trx.h" #include "mysql/plugin.h" +#ifdef WITH_WSREP +extern "C" int wsrep_trx_is_aborting(void *thd_ptr); +extern my_bool wsrep_debug; +#endif /** Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket. */ @@ -86,6 +90,9 @@ struct srv_conc_slot_t{ reserved may still be TRUE at that point */ srv_conc_node_t srv_conc_queue; /*!< queue node */ +#ifdef WITH_WSREP + void *thd; /*!< to see priority */ +#endif }; /** Queue of threads waiting to get in */ @@ -145,6 +152,9 @@ srv_conc_init(void) conc_slot->event = os_event_create(); ut_a(conc_slot->event); +#ifdef WITH_WSREP + conc_slot->thd = NULL; +#endif /* WITH_WSREP */ } #endif /* !HAVE_ATOMIC_BUILTINS */ } @@ -202,6 +212,16 @@ srv_conc_enter_innodb_with_atomics( for (;;) { ulint sleep_in_us; +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd) && + wsrep_trx_is_aborting(trx->mysql_thd)) { + if (wsrep_debug) + fprintf(stderr, + "srv_conc_enter due to MUST_ABORT"); + srv_conc_force_enter_innodb(trx); + return; + } +#endif /* WITH_WSREP */ if (srv_conc.n_active < (lint) srv_thread_concurrency) { ulint n_active; @@ -319,6 +339,9 @@ srv_conc_exit_innodb_without_atomics( slot = NULL; if (srv_conc.n_active < (lint) srv_thread_concurrency) { +#ifdef WITH_WSREP + srv_conc_slot_t* wsrep_slot; +#endif /* Look for a slot where a thread is waiting and no other thread has yet released the thread */ @@ -329,6 +352,19 @@ srv_conc_exit_innodb_without_atomics( /* No op */ } +#ifdef WITH_WSREP + /* look for aborting trx, they must be released asap */ + wsrep_slot= slot; + while (wsrep_slot && (wsrep_slot->wait_ended == TRUE || + !wsrep_trx_is_aborting(wsrep_slot->thd))) { + wsrep_slot = UT_LIST_GET_NEXT(srv_conc_queue, wsrep_slot); + } + if (wsrep_slot) { + slot = wsrep_slot; + if (wsrep_debug) + fprintf(stderr, "WSREP: releasing aborting thd\n"); + } +#endif if (slot != NULL) { slot->wait_ended = TRUE; @@ -384,6 +420,13 @@ retry: return; } +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd) && + wsrep_thd_is_brute_force(trx->mysql_thd)) { + srv_conc_force_enter_innodb(trx); + return; + } +#endif /* If the transaction is not holding resources, let it sleep for srv_thread_sleep_delay microseconds, and try again then */ @@ -450,6 +493,9 @@ retry: /* Add to the queue */ slot->reserved = TRUE; slot->wait_ended = FALSE; +#ifdef WITH_WSREP + slot->thd = trx->mysql_thd; +#endif UT_LIST_ADD_LAST(srv_conc_queue, srv_conc_queue, slot); @@ -457,6 +503,18 @@ retry: srv_conc.n_waiting++; +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd) && + wsrep_trx_is_aborting(trx->mysql_thd)) { + os_fast_mutex_unlock(&srv_conc_mutex); + if (wsrep_debug) + fprintf(stderr, "srv_conc_enter due to MUST_ABORT"); + trx->declared_to_be_inside_innodb = TRUE; + trx->n_tickets_to_enter_innodb = srv_n_free_tickets_to_enter; + return; + } + trx->wsrep_event = slot->event; +#endif /* WITH_WSREP */ os_fast_mutex_unlock(&srv_conc_mutex); /* Go to wait for the event; when a thread leaves InnoDB it will @@ -472,6 +530,9 @@ retry: os_event_wait(slot->event); thd_wait_end(trx->mysql_thd); +#ifdef WITH_WSREP + trx->wsrep_event = NULL; +#endif /* WITH_WSREP */ trx->op_info = ""; @@ -483,6 +544,9 @@ retry: incremented the thread counter on behalf of this thread */ slot->reserved = FALSE; +#ifdef WITH_WSREP + slot->thd = NULL; +#endif UT_LIST_REMOVE(srv_conc_queue, srv_conc_queue, slot); @@ -593,5 +657,32 @@ srv_conc_get_active_threads(void) /*==============================*/ { return(srv_conc.n_active); - } +} + +#ifdef WITH_WSREP +UNIV_INTERN +void +wsrep_srv_conc_cancel_wait( +/*==================*/ + trx_t* trx) /*!< in: transaction object associated with the + thread */ +{ +#ifdef HAVE_ATOMIC_BUILTINS + /* aborting transactions will enter innodb by force in + srv_conc_enter_innodb_with_atomics(). No need to cancel here, + thr will wake up after os_sleep and let to enter innodb + */ + if (wsrep_debug) + fprintf(stderr, "WSREP: conc slot cancel, no atomics\n"); +#else + os_fast_mutex_lock(&srv_conc_mutex); + if (trx->wsrep_event) { + if (wsrep_debug) + fprintf(stderr, "WSREP: conc slot cancel\n"); + os_event_set(trx->wsrep_event); + } + os_fast_mutex_unlock(&srv_conc_mutex); +#endif +} +#endif /* WITH_WSREP */ diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index b9cfb3544b9..ba742c7238c 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -73,6 +73,10 @@ Created 10/8/1995 Heikki Tuuri #include "mysql/service_thd_wait.h" #include "fil0pagecompress.h" +#ifdef WITH_WSREP +extern int wsrep_debug; +extern int wsrep_trx_is_aborting(void *thd_ptr); +#endif /* The following is the maximum allowed duration of a lock wait. */ UNIV_INTERN ulint srv_fatal_semaphore_wait_threshold = 600; @@ -223,6 +227,10 @@ srv_printf_innodb_monitor() will request mutex acquisition with mutex_enter(), which will wait until it gets the mutex. */ #define MUTEX_NOWAIT(mutex_skipped) ((mutex_skipped) < MAX_MUTEX_NOWAIT) +#ifdef WITH_INNODB_DISALLOW_WRITES +UNIV_INTERN os_event_t srv_allow_writes_event; +#endif /* WITH_INNODB_DISALLOW_WRITES */ + /** The sort order table of the MySQL latin1_swedish_ci character set collation */ UNIV_INTERN const byte* srv_latin1_ordering; @@ -1004,6 +1012,14 @@ srv_init(void) dict_ind_init(); srv_conc_init(); +#ifdef WITH_INNODB_DISALLOW_WRITES + /* Writes have to be enabled on init or else we hang. Thus, we + always set the event here regardless of innobase_disallow_writes. + That flag will always be 0 at this point because it isn't settable + via my.cnf or command line arg. */ + srv_allow_writes_event = os_event_create(); + os_event_set(srv_allow_writes_event); +#endif /* WITH_INNODB_DISALLOW_WRITES */ /* Initialize some INFORMATION SCHEMA internal structures */ trx_i_s_cache_init(trx_i_s_cache); @@ -1774,7 +1790,20 @@ loop: if (sync_array_print_long_waits(&waiter, &sema) && sema == old_sema && os_thread_eq(waiter, old_waiter)) { +#if defined(WITH_WSREP) && defined(WITH_INNODB_DISALLOW_WRITES) + if (srv_allow_writes_event->is_set) { +#endif /* WITH_WSREP */ fatal_cnt++; +#if defined(WITH_WSREP) && defined(WITH_INNODB_DISALLOW_WRITES) + } else { + fprintf(stderr, + "WSREP: avoiding InnoDB self crash due to long " + "semaphore wait of > %lu seconds\n" + "Server is processing SST donor operation, " + "fatal_cnt now: %lu", + (ulong) srv_fatal_semaphore_wait_threshold, fatal_cnt); + } +#endif /* WITH_WSREP */ if (fatal_cnt > 10) { fprintf(stderr, diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc index fcf1c1cedf4..4af61d4869b 100644 --- a/storage/innobase/trx/trx0sys.cc +++ b/storage/innobase/trx/trx0sys.cc @@ -44,6 +44,10 @@ Created 3/26/1996 Heikki Tuuri #include "os0file.h" #include "read0read.h" +#ifdef WITH_WSREP +#include "ha_prototypes.h" /* wsrep_is_wsrep_xid() */ +#endif /* */ + /** The file format tag structure with id and name. */ struct file_format_t { ulint id; /*!< id of the file format */ @@ -174,7 +178,12 @@ trx_sys_flush_max_trx_id(void) mtr_t mtr; trx_sysf_t* sys_header; +#ifndef WITH_WSREP + /* wsrep_fake_trx_id violates this assert + * Copied from trx_sys_get_new_trx_id + */ ut_ad(mutex_own(&trx_sys->mutex)); +#endif /* WITH_WSREP */ if (!srv_read_only_mode) { mtr_start(&mtr); @@ -202,9 +211,14 @@ trx_sys_update_mysql_binlog_offset( ib_int64_t offset, /*!< in: position in that log file */ ulint field, /*!< in: offset of the MySQL log info field in the trx sys header */ +#ifdef WITH_WSREP + trx_sysf_t* sys_header, /*!< in: trx sys header */ +#endif /* WITH_WSREP */ mtr_t* mtr) /*!< in: mtr */ { +#ifndef WITH_WSREP trx_sysf_t* sys_header; +#endif /* !WITH_WSREP */ if (ut_strlen(file_name) >= TRX_SYS_MYSQL_LOG_NAME_LEN) { @@ -213,7 +227,9 @@ trx_sys_update_mysql_binlog_offset( return; } +#ifndef WITH_WSREP sys_header = trx_sysf_get(mtr); +#endif /* !WITH_WSREP */ if (mach_read_from_4(sys_header + field + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD) @@ -300,6 +316,124 @@ trx_sys_print_mysql_binlog_offset(void) mtr_commit(&mtr); } +#ifdef WITH_WSREP + +#ifdef UNIV_DEBUG +static long long trx_sys_cur_xid_seqno = -1; +static unsigned char trx_sys_cur_xid_uuid[16]; + +long long read_wsrep_xid_seqno(const XID* xid) +{ + long long seqno; + memcpy(&seqno, xid->data + 24, sizeof(long long)); + return seqno; +} + +void read_wsrep_xid_uuid(const XID* xid, unsigned char* buf) +{ + memcpy(buf, xid->data + 8, 16); +} + +#endif /* UNIV_DEBUG */ + +void +trx_sys_update_wsrep_checkpoint( + const XID* xid, /*!< in: transaction XID */ + trx_sysf_t* sys_header, /*!< in: sys_header */ + mtr_t* mtr) /*!< in: mtr */ +{ +#ifdef UNIV_DEBUG + { + /* Check that seqno is monotonically increasing */ + unsigned char xid_uuid[16]; + long long xid_seqno = read_wsrep_xid_seqno(xid); + read_wsrep_xid_uuid(xid, xid_uuid); + if (!memcmp(xid_uuid, trx_sys_cur_xid_uuid, 8)) + { + ut_ad(xid_seqno > trx_sys_cur_xid_seqno); + trx_sys_cur_xid_seqno = xid_seqno; + } + else + { + memcpy(trx_sys_cur_xid_uuid, xid_uuid, 16); + } + trx_sys_cur_xid_seqno = xid_seqno; + } +#endif /* UNIV_DEBUG */ + + ut_ad(xid && mtr); + ut_a(xid->formatID == -1 || wsrep_is_wsrep_xid(xid)); + + if (mach_read_from_4(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_MAGIC_N_FLD) + != TRX_SYS_WSREP_XID_MAGIC_N) { + mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_MAGIC_N_FLD, + TRX_SYS_WSREP_XID_MAGIC_N, + MLOG_4BYTES, mtr); + } + + mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_FORMAT, + (int)xid->formatID, + MLOG_4BYTES, mtr); + mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_GTRID_LEN, + (int)xid->gtrid_length, + MLOG_4BYTES, mtr); + mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_BQUAL_LEN, + (int)xid->bqual_length, + MLOG_4BYTES, mtr); + mlog_write_string(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_DATA, + (const unsigned char*) xid->data, + XIDDATASIZE, mtr); + +} + +void +trx_sys_read_wsrep_checkpoint(XID* xid) +/*===================================*/ +{ + trx_sysf_t* sys_header; + mtr_t mtr; + ulint magic; + + ut_ad(xid); + + mtr_start(&mtr); + + sys_header = trx_sysf_get(&mtr); + + if ((magic = mach_read_from_4(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_MAGIC_N_FLD)) + != TRX_SYS_WSREP_XID_MAGIC_N) { + memset(xid, 0, sizeof(*xid)); + xid->formatID = -1; + trx_sys_update_wsrep_checkpoint(xid, sys_header, &mtr); + mtr_commit(&mtr); + return; + } + + xid->formatID = (int)mach_read_from_4( + sys_header + + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_FORMAT); + xid->gtrid_length = (int)mach_read_from_4( + sys_header + + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_GTRID_LEN); + xid->bqual_length = (int)mach_read_from_4( + sys_header + + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_BQUAL_LEN); + ut_memcpy(xid->data, + sys_header + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_DATA, + XIDDATASIZE); + + mtr_commit(&mtr); +} + +#endif /* WITH_WSREP */ + /*****************************************************************//** Prints to stderr the MySQL master log offset info in the trx system header if the magic number shows it valid. */ diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index a07167168fc..48073667b2f 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -159,6 +159,9 @@ trx_create(void) trx->lock.table_locks = ib_vector_create( heap_alloc, sizeof(void**), 32); +#ifdef WITH_WSREP + trx->wsrep_event = NULL; +#endif /* WITH_WSREP */ return(trx); } @@ -854,6 +857,11 @@ trx_start_low( srv_undo_logs, srv_undo_tablespaces); } +#ifdef WITH_WSREP + memset(&trx->xid, 0, sizeof(trx->xid)); + trx->xid.formatID = -1; +#endif /* WITH_WSREP */ + /* The initial value for trx->no: TRX_ID_MAX is used in read_view_open_now: */ @@ -968,6 +976,9 @@ trx_write_serialisation_history( trx_t* trx, /*!< in/out: transaction */ mtr_t* mtr) /*!< in/out: mini-transaction */ { +#ifdef WITH_WSREP + trx_sysf_t* sys_header; +#endif /* WITH_WSREP */ trx_rseg_t* rseg; rseg = trx->rseg; @@ -1014,6 +1025,15 @@ trx_write_serialisation_history( MONITOR_INC(MONITOR_TRX_COMMIT_UNDO); +#ifdef WITH_WSREP + sys_header = trx_sysf_get(mtr); + /* Update latest MySQL wsrep XID in trx sys header. */ + if (wsrep_is_wsrep_xid((const void *)&trx->xid)) + { + trx_sys_update_wsrep_checkpoint(&trx->xid, sys_header, mtr); + } +#endif /* WITH_WSREP */ + /* Update the latest MySQL binlog name and offset info in trx sys header if MySQL binlogging is on or the database server is a MySQL replication slave */ @@ -1024,7 +1044,11 @@ trx_write_serialisation_history( trx_sys_update_mysql_binlog_offset( trx->mysql_log_file_name, trx->mysql_log_offset, - TRX_SYS_MYSQL_LOG_INFO, mtr); + TRX_SYS_MYSQL_LOG_INFO, +#ifdef WITH_WSREP + sys_header, +#endif /* WITH_WSREP */ + mtr); trx->mysql_log_file_name = NULL; } @@ -1312,6 +1336,11 @@ trx_commit_in_memory( ut_ad(!trx->in_ro_trx_list); ut_ad(!trx->in_rw_trx_list); +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd)) { + trx->lock.was_chosen_as_deadlock_victim = FALSE; + } +#endif trx->dict_operation = TRX_DICT_OP_NONE; trx->error_state = DB_SUCCESS; @@ -1496,6 +1525,10 @@ trx_commit_or_rollback_prepare( switch (trx->state) { case TRX_STATE_NOT_STARTED: +#ifdef WITH_WSREP + ut_d(trx->start_file = __FILE__); + ut_d(trx->start_line = __LINE__); +#endif /* WITH_WSREP */ trx_start_low(trx); /* fall through */ case TRX_STATE_ACTIVE: diff --git a/storage/innobase/wsrep/md5.cc b/storage/innobase/wsrep/md5.cc new file mode 100644 index 00000000000..30be6ab7dd3 --- /dev/null +++ b/storage/innobase/wsrep/md5.cc @@ -0,0 +1,74 @@ +/* + Copyright (c) 2014 SkySQL AB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifdef WITH_WSREP + +#if defined(HAVE_YASSL) +#include "my_config.h" +#include "md5.hpp" +#elif defined(HAVE_OPENSSL) +#include +#endif /* HAVE_YASSL */ + +/* Initialize md5 object. */ +void *wsrep_md5_init() +{ +#if defined(HAVE_YASSL) + TaoCrypt::MD5 *hasher= new TaoCrypt::MD5; + return (void*)hasher; +#elif defined(HAVE_OPENSSL) + MD5_CTX *ctx = new MD5_CTX(); + MD5_Init (ctx); + return (void *)ctx; +#endif /* HAVE_YASSL */ +} + +/** + Supply message to be hashed. + + @param ctx [IN] Pointer to MD5 context + @param buf [IN] Message to be computed. + @param len [IN] Length of the message. +*/ +void wsrep_md5_update(void *ctx, char* buf, int len) +{ +#if defined(HAVE_YASSL) + ((TaoCrypt::MD5 *)ctx)->Update((TaoCrypt::byte *) buf, len); +#elif defined(HAVE_OPENSSL) + MD5_Update((MD5_CTX*)(ctx), buf, len); +#endif /* HAVE_YASSL */ +} + +/** + Place computed MD5 digest into the given buffer. + + @param digest [OUT] Computed MD5 digest + @param ctx [IN] Pointer to MD5 context +*/ +void wsrep_compute_md5_hash(char *digest, void *ctx) +{ +#if defined(HAVE_YASSL) + ((TaoCrypt::MD5*)ctx)->Final((TaoCrypt::byte *) digest); + delete (TaoCrypt::MD5*)ctx; +#elif defined(HAVE_OPENSSL) + MD5_Final ((unsigned char*)digest, (MD5_CTX*)ctx); + delete (MD5_CTX*)ctx; +#endif /* HAVE_YASSL */ +} + +#endif /* WITH_WSREP */ + diff --git a/storage/innobase/wsrep/wsrep_md5.h b/storage/innobase/wsrep/wsrep_md5.h new file mode 100644 index 00000000000..1339f7f4b86 --- /dev/null +++ b/storage/innobase/wsrep/wsrep_md5.h @@ -0,0 +1,26 @@ +#ifndef WSREP_MD5_INCLUDED +#define WSREP_MD5_INCLUDED + +/* Copyright (c) 2014 SkySQL AB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +*/ + +#ifdef WITH_WSREP +void *wsrep_md5_init(); +void wsrep_md5_update(void *ctx, char* buf, int len); +void wsrep_compute_md5_hash(char *digest, void *ctx); +#endif /* WITH_WSREP */ + +#endif /* WSREP_MD5_INCLUDED */ diff --git a/storage/perfschema/CMakeLists.txt b/storage/perfschema/CMakeLists.txt index 718baa8296b..aaa1142a180 100644 --- a/storage/perfschema/CMakeLists.txt +++ b/storage/perfschema/CMakeLists.txt @@ -13,6 +13,10 @@ # along with this program; if not, write to the Free Software Foundation, # 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA +IF (WITH_WSREP) + BUILD_WITH_WSREP() +ENDIF() + INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/sql diff --git a/storage/xtradb/CMakeLists.txt b/storage/xtradb/CMakeLists.txt index 528c6f87fcc..6d9bd1a500a 100644 --- a/storage/xtradb/CMakeLists.txt +++ b/storage/xtradb/CMakeLists.txt @@ -268,6 +268,27 @@ ENDIF() INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/storage/xtradb/include ${CMAKE_SOURCE_DIR}/storage/xtradb/handler) +IF(WITH_WSREP) + # ssl include directory + INCLUDE_DIRECTORIES(${SSL_INCLUDE_DIRS} + ${CMAKE_SOURCE_DIR}/storage/xtradb/wsrep) + + IF(SSL_DEFINES) + ADD_DEFINITIONS(${SSL_DEFINES}) + ENDIF() + + LINK_LIBRARIES(${SSL_LIBRARIES}) + + # We do RESTRICT_SYMBOL_EXPORTS(yassl) elsewhere. + # In order to get correct symbol visibility, these files + # must be compiled with "-fvisibility=hidden" + IF(WITH_SSL STREQUAL "bundled" AND HAVE_VISIBILITY_HIDDEN) + SET_SOURCE_FILES_PROPERTIES( + {CMAKE_CURRENT_SOURCE_DIR}/wsrep/md5.cc + PROPERTIES COMPILE_FLAGS "-fvisibility=hidden") + ENDIF() +ENDIF() + # Sun Studio bug with -xO2 IF(CMAKE_CXX_COMPILER_ID MATCHES "SunPro" AND CMAKE_CXX_FLAGS_RELEASE MATCHES "O2" @@ -407,6 +428,10 @@ SET(INNOBASE_SOURCES ut/ut0vec.cc ut/ut0wqueue.cc) +IF(WITH_WSREP) + SET(INNOBASE_SOURCES ${INNOBASE_SOURCES} wsrep/md5.cc) +ENDIF() + IF(NOT XTRADB_OK) MESSAGE(FATAL_ERROR "Percona XtraDB is not supported on this platform") ENDIF() diff --git a/storage/xtradb/dict/dict0dict.cc b/storage/xtradb/dict/dict0dict.cc index af3518337d4..c340590b4bb 100644 --- a/storage/xtradb/dict/dict0dict.cc +++ b/storage/xtradb/dict/dict0dict.cc @@ -3241,7 +3241,29 @@ dict_foreign_find_index( return(NULL); } - +#ifdef WITH_WSREP +dict_index_t* +wsrep_dict_foreign_find_index( +/*====================*/ + dict_table_t* table, /*!< in: table */ + const char** col_names, /*!< in: column names, or NULL + to use table->col_names */ + const char** columns,/*!< in: array of column names */ + ulint n_cols, /*!< in: number of columns */ + dict_index_t* types_idx, /*!< in: NULL or an index to whose types the + column types must match */ + ibool check_charsets, + /*!< in: whether to check charsets. + only has an effect if types_idx != NULL */ + ulint check_null) + /*!< in: nonzero if none of the columns must + be declared NOT NULL */ +{ + return dict_foreign_find_index( + table, col_names, columns, n_cols, types_idx, check_charsets, + check_null); +} +#endif /* WITH_WSREP */ /**********************************************************************//** Report an error in a foreign key definition. */ static diff --git a/storage/xtradb/fil/fil0fil.cc b/storage/xtradb/fil/fil0fil.cc index d40cfa57bd5..343cc0f47c4 100644 --- a/storage/xtradb/fil/fil0fil.cc +++ b/storage/xtradb/fil/fil0fil.cc @@ -6833,36 +6833,36 @@ fil_get_page_type_name( { switch(page_type) { case FIL_PAGE_PAGE_COMPRESSED: - return "PAGE_COMPRESSED"; + return (char *)"PAGE_COMPRESSED"; case FIL_PAGE_INDEX: - return "INDEX"; + return (char *)"INDEX"; case FIL_PAGE_UNDO_LOG: - return "UNDO LOG"; + return (char *)"UNDO LOG"; case FIL_PAGE_INODE: - return "INODE"; + return (char *)"INODE"; case FIL_PAGE_IBUF_FREE_LIST: - return "IBUF_FREE_LIST"; + return (char *)"IBUF_FREE_LIST"; case FIL_PAGE_TYPE_ALLOCATED: - return "ALLOCATED"; + return (char *)"ALLOCATED"; case FIL_PAGE_IBUF_BITMAP: - return "IBUF_BITMAP"; + return (char *)"IBUF_BITMAP"; case FIL_PAGE_TYPE_SYS: - return "SYS"; + return (char *)"SYS"; case FIL_PAGE_TYPE_TRX_SYS: - return "TRX_SYS"; + return (char *)"TRX_SYS"; case FIL_PAGE_TYPE_FSP_HDR: - return "FSP_HDR"; + return (char *)"FSP_HDR"; case FIL_PAGE_TYPE_XDES: - return "XDES"; + return (char *)"XDES"; case FIL_PAGE_TYPE_BLOB: - return "BLOB"; + return (char *)"BLOB"; case FIL_PAGE_TYPE_ZBLOB: - return "ZBLOB"; + return (char *)"ZBLOB"; case FIL_PAGE_TYPE_ZBLOB2: - return "ZBLOB2"; + return (char *)"ZBLOB2"; case FIL_PAGE_TYPE_COMPRESSED: - return "ORACLE PAGE COMPRESSED"; + return (char *)"ORACLE PAGE COMPRESSED"; default: - return "PAGE TYPE CORRUPTED"; + return (char *)"PAGE TYPE CORRUPTED"; } } diff --git a/storage/xtradb/fil/fil0pagecompress.cc b/storage/xtradb/fil/fil0pagecompress.cc index 854b094ea81..ec19a4ef4b7 100644 --- a/storage/xtradb/fil/fil0pagecompress.cc +++ b/storage/xtradb/fil/fil0pagecompress.cc @@ -487,7 +487,9 @@ fil_decompress_page( ulint actual_size = 0; ulint compression_alg = 0; byte *in_buf; +#ifdef HAVE_LZO ulint olen=0; +#endif ulint ptype; ut_ad(buf); diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index fb3e097491d..4c4bccd15e1 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -120,6 +120,44 @@ this program; if not, write to the Free Software Foundation, Inc., # define MYSQL_PLUGIN_IMPORT /* nothing */ # endif /* MYSQL_PLUGIN_IMPORT */ +#ifdef WITH_WSREP +#include "dict0priv.h" +#include "../storage/innobase/include/ut0byte.h" +#include +#include + +extern my_bool wsrep_certify_nonPK; +class binlog_trx_data; +extern handlerton *binlog_hton; + +extern MYSQL_PLUGIN_IMPORT mysql_mutex_t LOCK_wsrep_rollback; +extern MYSQL_PLUGIN_IMPORT mysql_cond_t COND_wsrep_rollback; +extern MYSQL_PLUGIN_IMPORT wsrep_aborting_thd_t wsrep_aborting_thd; + +static inline wsrep_ws_handle_t* +wsrep_ws_handle(THD* thd, const trx_t* trx) { + return wsrep_ws_handle_for_trx(wsrep_thd_ws_handle(thd), + (wsrep_trx_id_t)trx->id); +} + +extern bool wsrep_prepare_key_for_innodb(const uchar *cache_key, + size_t cache_key_len, + const uchar* row_id, + size_t row_id_len, + wsrep_buf_t* key, + size_t* key_len); + +extern handlerton * wsrep_hton; +extern TC_LOG* tc_log; +extern void wsrep_cleanup_transaction(THD *thd); +static int +wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd, + my_bool signal); +static void +wsrep_fake_trx_id(handlerton* hton, THD *thd); +static int innobase_wsrep_set_checkpoint(handlerton* hton, const XID* xid); +static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid); +#endif /* WITH_WSREP */ /** to protect innobase_open_files */ static mysql_mutex_t innobase_share_mutex; /** to force correct commit order in binlog */ @@ -1483,6 +1521,10 @@ innobase_srv_conc_enter_innodb( /*===========================*/ trx_t* trx) /*!< in: transaction handle */ { +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd) && + wsrep_thd_is_BF(trx->mysql_thd, FALSE)) return; +#endif /* WITH_WSREP */ if (srv_thread_concurrency) { if (trx->n_tickets_to_enter_innodb > 0) { @@ -1517,6 +1559,10 @@ innobase_srv_conc_exit_innodb( #ifdef UNIV_SYNC_DEBUG ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch)); #endif /* UNIV_SYNC_DEBUG */ +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd) && + wsrep_thd_is_BF(trx->mysql_thd, FALSE)) return; +#endif /* WITH_WSREP */ /* This is to avoid making an unnecessary function call. */ if (trx->declared_to_be_inside_innodb @@ -1649,6 +1695,16 @@ thd_to_trx( return(*(trx_t**) thd_ha_data(thd, innodb_hton_ptr)); } +#ifdef WITH_WSREP +ulonglong +thd_to_trx_id( +/*=======*/ + THD* thd) /*!< in: MySQL thread */ +{ + return(thd_to_trx(thd)->id); +} +#endif /* WITH_WSREP */ + my_bool ha_innobase::is_fake_change_enabled(THD* thd) { @@ -2149,6 +2205,9 @@ int innobase_mysql_tmpfile(void) /*========================*/ { +#ifdef WITH_INNODB_DISALLOW_WRITES + os_event_wait(srv_allow_writes_event); +#endif /* WITH_INNODB_DISALLOW_WRITES */ int fd2 = -1; File fd; @@ -3313,6 +3372,12 @@ innobase_init( innobase_hton->tablefile_extensions = ha_innobase_exts; innobase_hton->table_options = innodb_table_option_list; +#ifdef WITH_WSREP + innobase_hton->abort_transaction=wsrep_abort_transaction; + innobase_hton->set_checkpoint=innobase_wsrep_set_checkpoint; + innobase_hton->get_checkpoint=innobase_wsrep_get_checkpoint; + innobase_hton->fake_trx_id=wsrep_fake_trx_id; +#endif /* WITH_WSREP */ ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR); @@ -4050,10 +4115,30 @@ innobase_commit_low( /*================*/ trx_t* trx) /*!< in: transaction handle */ { +#ifdef WITH_WSREP + THD* thd = (THD*)trx->mysql_thd; + const char* tmp = 0; + if (wsrep_on((void*)thd)) { +#ifdef WSREP_PROC_INFO + char info[64]; + info[sizeof(info) - 1] = '\0'; + snprintf(info, sizeof(info) - 1, + "innobase_commit_low():trx_commit_for_mysql(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); + tmp = thd_proc_info(thd, info); + +#else + tmp = thd_proc_info(thd, "innobase_commit_low()"); +#endif /* WSREP_PROC_INFO */ + } +#endif /* WITH_WSREP */ if (trx_is_started(trx)) { trx_commit_for_mysql(trx); } +#ifdef WITH_WSREP + if (wsrep_on((void*)thd)) { thd_proc_info(thd, tmp); } +#endif /* WITH_WSREP */ } /*****************************************************************//** @@ -4828,22 +4913,32 @@ innobase_kill_connection( DBUG_ENTER("innobase_kill_connection"); DBUG_ASSERT(hton == innodb_hton_ptr); - lock_mutex_enter(); - +#ifdef WITH_WSREP + wsrep_thd_LOCK(thd); + if (wsrep_thd_conflict_state(thd) != NO_CONFLICT) { + /* if victim has been signaled by BF thread and/or aborting + is already progressing, following query aborting is not necessary + any more. + Also, BF thread should own trx mutex for the victim, which would + conflict with trx_mutex_enter() below + */ + wsrep_thd_UNLOCK(thd); + DBUG_VOID_RETURN; + } + wsrep_thd_UNLOCK(thd); +#endif /* WITH_WSREP */ trx = thd_to_trx(thd); if (trx) { - trx_mutex_enter(trx); - - /* Cancel a pending lock request. */ - if (trx->lock.wait_lock) - lock_cancel_waiting_and_release(trx->lock.wait_lock); - - trx_mutex_exit(trx); - } - - lock_mutex_exit(); + /* Cancel a pending lock request. */ + lock_mutex_enter(); + trx_mutex_enter(trx); + if (trx->lock.wait_lock) + lock_cancel_waiting_and_release(trx->lock.wait_lock); + trx_mutex_exit(trx); + lock_mutex_exit(); + } DBUG_VOID_RETURN; } @@ -4956,7 +5051,11 @@ ha_innobase::max_supported_key_length() const case 8192: return(1536); default: +#ifdef WITH_WSREP return(3500); +#else + return(3500); +#endif } } @@ -6072,6 +6171,117 @@ get_field_offset( return((uint) (field->ptr - table->record[0])); } +#ifdef WITH_WSREP +UNIV_INTERN +int +wsrep_innobase_mysql_sort( +/*===============*/ + /* out: str contains sort string */ + int mysql_type, /* in: MySQL type */ + uint charset_number, /* in: number of the charset */ + unsigned char* str, /* in: data field */ + unsigned int str_length, /* in: data field length, + not UNIV_SQL_NULL */ + unsigned int buf_length) /* in: total str buffer length */ + +{ + CHARSET_INFO* charset; + enum_field_types mysql_tp; + int ret_length = str_length; + + DBUG_ASSERT(str_length != UNIV_SQL_NULL); + + mysql_tp = (enum_field_types) mysql_type; + + switch (mysql_tp) { + + case MYSQL_TYPE_BIT: + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_VARCHAR: + { + uchar tmp_str[REC_VERSION_56_MAX_INDEX_COL_LEN] = {'\0'}; + uint tmp_length = REC_VERSION_56_MAX_INDEX_COL_LEN; + + /* Use the charset number to pick the right charset struct for + the comparison. Since the MySQL function get_charset may be + slow before Bar removes the mutex operation there, we first + look at 2 common charsets directly. */ + + if (charset_number == default_charset_info->number) { + charset = default_charset_info; + } else if (charset_number == my_charset_latin1.number) { + charset = &my_charset_latin1; + } else { + charset = get_charset(charset_number, MYF(MY_WME)); + + if (charset == NULL) { + sql_print_error("InnoDB needs charset %lu for doing " + "a comparison, but MySQL cannot " + "find that charset.", + (ulong) charset_number); + ut_a(0); + } + } + + ut_a(str_length <= tmp_length); + memcpy(tmp_str, str, str_length); + + tmp_length = charset->coll->strnxfrm(charset, str, str_length, + str_length, tmp_str, + tmp_length, 0); + DBUG_ASSERT(tmp_length <= str_length); + if (wsrep_protocol_version < 3) { + tmp_length = charset->coll->strnxfrm( + charset, str, str_length, + str_length, tmp_str, tmp_length, 0); + DBUG_ASSERT(tmp_length <= str_length); + } else { + /* strnxfrm will expand the destination string, + protocols < 3 truncated the sorted sring + protocols >= 3 gets full sorted sring + */ + tmp_length = charset->coll->strnxfrm( + charset, str, buf_length, + str_length, tmp_str, str_length, 0); + DBUG_ASSERT(tmp_length <= buf_length); + ret_length = tmp_length; + } + + break; + } + case MYSQL_TYPE_DECIMAL : + case MYSQL_TYPE_TINY : + case MYSQL_TYPE_SHORT : + case MYSQL_TYPE_LONG : + case MYSQL_TYPE_FLOAT : + case MYSQL_TYPE_DOUBLE : + case MYSQL_TYPE_NULL : + case MYSQL_TYPE_TIMESTAMP : + case MYSQL_TYPE_LONGLONG : + case MYSQL_TYPE_INT24 : + case MYSQL_TYPE_DATE : + case MYSQL_TYPE_TIME : + case MYSQL_TYPE_DATETIME : + case MYSQL_TYPE_YEAR : + case MYSQL_TYPE_NEWDATE : + case MYSQL_TYPE_NEWDECIMAL : + case MYSQL_TYPE_ENUM : + case MYSQL_TYPE_SET : + case MYSQL_TYPE_GEOMETRY : + break; + default: + break; + } + + return ret_length; +} +#endif /* WITH_WSREP */ + /*************************************************************//** InnoDB uses this function to compare two data fields for which the data type is such that we must use MySQL code to compare them. NOTE that the prototype @@ -6572,6 +6782,312 @@ innobase_read_from_2_little_endian( return((uint) ((ulint)(buf[0]) + 256 * ((ulint)(buf[1])))); } +/*******************************************************************//** +Stores a key value for a row to a buffer. +@return key value length as stored in buff */ +#ifdef WITH_WSREP +UNIV_INTERN +uint +wsrep_store_key_val_for_row( +/*===============================*/ + THD* thd, + TABLE* table, + uint keynr, /*!< in: key number */ + char* buff, /*!< in/out: buffer for the key value (in MySQL + format) */ + uint buff_len,/*!< in: buffer length */ + const uchar* record, + ibool* key_is_null)/*!< out: full key was null */ +{ + KEY* key_info = table->key_info + keynr; + KEY_PART_INFO* key_part = key_info->key_part; + KEY_PART_INFO* end = key_part + key_info->user_defined_key_parts; + char* buff_start = buff; + enum_field_types mysql_type; + Field* field; + uint buff_space = buff_len; + + DBUG_ENTER("wsrep_store_key_val_for_row"); + + memset(buff, 0, buff_len); + *key_is_null = TRUE; + + for (; key_part != end; key_part++) { + + uchar sorted[REC_VERSION_56_MAX_INDEX_COL_LEN] = {'\0'}; + ibool part_is_null = FALSE; + + if (key_part->null_bit) { + if (buff_space > 0) { + if (record[key_part->null_offset] + & key_part->null_bit) { + *buff = 1; + part_is_null = TRUE; + } else { + *buff = 0; + } + buff++; + buff_space--; + } else { + fprintf (stderr, "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); + } + } + if (!part_is_null) *key_is_null = FALSE; + + field = key_part->field; + mysql_type = field->type(); + + if (mysql_type == MYSQL_TYPE_VARCHAR) { + /* >= 5.0.3 true VARCHAR */ + ulint lenlen; + ulint len; + const byte* data; + ulint key_len; + ulint true_len; + const CHARSET_INFO* cs; + int error=0; + + key_len = key_part->length; + + if (part_is_null) { + true_len = key_len + 2; + if (true_len > buff_space) { + fprintf (stderr, + "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); + true_len = buff_space; + } + buff += true_len; + buff_space -= true_len; + continue; + } + cs = field->charset(); + + lenlen = (ulint) + (((Field_varstring*)field)->length_bytes); + + data = row_mysql_read_true_varchar(&len, + (byte*) (record + + (ulint)get_field_offset(table, field)), + lenlen); + + true_len = len; + + /* For multi byte character sets we need to calculate + the true length of the key */ + + if (len > 0 && cs->mbmaxlen > 1) { + true_len = (ulint) cs->cset->well_formed_len(cs, + (const char *) data, + (const char *) data + len, + (uint) (key_len / + cs->mbmaxlen), + &error); + } + + /* In a column prefix index, we may need to truncate + the stored value: */ + + if (true_len > key_len) { + true_len = key_len; + } + + memcpy(sorted, data, true_len); + true_len = wsrep_innobase_mysql_sort( + mysql_type, cs->number, sorted, true_len, + REC_VERSION_56_MAX_INDEX_COL_LEN); + + if (wsrep_protocol_version > 1) { + /* Note that we always reserve the maximum possible + length of the true VARCHAR in the key value, though + only len first bytes after the 2 length bytes contain + actual data. The rest of the space was reset to zero + in the bzero() call above. */ + if (true_len > buff_space) { + fprintf (stderr, + "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); + true_len = buff_space; + } + memcpy(buff, sorted, true_len); + buff += true_len; + buff_space -= true_len; + } else { + buff += key_len; + } + } else if (mysql_type == MYSQL_TYPE_TINY_BLOB + || mysql_type == MYSQL_TYPE_MEDIUM_BLOB + || mysql_type == MYSQL_TYPE_BLOB + || mysql_type == MYSQL_TYPE_LONG_BLOB + /* MYSQL_TYPE_GEOMETRY data is treated + as BLOB data in innodb. */ + || mysql_type == MYSQL_TYPE_GEOMETRY) { + + const CHARSET_INFO* cs; + ulint key_len; + ulint true_len; + int error=0; + ulint blob_len; + const byte* blob_data; + + ut_a(key_part->key_part_flag & HA_PART_KEY_SEG); + + key_len = key_part->length; + + if (part_is_null) { + true_len = key_len + 2; + if (true_len > buff_space) { + fprintf (stderr, + "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); + true_len = buff_space; + } + buff += true_len; + buff_space -= true_len; + + continue; + } + + cs = field->charset(); + + blob_data = row_mysql_read_blob_ref(&blob_len, + (byte*) (record + + (ulint)get_field_offset(table, field)), + (ulint) field->pack_length()); + + true_len = blob_len; + + ut_a(get_field_offset(table, field) + == key_part->offset); + + /* For multi byte character sets we need to calculate + the true length of the key */ + + if (blob_len > 0 && cs->mbmaxlen > 1) { + true_len = (ulint) cs->cset->well_formed_len(cs, + (const char *) blob_data, + (const char *) blob_data + + blob_len, + (uint) (key_len / + cs->mbmaxlen), + &error); + } + + /* All indexes on BLOB and TEXT are column prefix + indexes, and we may need to truncate the data to be + stored in the key value: */ + + if (true_len > key_len) { + true_len = key_len; + } + + memcpy(sorted, blob_data, true_len); + true_len = wsrep_innobase_mysql_sort( + mysql_type, cs->number, sorted, true_len, + REC_VERSION_56_MAX_INDEX_COL_LEN); + + + /* Note that we always reserve the maximum possible + length of the BLOB prefix in the key value. */ + if (wsrep_protocol_version > 1) { + if (true_len > buff_space) { + fprintf (stderr, + "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); + true_len = buff_space; + } + buff += true_len; + buff_space -= true_len; + } else { + buff += key_len; + } + memcpy(buff, sorted, true_len); + } else { + /* Here we handle all other data types except the + true VARCHAR, BLOB and TEXT. Note that the column + value we store may be also in a column prefix + index. */ + + const CHARSET_INFO* cs = NULL; + ulint true_len; + ulint key_len; + const uchar* src_start; + int error=0; + enum_field_types real_type; + + key_len = key_part->length; + + if (part_is_null) { + true_len = key_len; + if (true_len > buff_space) { + fprintf (stderr, + "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); + true_len = buff_space; + } + buff += true_len; + buff_space -= true_len; + + continue; + } + + src_start = record + key_part->offset; + real_type = field->real_type(); + true_len = key_len; + + /* Character set for the field is defined only + to fields whose type is string and real field + type is not enum or set. For these fields check + if character set is multi byte. */ + + if (real_type != MYSQL_TYPE_ENUM + && real_type != MYSQL_TYPE_SET + && ( mysql_type == MYSQL_TYPE_VAR_STRING + || mysql_type == MYSQL_TYPE_STRING)) { + + cs = field->charset(); + + /* For multi byte character sets we need to + calculate the true length of the key */ + + if (key_len > 0 && cs->mbmaxlen > 1) { + + true_len = (ulint) + cs->cset->well_formed_len(cs, + (const char *)src_start, + (const char *)src_start + + key_len, + (uint) (key_len / + cs->mbmaxlen), + &error); + } + memcpy(sorted, src_start, true_len); + true_len = wsrep_innobase_mysql_sort( + mysql_type, cs->number, sorted, true_len, + REC_VERSION_56_MAX_INDEX_COL_LEN); + + if (true_len > buff_space) { + fprintf (stderr, + "WSREP: key truncated: %s\n", + wsrep_thd_query(thd)); + true_len = buff_space; + } + memcpy(buff, sorted, true_len); + } else { + memcpy(buff, src_start, true_len); + } + buff += true_len; + buff_space -= true_len; + } + } + + ut_a(buff <= buff_start + buff_len); + + DBUG_RETURN((uint)(buff - buff_start)); +} +#endif /* WITH_WSREP */ + /*******************************************************************//** Stores a key value for a row to a buffer. @return key value length as stored in buff */ @@ -7419,6 +7935,9 @@ ha_innobase::write_row( ibool auto_inc_used= FALSE; ulint sql_command; trx_t* trx = thd_to_trx(user_thd); +#ifdef WITH_WSREP + ibool auto_inc_inserted= FALSE; /* if NULL was inserted */ +#endif DBUG_ENTER("ha_innobase::write_row"); @@ -7454,8 +7973,18 @@ ha_innobase::write_row( if ((sql_command == SQLCOM_ALTER_TABLE || sql_command == SQLCOM_OPTIMIZE || sql_command == SQLCOM_CREATE_INDEX +#ifdef WITH_WSREP + || (wsrep_on(user_thd) && wsrep_load_data_splitting && + sql_command == SQLCOM_LOAD) +#endif /* WITH_WSREP */ || sql_command == SQLCOM_DROP_INDEX) && num_write_row >= 10000) { +#ifdef WITH_WSREP + if (wsrep_on(user_thd) && sql_command == SQLCOM_LOAD) { + WSREP_DEBUG("forced trx split for LOAD: %s", + wsrep_thd_query(user_thd)); + } +#endif /* WITH_WSREP */ /* ALTER TABLE is COMMITted at every 10000 copied rows. The IX table lock for the original table has to be re-issued. As this method will be called on a temporary table where the @@ -7489,6 +8018,21 @@ no_commit: */ ; } else if (src_table == prebuilt->table) { +#ifdef WITH_WSREP + switch (wsrep_run_wsrep_commit(user_thd, wsrep_hton, 1)) + { + case WSREP_TRX_OK: + break; + case WSREP_TRX_SIZE_EXCEEDED: + case WSREP_TRX_CERT_FAIL: + case WSREP_TRX_ERROR: + DBUG_RETURN(1); + } + + if (binlog_hton->commit(binlog_hton, user_thd, 1)) + DBUG_RETURN(1); + wsrep_post_commit(user_thd, TRUE); +#endif /* WITH_WSREP */ /* Source table is not in InnoDB format: no need to re-acquire locks on it. */ @@ -7499,6 +8043,21 @@ no_commit: /* We will need an IX lock on the destination table. */ prebuilt->sql_stat_start = TRUE; } else { +#ifdef WITH_WSREP + switch (wsrep_run_wsrep_commit(user_thd, wsrep_hton, 1)) + { + case WSREP_TRX_OK: + break; + case WSREP_TRX_SIZE_EXCEEDED: + case WSREP_TRX_CERT_FAIL: + case WSREP_TRX_ERROR: + DBUG_RETURN(1); + } + + if (binlog_hton->commit(binlog_hton, user_thd, 1)) + DBUG_RETURN(1); + wsrep_post_commit(user_thd, TRUE); +#endif /* WITH_WSREP */ /* Ensure that there are no other table locks than LOCK_IX and LOCK_AUTO_INC on the destination table. */ @@ -7528,6 +8087,10 @@ no_commit: innobase_get_auto_increment(). */ prebuilt->autoinc_error = DB_SUCCESS; +#ifdef WITH_WSREP + auto_inc_inserted= (table->next_number_field->val_int() == 0); +#endif + if ((error_result = update_auto_increment())) { /* We don't want to mask autoinc overflow errors. */ @@ -7615,6 +8178,32 @@ no_commit: case SQLCOM_REPLACE_SELECT: goto set_max_autoinc; +#ifdef WITH_WSREP + /* workaround for LP bug #355000, retrying the insert */ + case SQLCOM_INSERT: + if (wsrep_on(current_thd) && + auto_inc_inserted && + wsrep_drupal_282555_workaround && + wsrep_thd_retry_counter(current_thd) == 0 && + !thd_test_options(current_thd, + OPTION_NOT_AUTOCOMMIT | + OPTION_BEGIN)) { + WSREP_DEBUG( + "retrying insert: %s", + (*wsrep_thd_query(current_thd)) ? + wsrep_thd_query(current_thd) : + (char *)"void"); + error= DB_SUCCESS; + wsrep_thd_set_conflict_state( + current_thd, MUST_ABORT); + innobase_srv_conc_exit_innodb(prebuilt->trx); + /* jump straight to func exit over + * later wsrep hooks */ + goto func_exit; + } + break; +#endif /* WITH_WSREP */ + default: break; } @@ -7674,6 +8263,21 @@ report_error: prebuilt->table->flags, user_thd); +#ifdef WITH_WSREP + if (!error_result && wsrep_thd_exec_mode(user_thd) == LOCAL_STATE && + wsrep_on(user_thd) && !wsrep_consistency_check(user_thd) && + (sql_command != SQLCOM_LOAD || + thd_binlog_format(user_thd) == BINLOG_FORMAT_ROW)) { + + if (wsrep_append_keys(user_thd, false, record, NULL)) { + DBUG_PRINT("wsrep", ("row key failed")); + error_result = HA_ERR_INTERNAL_ERROR; + goto wsrep_error; + } + } +wsrep_error: +#endif /* WITH_WSREP */ + if (error_result == HA_FTS_INVALID_DOCID) { my_error(HA_FTS_INVALID_DOCID, MYF(0)); } @@ -7963,6 +8567,87 @@ calc_row_difference( return(DB_SUCCESS); } +#ifdef WITH_WSREP +static +int +wsrep_calc_row_hash( +/*================*/ + byte* digest, /*!< in/out: md5 sum */ + const uchar* row, /*!< in: row in MySQL format */ + TABLE* table, /*!< in: table in MySQL data + dictionary */ + row_prebuilt_t* prebuilt, /*!< in: InnoDB prebuilt struct */ + THD* thd) /*!< in: user thread */ +{ + Field* field; + enum_field_types field_mysql_type; + uint n_fields; + ulint len; + const byte* ptr; + ulint col_type; + uint i; + + void *ctx = wsrep_md5_init(); + + n_fields = table->s->fields; + + for (i = 0; i < n_fields; i++) { + byte null_byte=0; + byte true_byte=1; + + field = table->field[i]; + + ptr = (const byte*) row + get_field_offset(table, field); + len = field->pack_length(); + + field_mysql_type = field->type(); + + col_type = prebuilt->table->cols[i].mtype; + + switch (col_type) { + + case DATA_BLOB: + ptr = row_mysql_read_blob_ref(&len, ptr, len); + + break; + + case DATA_VARCHAR: + case DATA_BINARY: + case DATA_VARMYSQL: + if (field_mysql_type == MYSQL_TYPE_VARCHAR) { + /* This is a >= 5.0.3 type true VARCHAR where + the real payload data length is stored in + 1 or 2 bytes */ + + ptr = row_mysql_read_true_varchar( + &len, ptr, + (ulint) + (((Field_varstring*)field)->length_bytes)); + + } + + break; + default: + ; + } + /* + if (field->null_ptr && + field_in_record_is_null(table, field, (char*) row)) { + */ + + if (field->is_null_in_record(row)) { + wsrep_md5_update(ctx, (char*)&null_byte, 1); + } else { + wsrep_md5_update(ctx, (char*)&true_byte, 1); + wsrep_md5_update(ctx, (char*)ptr, len); + } + } + + wsrep_compute_md5_hash((char*)digest, ctx); + + return(0); +} +#endif /* WITH_WSREP */ /**********************************************************************//** Updates a row given as a parameter to a new value. Note that we are given whole rows, not just the fields which are updated: this incurs some @@ -8109,6 +8794,23 @@ func_exit: innobase_active_small(); +#ifdef WITH_WSREP + if (error == DB_SUCCESS && + wsrep_thd_exec_mode(user_thd) == LOCAL_STATE && + wsrep_on(user_thd)) { + + DBUG_PRINT("wsrep", ("update row key")); + + if (wsrep_append_keys(user_thd, false, old_row, new_row)) { + WSREP_DEBUG("WSREP: UPDATE_ROW_KEY FAILED"); + DBUG_PRINT("wsrep", ("row key failed")); + err = HA_ERR_INTERNAL_ERROR; + goto wsrep_error; + } + } +wsrep_error: +#endif /* WITH_WSREP */ + if (UNIV_UNLIKELY(share->ib_table->is_corrupt)) { DBUG_RETURN(HA_ERR_CRASHED); } @@ -8171,6 +8873,19 @@ ha_innobase::delete_row( innobase_active_small(); +#ifdef WITH_WSREP + if (error == DB_SUCCESS && wsrep_thd_exec_mode(user_thd) == LOCAL_STATE && + wsrep_on(user_thd)) { + + if (wsrep_append_keys(user_thd, false, record, NULL)) { + DBUG_PRINT("wsrep", ("delete fail")); + error = DB_ERROR; + goto wsrep_error; + } + } +wsrep_error: +#endif /* WITH_WSREP */ + if (UNIV_UNLIKELY(share && share->ib_table && share->ib_table->is_corrupt)) { DBUG_RETURN(HA_ERR_CRASHED); @@ -9360,6 +10075,394 @@ ha_innobase::ft_end() rnd_end(); } +#ifdef WITH_WSREP +extern dict_index_t* +wsrep_dict_foreign_find_index( + dict_table_t* table, + const char** col_names, + const char** columns, + ulint n_cols, + dict_index_t* types_idx, + ibool check_charsets, + ulint check_null); + + +extern dberr_t +wsrep_append_foreign_key( +/*===========================*/ + trx_t* trx, /*!< in: trx */ + dict_foreign_t* foreign, /*!< in: foreign key constraint */ + const rec_t* rec, /*!mysql_thd; + ulint rcode = DB_SUCCESS; + char cache_key[513] = {'\0'}; + int cache_key_len; + bool const copy = true; + + if (!wsrep_on(trx->mysql_thd) || + wsrep_thd_exec_mode(thd) != LOCAL_STATE) + return DB_SUCCESS; + + if (!thd || !foreign || + (!foreign->referenced_table && !foreign->foreign_table)) + { + WSREP_INFO("FK: %s missing in: %s", + (!thd) ? "thread" : + ((!foreign) ? "constraint" : + ((!foreign->referenced_table) ? + "referenced table" : "foreign table")), + (thd && wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + return DB_ERROR; + } + + if ( !((referenced) ? + foreign->referenced_table : foreign->foreign_table)) + { + WSREP_DEBUG("pulling %s table into cache", + (referenced) ? "referenced" : "foreign"); + mutex_enter(&(dict_sys->mutex)); + if (referenced) + { + foreign->referenced_table = + dict_table_get_low( + foreign->referenced_table_name_lookup); + if (foreign->referenced_table) + { + foreign->referenced_index = + wsrep_dict_foreign_find_index( + foreign->referenced_table, NULL, + foreign->referenced_col_names, + foreign->n_fields, + foreign->foreign_index, + TRUE, FALSE); + } + } + else + { + foreign->foreign_table = + dict_table_get_low( + foreign->foreign_table_name_lookup); + if (foreign->foreign_table) + { + foreign->foreign_index = + wsrep_dict_foreign_find_index( + foreign->foreign_table, NULL, + foreign->foreign_col_names, + foreign->n_fields, + foreign->referenced_index, + TRUE, FALSE); + } + } + mutex_exit(&(dict_sys->mutex)); + } + + if ( !((referenced) ? + foreign->referenced_table : foreign->foreign_table)) + { + WSREP_WARN("FK: %s missing in query: %s", + (!foreign->referenced_table) ? + "referenced table" : "foreign table", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + return DB_ERROR; + } + byte key[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + ulint len = WSREP_MAX_SUPPORTED_KEY_LENGTH; + + dict_index_t *idx_target = (referenced) ? + foreign->referenced_index : index; + dict_index_t *idx = (referenced) ? + UT_LIST_GET_FIRST(foreign->referenced_table->indexes) : + UT_LIST_GET_FIRST(foreign->foreign_table->indexes); + int i = 0; + while (idx != NULL && idx != idx_target) { + if (innobase_strcasecmp (idx->name, innobase_index_reserve_name) != 0) { + i++; + } + idx = UT_LIST_GET_NEXT(indexes, idx); + } + ut_a(idx); + key[0] = (char)i; + + rcode = wsrep_rec_get_foreign_key( + &key[1], &len, rec, index, idx, + wsrep_protocol_version > 1); + if (rcode != DB_SUCCESS) { + WSREP_ERROR( + "FK key set failed: %lu (%lu %lu), index: %s %s, %s", + rcode, referenced, shared, + (index && index->name) ? index->name : + "void index", + (index && index->table_name) ? index->table_name : + "void table", + wsrep_thd_query(thd)); + return DB_ERROR; + } + strncpy(cache_key, + (wsrep_protocol_version > 1) ? + ((referenced) ? + foreign->referenced_table->name : + foreign->foreign_table->name) : + foreign->foreign_table->name, sizeof(cache_key) - 1); + cache_key_len = strlen(cache_key); +#ifdef WSREP_DEBUG_PRINT + ulint j; + fprintf(stderr, "FK parent key, table: %s %s len: %lu ", + cache_key, (shared) ? "shared" : "exclusive", len+1); + for (j=0; jreferenced_table->name, + foreign->foreign_table->name); + } + + wsrep_buf_t wkey_part[3]; + wsrep_key_t wkey = {wkey_part, 3}; + if (!wsrep_prepare_key_for_innodb( + (const uchar*)cache_key, + cache_key_len + 1, + (const uchar*)key, len+1, + wkey_part, + (size_t*)&wkey.key_parts_num)) { + WSREP_WARN("key prepare failed for cascaded FK: %s", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + return DB_ERROR; + } + rcode = (int)wsrep->append_key( + wsrep, + wsrep_ws_handle(thd, trx), + &wkey, + 1, + shared ? WSREP_KEY_SHARED : WSREP_KEY_EXCLUSIVE, + copy); + if (rcode) { + DBUG_PRINT("wsrep", ("row key failed: %lu", rcode)); + WSREP_ERROR("Appending cascaded fk row key failed: %s, %lu", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void", rcode); + return DB_ERROR; + } + + return DB_SUCCESS; +} + +static int +wsrep_append_key( +/*==================*/ + THD *thd, + trx_t *trx, + TABLE_SHARE *table_share, + TABLE *table, + const char* key, + uint16_t key_len, + bool shared +) +{ + DBUG_ENTER("wsrep_append_key"); + bool const copy = true; +#ifdef WSREP_DEBUG_PRINT + fprintf(stderr, "%s conn %ld, trx %lu, keylen %d, table %s ", + (shared) ? "Shared" : "Exclusive", + wsrep_thd_thread_id(thd), (long long)trx->id, key_len, + table_share->table_name.str); + for (int i=0; itable_cache_key.str, + table_share->table_cache_key.length, + (const uchar*)key, key_len, + wkey_part, + (size_t*)&wkey.key_parts_num)) { + WSREP_WARN("key prepare failed for: %s", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + } + + int rcode = (int)wsrep->append_key( + wsrep, + wsrep_ws_handle(thd, trx), + &wkey, + 1, + shared ? WSREP_KEY_SHARED : WSREP_KEY_EXCLUSIVE, + copy); + if (rcode) { + DBUG_PRINT("wsrep", ("row key failed: %d", rcode)); + WSREP_WARN("Appending row key failed: %s, %d", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void", rcode); + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + } + DBUG_RETURN(0); +} + +extern void compute_md5_hash(char *digest, const char *buf, int len); +#define MD5_HASH compute_md5_hash + +int +ha_innobase::wsrep_append_keys( +/*==================*/ + THD *thd, + bool shared, + const uchar* record0, /* in: row in MySQL format */ + const uchar* record1) /* in: row in MySQL format */ +{ + int rcode; + DBUG_ENTER("wsrep_append_keys"); + + bool key_appended = false; + trx_t *trx = thd_to_trx(thd); + + if (table_share && table_share->tmp_table != NO_TMP_TABLE) { + WSREP_DEBUG("skipping tmp table DML: THD: %lu tmp: %d SQL: %s", + wsrep_thd_thread_id(thd), + table_share->tmp_table, + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + DBUG_RETURN(0); + } + + if (wsrep_protocol_version == 0) { + uint len; + char keyval[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + char *key = &keyval[0]; + ibool is_null; + + len = wsrep_store_key_val_for_row( + thd, table, 0, key, WSREP_MAX_SUPPORTED_KEY_LENGTH, + record0, &is_null); + + if (!is_null) { + rcode = wsrep_append_key( + thd, trx, table_share, table, keyval, + len, shared); + if (rcode) DBUG_RETURN(rcode); + } + else + { + WSREP_DEBUG("NULL key skipped (proto 0): %s", + wsrep_thd_query(thd)); + } + } else { + ut_a(table->s->keys <= 256); + uint i; + bool hasPK= false; + + for (i=0; is->keys; ++i) { + KEY* key_info = table->key_info + i; + if (key_info->flags & HA_NOSAME) { + hasPK = true; + } + } + + for (i=0; is->keys; ++i) { + uint len; + char keyval0[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + char keyval1[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + char* key0 = &keyval0[1]; + char* key1 = &keyval1[1]; + KEY* key_info = table->key_info + i; + ibool is_null; + + dict_index_t* idx = innobase_get_index(i); + dict_table_t* tab = (idx) ? idx->table : NULL; + + keyval0[0] = (char)i; + keyval1[0] = (char)i; + + if (!tab) { + WSREP_WARN("MySQL-InnoDB key mismatch %s %s", + table->s->table_name.str, + key_info->name); + } + /* !hasPK == table with no PK, must append all non-unique keys */ + if (!hasPK || key_info->flags & HA_NOSAME || + ((tab && + dict_table_get_referenced_constraint(tab, idx)) || + (!tab && referenced_by_foreign_key()))) { + + len = wsrep_store_key_val_for_row( + thd, table, i, key0, + WSREP_MAX_SUPPORTED_KEY_LENGTH, + record0, &is_null); + if (!is_null) { + rcode = wsrep_append_key( + thd, trx, table_share, table, + keyval0, len+1, shared); + if (rcode) DBUG_RETURN(rcode); + + if (key_info->flags & HA_NOSAME || shared) + key_appended = true; + } + else + { + WSREP_DEBUG("NULL key skipped: %s", + wsrep_thd_query(thd)); + } + if (record1) { + len = wsrep_store_key_val_for_row( + thd, table, i, key1, + WSREP_MAX_SUPPORTED_KEY_LENGTH, + record1, &is_null); + if (!is_null && memcmp(key0, key1, len)) { + rcode = wsrep_append_key( + thd, trx, table_share, + table, + keyval1, len+1, shared); + if (rcode) DBUG_RETURN(rcode); + } + } + } + } + } + + /* if no PK, calculate hash of full row, to be the key value */ + if (!key_appended && wsrep_certify_nonPK) { + uchar digest[16]; + int rcode; + + wsrep_calc_row_hash(digest, record0, table, prebuilt, thd); + if ((rcode = wsrep_append_key(thd, trx, table_share, table, + (const char*) digest, 16, + shared))) { + DBUG_RETURN(rcode); + } + + if (record1) { + wsrep_calc_row_hash( + digest, record1, table, prebuilt, thd); + if ((rcode = wsrep_append_key(thd, trx, table_share, + table, + (const char*) digest, + 16, shared))) { + DBUG_RETURN(rcode); + } + } + DBUG_RETURN(0); + } + + DBUG_RETURN(0); +} +#endif /* WITH_WSREP */ /*********************************************************************//** Stores a reference to the current row to 'ref' field of the handle. Note @@ -13276,11 +14379,18 @@ ha_innobase::external_lock( /* used by test case */ DBUG_EXECUTE_IF("no_innodb_binlog_errors", skip = true;); if (!skip) { - my_error(ER_BINLOG_STMT_MODE_AND_ROW_ENGINE, MYF(0), - " InnoDB is limited to row-logging when " - "transaction isolation level is " - "READ COMMITTED or READ UNCOMMITTED."); - DBUG_RETURN(HA_ERR_LOGGING_IMPOSSIBLE); +#ifdef WITH_WSREP + if (!wsrep_on(thd) + || wsrep_thd_exec_mode(thd) == LOCAL_STATE) { +#endif /* WITH_WSREP */ + my_error(ER_BINLOG_STMT_MODE_AND_ROW_ENGINE, MYF(0), + " InnoDB is limited to row-logging when " + "transaction isolation level is " + "READ COMMITTED or READ UNCOMMITTED."); + DBUG_RETURN(HA_ERR_LOGGING_IMPOSSIBLE); +#ifdef WITH_WSREP + } +#endif /* WITH_WSREP */ } } @@ -14754,6 +15864,9 @@ innobase_xa_prepare( time, not the current session variable value. Any possible changes to the session variable take effect only in the next transaction */ if (!trx->support_xa) { +#ifdef WITH_WSREP + thd_get_xid(thd, (MYSQL_XID*) &trx->xid); +#endif // WITH_WSREP return(0); } @@ -17155,6 +18268,303 @@ static SHOW_VAR innodb_status_variables_export[]= { static struct st_mysql_storage_engine innobase_storage_engine= { MYSQL_HANDLERTON_INTERFACE_VERSION }; +#ifdef WITH_WSREP +void +wsrep_abort_slave_trx(wsrep_seqno_t bf_seqno, wsrep_seqno_t victim_seqno) +{ + WSREP_ERROR("Trx %lld tries to abort slave trx %lld. This could be " + "caused by:\n\t" + "1) unsupported configuration options combination, please check documentation.\n\t" + "2) a bug in the code.\n\t" + "3) a database corruption.\n Node consistency compromized, " + "need to abort. Restart the node to resync with cluster.", + (long long)bf_seqno, (long long)victim_seqno); + abort(); +} +/*******************************************************************//** +This function is used to kill one transaction in BF. */ + +int +wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, + const trx_t * const bf_trx, + trx_t *victim_trx, ibool signal) +{ + ut_ad(lock_mutex_own()); + ut_ad(trx_mutex_own(victim_trx)); + ut_ad(bf_thd_ptr); + ut_ad(victim_trx); + + DBUG_ENTER("wsrep_innobase_kill_one_trx"); + THD *bf_thd = bf_thd_ptr ? (THD*) bf_thd_ptr : NULL; + THD *thd = (THD *) victim_trx->mysql_thd; + int64_t bf_seqno = (bf_thd) ? wsrep_thd_trx_seqno(bf_thd) : 0; + + if (!thd) { + DBUG_PRINT("wsrep", ("no thd for conflicting lock")); + WSREP_WARN("no THD for trx: %lu", victim_trx->id); + DBUG_RETURN(1); + } + if (!bf_thd) { + DBUG_PRINT("wsrep", ("no BF thd for conflicting lock")); + WSREP_WARN("no BF THD for trx: %lu", (bf_trx) ? bf_trx->id : 0); + DBUG_RETURN(1); + } + + WSREP_LOG_CONFLICT(bf_thd, thd, TRUE); + + WSREP_DEBUG("BF kill (%lu, seqno: %lld), victim: (%lu) trx: %lu", + signal, (long long)bf_seqno, + wsrep_thd_thread_id(thd), + victim_trx->id); + + WSREP_DEBUG("Aborting query: %s", + (thd && wsrep_thd_query(thd)) ? wsrep_thd_query(thd) : "void"); + + wsrep_thd_LOCK(thd); + + if (wsrep_thd_query_state(thd) == QUERY_EXITING) { + WSREP_DEBUG("kill trx EXITING for %lu", victim_trx->id); + wsrep_thd_UNLOCK(thd); + DBUG_RETURN(0); + } + if(wsrep_thd_exec_mode(thd) != LOCAL_STATE) { + WSREP_DEBUG("withdraw for BF trx: %lu, state: %d", + victim_trx->id, + wsrep_thd_conflict_state(thd)); + } + + switch (wsrep_thd_conflict_state(thd)) { + case NO_CONFLICT: + wsrep_thd_set_conflict_state(thd, MUST_ABORT); + break; + case MUST_ABORT: + WSREP_DEBUG("victim %lu in MUST ABORT state", + victim_trx->id); + wsrep_thd_UNLOCK(thd); + wsrep_thd_awake(thd, signal); + DBUG_RETURN(0); + break; + case ABORTED: + case ABORTING: // fall through + default: + WSREP_DEBUG("victim %lu in state %d", + victim_trx->id, wsrep_thd_conflict_state(thd)); + wsrep_thd_UNLOCK(thd); + DBUG_RETURN(0); + break; + } + + switch (wsrep_thd_query_state(thd)) { + case QUERY_COMMITTING: + enum wsrep_status rcode; + + WSREP_DEBUG("kill query for: %ld", + wsrep_thd_thread_id(thd)); + WSREP_DEBUG("kill trx QUERY_COMMITTING for %lu", + victim_trx->id); + + if (wsrep_thd_exec_mode(thd) == REPL_RECV) { + wsrep_abort_slave_trx(bf_seqno, + wsrep_thd_trx_seqno(thd)); + } else { + rcode = wsrep->abort_pre_commit( + wsrep, bf_seqno, + (wsrep_trx_id_t)victim_trx->id + ); + + switch (rcode) { + case WSREP_WARNING: + WSREP_DEBUG("cancel commit warning: %lu", + victim_trx->id); + wsrep_thd_UNLOCK(thd); + wsrep_thd_awake(thd, signal); + DBUG_RETURN(1); + break; + case WSREP_OK: + break; + default: + WSREP_ERROR( + "cancel commit bad exit: %d %lu", + rcode, + victim_trx->id); + /* unable to interrupt, must abort */ + /* note: kill_mysql() will block, if we cannot. + * kill the lock holder first. + */ + abort(); + break; + } + } + wsrep_thd_UNLOCK(thd); + wsrep_thd_awake(thd, signal); + break; + case QUERY_EXEC: + /* it is possible that victim trx is itself waiting for some + * other lock. We need to cancel this waiting + */ + WSREP_DEBUG("kill trx QUERY_EXEC for %lu", victim_trx->id); + + victim_trx->lock.was_chosen_as_deadlock_victim= TRUE; + if (victim_trx->lock.wait_lock) { + WSREP_DEBUG("victim has wait flag: %ld", + wsrep_thd_thread_id(thd)); + lock_t* wait_lock = victim_trx->lock.wait_lock; + if (wait_lock) { + WSREP_DEBUG("canceling wait lock"); + victim_trx->lock.was_chosen_as_deadlock_victim= TRUE; + lock_cancel_waiting_and_release(wait_lock); + } + + wsrep_thd_UNLOCK(thd); + wsrep_thd_awake(thd, signal); + } else { + /* abort currently executing query */ + DBUG_PRINT("wsrep",("sending KILL_QUERY to: %ld", + wsrep_thd_thread_id(thd))); + WSREP_DEBUG("kill query for: %ld", + wsrep_thd_thread_id(thd)); + /* Note that innobase_kill_connection will take lock_mutex + and trx_mutex */ + wsrep_thd_UNLOCK(thd); + wsrep_thd_awake(thd, signal); + + /* for BF thd, we need to prevent him from committing */ + if (wsrep_thd_exec_mode(thd) == REPL_RECV) { + wsrep_abort_slave_trx(bf_seqno, + wsrep_thd_trx_seqno(thd)); + } + } + break; + case QUERY_IDLE: + { + bool skip_abort= false; + wsrep_aborting_thd_t abortees; + + WSREP_DEBUG("kill IDLE for %lu", victim_trx->id); + + if (wsrep_thd_exec_mode(thd) == REPL_RECV) { + WSREP_DEBUG("kill BF IDLE, seqno: %lld", + (long long)wsrep_thd_trx_seqno(thd)); + wsrep_thd_UNLOCK(thd); + wsrep_abort_slave_trx(bf_seqno, + wsrep_thd_trx_seqno(thd)); + DBUG_RETURN(0); + } + /* This will lock thd from proceeding after net_read() */ + wsrep_thd_set_conflict_state(thd, ABORTING); + + mysql_mutex_lock(&LOCK_wsrep_rollback); + + abortees = wsrep_aborting_thd; + while (abortees && !skip_abort) { + /* check if we have a kill message for this already */ + if (abortees->aborting_thd == thd) { + skip_abort = true; + WSREP_WARN("duplicate thd aborter %lu", + wsrep_thd_thread_id(thd)); + } + abortees = abortees->next; + } + if (!skip_abort) { + wsrep_aborting_thd_t aborting = (wsrep_aborting_thd_t) + my_malloc(sizeof(struct wsrep_aborting_thd), + MYF(0)); + aborting->aborting_thd = thd; + aborting->next = wsrep_aborting_thd; + wsrep_aborting_thd = aborting; + DBUG_PRINT("wsrep",("enqueuing trx abort for %lu", + wsrep_thd_thread_id(thd))); + WSREP_DEBUG("enqueuing trx abort for (%lu)", + wsrep_thd_thread_id(thd)); + } + + DBUG_PRINT("wsrep",("signalling wsrep rollbacker")); + WSREP_DEBUG("signaling aborter"); + mysql_cond_signal(&COND_wsrep_rollback); + mysql_mutex_unlock(&LOCK_wsrep_rollback); + wsrep_thd_UNLOCK(thd); + + break; + } + default: + WSREP_WARN("bad wsrep query state: %d", + wsrep_thd_query_state(thd)); + wsrep_thd_UNLOCK(thd); + break; + } + + DBUG_RETURN(0); +} +static int +wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd, + my_bool signal) +{ + DBUG_ENTER("wsrep_innobase_abort_thd"); + trx_t* victim_trx = thd_to_trx(victim_thd); + trx_t* bf_trx = (bf_thd) ? thd_to_trx(bf_thd) : NULL; + WSREP_DEBUG("abort transaction: BF: %s victim: %s", + wsrep_thd_query(bf_thd), + wsrep_thd_query(victim_thd)); + + if (victim_trx) + { + lock_mutex_enter(); + trx_mutex_enter(victim_trx); + int rcode = wsrep_innobase_kill_one_trx(bf_thd, bf_trx, + victim_trx, signal); + trx_mutex_exit(victim_trx); + lock_mutex_exit(); + wsrep_srv_conc_cancel_wait(victim_trx); + + DBUG_RETURN(rcode); + } else { + WSREP_DEBUG("victim does not have transaction"); + wsrep_thd_LOCK(victim_thd); + wsrep_thd_set_conflict_state(victim_thd, MUST_ABORT); + wsrep_thd_UNLOCK(victim_thd); + wsrep_thd_awake(victim_thd, signal); + } + DBUG_RETURN(-1); +} + +static int innobase_wsrep_set_checkpoint(handlerton* hton, const XID* xid) +{ + DBUG_ASSERT(hton == innodb_hton_ptr); + if (wsrep_is_wsrep_xid((const void *)xid)) { + mtr_t mtr; + mtr_start(&mtr); + trx_sysf_t* sys_header = trx_sysf_get(&mtr); + trx_sys_update_wsrep_checkpoint(xid, sys_header, &mtr); + mtr_commit(&mtr); + innobase_flush_logs(hton); + return 0; + } else { + return 1; + } +} + +static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid) +{ + DBUG_ASSERT(hton == innodb_hton_ptr); + trx_sys_read_wsrep_checkpoint(xid); + return 0; +} + +static void +wsrep_fake_trx_id( +/*==================*/ + handlerton *hton, + THD *thd) /*!< in: user thread handle */ +{ + mutex_enter(&trx_sys->mutex); + trx_id_t trx_id = trx_sys_get_new_trx_id(); + mutex_exit(&trx_sys->mutex); + + (void *)wsrep_ws_handle_for_trx(wsrep_thd_ws_handle(thd), trx_id); +} + +#endif /* WITH_WSREP */ + /* plugin options */ static MYSQL_SYSVAR_ENUM(checksum_algorithm, srv_checksum_algorithm, @@ -18092,6 +19502,40 @@ static MYSQL_SYSVAR_BOOL(disable_background_merge, NULL, NULL, FALSE); #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ +#ifdef WITH_INNODB_DISALLOW_WRITES +/******************************************************* + * innobase_disallow_writes variable definition * + *******************************************************/ + +/* Must always init to FALSE. */ +static my_bool innobase_disallow_writes = FALSE; + +/************************************************************************** +An "update" method for innobase_disallow_writes variable. */ +static +void +innobase_disallow_writes_update( +/*============================*/ + THD* thd, /* in: thread handle */ + st_mysql_sys_var* var, /* in: pointer to system + variable */ + void* var_ptr, /* out: pointer to dynamic + variable */ + const void* save) /* in: temporary storage */ +{ + *(my_bool*)var_ptr = *(my_bool*)save; + ut_a(srv_allow_writes_event); + if (*(my_bool*)var_ptr) + os_event_reset(srv_allow_writes_event); + else + os_event_set(srv_allow_writes_event); +} + +static MYSQL_SYSVAR_BOOL(disallow_writes, innobase_disallow_writes, + PLUGIN_VAR_NOCMDOPT, + "Tell InnoDB to stop any writes to disk", + NULL, innobase_disallow_writes_update, FALSE); +#endif /* WITH_INNODB_DISALLOW_WRITES */ static MYSQL_SYSVAR_BOOL(random_read_ahead, srv_random_read_ahead, PLUGIN_VAR_NOCMDARG, "Whether to use read ahead for random access within an extent.", @@ -18403,6 +19847,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(change_buffering_debug), MYSQL_SYSVAR(disable_background_merge), #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ +#ifdef WITH_INNODB_DISALLOW_WRITES + MYSQL_SYSVAR(disallow_writes), +#endif /* WITH_INNODB_DISALLOW_WRITES */ MYSQL_SYSVAR(random_read_ahead), MYSQL_SYSVAR(read_ahead_threshold), MYSQL_SYSVAR(read_only), diff --git a/storage/xtradb/handler/ha_innodb.h b/storage/xtradb/handler/ha_innodb.h index b4df711356c..ff4ab88335a 100644 --- a/storage/xtradb/handler/ha_innodb.h +++ b/storage/xtradb/handler/ha_innodb.h @@ -119,6 +119,10 @@ class ha_innobase: public handler void innobase_initialize_autoinc(); dict_index_t* innobase_get_index(uint keynr); +#ifdef WITH_WSREP + int wsrep_append_keys(THD *thd, bool shared, + const uchar* record0, const uchar* record1); +#endif /* Init values for the class: */ public: ha_innobase(handlerton *hton, TABLE_SHARE *table_arg); @@ -472,6 +476,40 @@ __attribute__((nonnull)); extern void mysql_bin_log_commit_pos(THD *thd, ulonglong *out_pos, const char **out_file); struct trx_t; +#ifdef WITH_WSREP +#include +//extern "C" int wsrep_trx_order_before(void *thd1, void *thd2); + +extern "C" bool wsrep_thd_is_wsrep_on(THD *thd); + +extern "C" enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd); +extern "C" enum wsrep_conflict_state wsrep_thd_conflict_state(THD *thd); +extern "C" enum wsrep_query_state wsrep_thd_query_state(THD *thd); +extern "C" const char * wsrep_thd_exec_mode_str(THD *thd); +extern "C" const char * wsrep_thd_conflict_state_str(THD *thd); +extern "C" const char * wsrep_thd_query_state_str(THD *thd); +extern "C" wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd); + +extern "C" void wsrep_thd_set_exec_mode(THD *thd, enum wsrep_exec_mode mode); +extern "C" void wsrep_thd_set_query_state( + THD *thd, enum wsrep_query_state state); +extern "C" void wsrep_thd_set_conflict_state( + THD *thd, enum wsrep_conflict_state state); + +extern "C" void wsrep_thd_set_trx_to_replay(THD *thd, uint64 trx_id); + +extern "C"void wsrep_thd_LOCK(THD *thd); +extern "C"void wsrep_thd_UNLOCK(THD *thd); +extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd); +extern "C" time_t wsrep_thd_query_start(THD *thd); +extern "C" my_thread_id wsrep_thd_thread_id(THD *thd); +extern "C" int64_t wsrep_thd_trx_seqno(THD *thd); +extern "C" query_id_t wsrep_thd_query_id(THD *thd); +extern "C" char * wsrep_thd_query(THD *thd); +extern "C" query_id_t wsrep_thd_wsrep_last_query_id(THD *thd); +extern "C" void wsrep_thd_set_wsrep_last_query_id(THD *thd, query_id_t id); +extern "C" void wsrep_thd_awake(THD* thd, my_bool signal); +#endif extern const struct _ft_vft ft_vft_result; @@ -509,6 +547,9 @@ innobase_index_name_is_reserved( __attribute__((nonnull, warn_unused_result)); /*****************************************************************//** +#ifdef WITH_WSREP +extern "C" int wsrep_trx_is_aborting(void *thd_ptr); +#endif Determines InnoDB table flags. @retval true if successful, false if error */ UNIV_INTERN diff --git a/storage/xtradb/handler/handler0alter.cc b/storage/xtradb/handler/handler0alter.cc index 34048e7c987..2cd0500007a 100644 --- a/storage/xtradb/handler/handler0alter.cc +++ b/storage/xtradb/handler/handler0alter.cc @@ -49,6 +49,10 @@ Smart ALTER TABLE #include "pars0pars.h" #include "row0sel.h" #include "ha_innodb.h" +#ifdef WITH_WSREP +//#include "wsrep_api.h" +#include // PROCESS_ACL +#endif /** Operations for creating secondary indexes (no rebuild needed) */ static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_ONLINE_CREATE diff --git a/storage/xtradb/include/dict0mem.h b/storage/xtradb/include/dict0mem.h index a347a75ea42..93fe2efa830 100644 --- a/storage/xtradb/include/dict0mem.h +++ b/storage/xtradb/include/dict0mem.h @@ -527,6 +527,9 @@ be REC_VERSION_56_MAX_INDEX_COL_LEN (3072) bytes */ /** Defines the maximum fixed length column size */ #define DICT_MAX_FIXED_COL_LEN DICT_ANTELOPE_MAX_INDEX_COL_LEN +#ifdef WITH_WSREP +#define WSREP_MAX_SUPPORTED_KEY_LENGTH 3500 +#endif /* WITH_WSREP */ /** Data structure for a field in an index */ struct dict_field_t{ diff --git a/storage/xtradb/include/ha_prototypes.h b/storage/xtradb/include/ha_prototypes.h index 66a96282b69..4ebaee3c89e 100644 --- a/storage/xtradb/include/ha_prototypes.h +++ b/storage/xtradb/include/ha_prototypes.h @@ -285,6 +285,23 @@ innobase_casedn_str( /*================*/ char* a); /*!< in/out: string to put in lower case */ +#ifdef WITH_WSREP +UNIV_INTERN +int +wsrep_innobase_kill_one_trx(void *thd_ptr, + const trx_t *bf_trx, trx_t *victim_trx, ibool signal); +my_bool wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe); +int wsrep_thd_conflict_state(void *thd_ptr, my_bool sync); +my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync); +my_bool wsrep_thd_is_wsrep(void *thd_ptr); +int wsrep_trx_order_before(void *thd1, void *thd2); +int wsrep_innobase_mysql_sort(int mysql_type, uint charset_number, + unsigned char* str, unsigned int str_length, + unsigned int buf_length); +int +wsrep_on(void *thd_ptr); +extern "C" int wsrep_is_wsrep_xid(const void*); +#endif /* WITH_WSREP */ /**********************************************************************//** Determines the connection character set. @return connection character set */ diff --git a/storage/xtradb/include/hash0hash.h b/storage/xtradb/include/hash0hash.h index a6fe4e680a1..68d3c6ace4e 100644 --- a/storage/xtradb/include/hash0hash.h +++ b/storage/xtradb/include/hash0hash.h @@ -144,6 +144,33 @@ do {\ }\ } while (0) +#ifdef WITH_WSREP +/*******************************************************************//** +Inserts a struct to the head of hash table. */ + +#define HASH_PREPEND(TYPE, NAME, TABLE, FOLD, DATA) \ +do { \ + hash_cell_t* cell3333; \ + TYPE* struct3333; \ + \ + HASH_ASSERT_OWN(TABLE, FOLD) \ + \ + (DATA)->NAME = NULL; \ + \ + cell3333 = hash_get_nth_cell(TABLE, hash_calc_hash(FOLD, TABLE));\ + \ + if (cell3333->node == NULL) { \ + cell3333->node = DATA; \ + DATA->NAME = NULL; \ + } else { \ + struct3333 = (TYPE*) cell3333->node; \ + \ + DATA->NAME = struct3333; \ + \ + cell3333->node = DATA; \ + } \ +} while (0) +#endif /*WITH_WSREP */ #ifdef UNIV_HASH_DEBUG # define HASH_ASSERT_VALID(DATA) ut_a((void*) (DATA) != (void*) -1) # define HASH_INVALIDATE(DATA, NAME) *(void**) (&DATA->NAME) = (void*) -1 diff --git a/storage/xtradb/include/rem0rec.h b/storage/xtradb/include/rem0rec.h index 8e7d5ff2d48..238cb04e1f8 100644 --- a/storage/xtradb/include/rem0rec.h +++ b/storage/xtradb/include/rem0rec.h @@ -981,6 +981,15 @@ are given in one byte (resp. two byte) format. */ two upmost bits in a two byte offset for special purposes */ #define REC_MAX_DATA_SIZE (16 * 1024) +#ifdef WITH_WSREP +int wsrep_rec_get_foreign_key( + byte *buf, /* out: extracted key */ + ulint *buf_len, /* in/out: length of buf */ + const rec_t* rec, /* in: physical record */ + dict_index_t* index_for, /* in: index for foreign table */ + dict_index_t* index_ref, /* in: index for referenced table */ + ibool new_protocol); /* in: protocol > 1 */ +#endif /* WITH_WSREP */ #ifndef UNIV_NONINL #include "rem0rec.ic" #endif diff --git a/storage/xtradb/include/srv0srv.h b/storage/xtradb/include/srv0srv.h index a02c8a96e1a..a54198f4e00 100644 --- a/storage/xtradb/include/srv0srv.h +++ b/storage/xtradb/include/srv0srv.h @@ -323,6 +323,10 @@ extern uint srv_flush_log_at_timeout; extern char srv_use_global_flush_log_at_trx_commit; extern char srv_adaptive_flushing; +#ifdef WITH_INNODB_DISALLOW_WRITES +/* When this event is reset we do not allow any file writes to take place. */ +extern os_event_t srv_allow_writes_event; +#endif /* WITH_INNODB_DISALLOW_WRITES */ /* If this flag is TRUE, then we will load the indexes' (and tables') metadata even if they are marked as "corrupted". Mostly it is for DBA to process corrupted index and table */ @@ -1167,4 +1171,13 @@ struct srv_slot_t{ # define srv_file_per_table 1 #endif /* !UNIV_HOTBACKUP */ +#ifdef WITH_WSREP +UNIV_INTERN +void +wsrep_srv_conc_cancel_wait( +/*==================*/ + trx_t* trx); /*!< in: transaction object associated with the + thread */ +#endif /* WITH_WSREP */ + #endif diff --git a/storage/xtradb/include/sync0sync.ic b/storage/xtradb/include/sync0sync.ic index c3529af5262..a302e1473a5 100644 --- a/storage/xtradb/include/sync0sync.ic +++ b/storage/xtradb/include/sync0sync.ic @@ -255,7 +255,10 @@ mutex_enter_func( ulint line) /*!< in: line where locked */ { ut_ad(mutex_validate(mutex)); +#ifndef WITH_WSREP + /* this cannot be be granted when BF trx kills a trx in lock wait state */ ut_ad(!mutex_own(mutex)); +#endif /* WITH_WSREP */ /* Note that we do not peek at the value of lock_word before trying the atomic test_and_set; we could peek, and possibly save time. */ diff --git a/storage/xtradb/include/trx0sys.h b/storage/xtradb/include/trx0sys.h index 7b97c6e99cd..7892fdd0bf1 100644 --- a/storage/xtradb/include/trx0sys.h +++ b/storage/xtradb/include/trx0sys.h @@ -42,6 +42,9 @@ Created 3/26/1996 Heikki Tuuri #include "read0types.h" #include "page0types.h" #include "ut0bh.h" +#ifdef WITH_WSREP +#include "trx0xa.h" +#endif /* WITH_WSREP */ typedef UT_LIST_BASE_NODE_T(trx_t) trx_list_t; @@ -314,6 +317,9 @@ trx_sys_update_mysql_binlog_offset( ib_int64_t offset, /*!< in: position in that log file */ ulint field, /*!< in: offset of the MySQL log info field in the trx sys header */ +#ifdef WITH_WSREP + trx_sysf_t* sys_header, /*!< in: trx sys header */ +#endif /* WITH_WSREP */ mtr_t* mtr); /*!< in: mtr */ /*****************************************************************//** Prints to stderr the MySQL binlog offset info in the trx system header if @@ -322,6 +328,19 @@ UNIV_INTERN void trx_sys_print_mysql_binlog_offset(void); /*===================================*/ +#ifdef WITH_WSREP +/** Update WSREP checkpoint XID in sys header. */ +void +trx_sys_update_wsrep_checkpoint( + const XID* xid, /*!< in: WSREP XID */ + trx_sysf_t* sys_header, /*!< in: sys_header */ + mtr_t* mtr); /*!< in: mtr */ + +void +/** Read WSREP checkpoint XID from sys header. */ +trx_sys_read_wsrep_checkpoint( + XID* xid); /*!< out: WSREP XID */ +#endif /* WITH_WSREP */ /*****************************************************************//** Prints to stderr the MySQL master log offset info in the trx system header if the magic number shows it valid. */ @@ -550,6 +569,20 @@ this contains the same fields as TRX_SYS_MYSQL_LOG_INFO below */ within that file */ #define TRX_SYS_MYSQL_LOG_NAME 12 /*!< MySQL log file name */ +#ifdef WITH_WSREP +/* The offset to WSREP XID headers */ +#define TRX_SYS_WSREP_XID_INFO (UNIV_PAGE_SIZE - 3500) +#define TRX_SYS_WSREP_XID_MAGIC_N_FLD 0 +#define TRX_SYS_WSREP_XID_MAGIC_N 0x77737265 + +/* XID field: formatID, gtrid_len, bqual_len, xid_data */ +#define TRX_SYS_WSREP_XID_LEN (4 + 4 + 4 + XIDDATASIZE) +#define TRX_SYS_WSREP_XID_FORMAT 4 +#define TRX_SYS_WSREP_XID_GTRID_LEN 8 +#define TRX_SYS_WSREP_XID_BQUAL_LEN 12 +#define TRX_SYS_WSREP_XID_DATA 16 +#endif /* WITH_WSREP*/ + /** Doublewrite buffer */ /* @{ */ /** The offset of the doublewrite buffer header on the trx system header page */ diff --git a/storage/xtradb/include/trx0sys.ic b/storage/xtradb/include/trx0sys.ic index 699148cff6d..6024c1dc94e 100644 --- a/storage/xtradb/include/trx0sys.ic +++ b/storage/xtradb/include/trx0sys.ic @@ -474,7 +474,10 @@ trx_id_t trx_sys_get_new_trx_id(void) /*========================*/ { +#ifndef WITH_WSREP + /* wsrep_fake_trx_id violates this assert */ ut_ad(mutex_own(&trx_sys->mutex)); +#endif /* WITH_WSREP */ /* VERY important: after the database is started, max_trx_id value is divisible by TRX_SYS_TRX_ID_WRITE_MARGIN, and the following if diff --git a/storage/xtradb/include/trx0trx.h b/storage/xtradb/include/trx0trx.h index aaa74724a14..be13c48fdfc 100644 --- a/storage/xtradb/include/trx0trx.h +++ b/storage/xtradb/include/trx0trx.h @@ -1031,6 +1031,9 @@ struct trx_t{ /*------------------------------*/ char detailed_error[256]; /*!< detailed error message for last error, or empty. */ +#ifdef WITH_WSREP + os_event_t wsrep_event; /* event waited for in srv_conc_slot */ +#endif /* WITH_WSREP */ /*------------------------------*/ ulint io_reads; ib_uint64_t io_read; diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc index 4f9395e27d8..8f7724daad9 100644 --- a/storage/xtradb/lock/lock0lock.cc +++ b/storage/xtradb/lock/lock0lock.cc @@ -50,6 +50,11 @@ Created 5/7/1996 Heikki Tuuri #include "dict0boot.h" #include +#ifdef WITH_WSREP +extern my_bool wsrep_debug; +extern my_bool wsrep_log_conflicts; +#include "ha_prototypes.h" +#endif /* Restricts the length of search we will do in the waits-for graph of transactions */ #define LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK 1000000 @@ -946,6 +951,9 @@ UNIV_INLINE ibool lock_rec_has_to_wait( /*=================*/ +#ifdef WITH_WSREP + ibool for_locking, /*!< is caller locking or releasing */ +#endif /* WITH_WSREP */ const trx_t* trx, /*!< in: trx of new lock */ ulint type_mode,/*!< in: precise mode of the new lock to set: LOCK_S or LOCK_X, possibly @@ -1016,6 +1024,50 @@ lock_rec_has_to_wait( return(FALSE); } +#ifdef WITH_WSREP + /* if BF thread is locking and has conflict with another BF + thread, we need to look at trx ordering and lock types */ + if (for_locking && + wsrep_thd_is_BF(trx->mysql_thd, FALSE) && + wsrep_thd_is_BF(lock2->trx->mysql_thd, TRUE)) { + + if (wsrep_debug) { + fprintf(stderr, "\n BF-BF lock conflict \n"); + lock_rec_print(stderr, lock2); + } + + if (wsrep_trx_order_before(trx->mysql_thd, + lock2->trx->mysql_thd) && + (type_mode & LOCK_MODE_MASK) == LOCK_X && + (lock2->type_mode & LOCK_MODE_MASK) == LOCK_X) + { + /* exclusive lock conflicts are not accepted */ + fprintf(stderr, "BF-BF X lock conflict," + "type_mode: %lu supremum: %lu\n", + type_mode, lock_is_on_supremum); + fprintf(stderr, "conflicts states: my %d locked %d\n", + wsrep_thd_conflict_state(trx->mysql_thd, FALSE), + wsrep_thd_conflict_state(lock2->trx->mysql_thd, FALSE) ); + lock_rec_print(stderr, lock2); + return FALSE; + //abort(); + } else { + /* if lock2->index->n_uniq <= + lock2->index->n_user_defined_cols + operation is on uniq index + */ + if (wsrep_debug) fprintf(stderr, + "BF conflict, modes: %lu %lu, " + "idx: %s-%s n_uniq %u n_user %u\n", + type_mode, lock2->type_mode, + lock2->index->name, + lock2->index->table_name, + lock2->index->n_uniq, + lock2->index->n_user_defined_cols); + return FALSE; + } + } +#endif /* WITH_WSREP */ return(TRUE); } @@ -1046,7 +1098,11 @@ lock_has_to_wait( /* If this lock request is for a supremum record then the second bit on the lock bitmap is set */ +#ifdef WITH_WSREP + return(lock_rec_has_to_wait(FALSE, lock1->trx, +#else return(lock_rec_has_to_wait(lock1->trx, +#endif /* WITH_WSREP */ lock1->type_mode, lock2, lock_rec_get_nth_bit( lock1, 1))); @@ -1515,6 +1571,11 @@ lock_rec_has_expl( return(NULL); } +#ifdef WITH_WSREP +static +void +lock_rec_discard(lock_t* in_lock); +#endif #ifdef UNIV_DEBUG /*********************************************************************//** Checks if some other transaction has a lock request in the queue. @@ -1561,6 +1622,69 @@ lock_rec_other_has_expl_req( } #endif /* UNIV_DEBUG */ +#ifdef WITH_WSREP +static +void +wsrep_kill_victim( + const trx_t * const trx, + const lock_t *lock) +{ + ut_ad(lock_mutex_own()); + ut_ad(trx_mutex_own(lock->trx)); + my_bool bf_this = wsrep_thd_is_BF(trx->mysql_thd, FALSE); + my_bool bf_other = wsrep_thd_is_BF(lock->trx->mysql_thd, TRUE); + + if ((bf_this && !bf_other) || + (bf_this && bf_other && wsrep_trx_order_before( + trx->mysql_thd, lock->trx->mysql_thd))) { + + if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { + if (wsrep_debug) { + fprintf(stderr, "WSREP: BF victim waiting\n"); + } + /* cannot release lock, until our lock + is in the queue*/ + } else if (lock->trx != trx) { + if (wsrep_log_conflicts) { + mutex_enter(&trx_sys->mutex); + if (bf_this) { + fputs("\n*** Priority TRANSACTION:\n", + stderr); + } else { + fputs("\n*** Victim TRANSACTION:\n", + stderr); + } + + trx_print_latched(stderr, trx, 3000); + + if (bf_other) { + fputs("\n*** Priority TRANSACTION:\n", + stderr); + } else { + fputs("\n*** Victim TRANSACTION:\n", + stderr); + } + + trx_print_latched(stderr, lock->trx, 3000); + + mutex_exit(&trx_sys->mutex); + + fputs("*** WAITING FOR THIS LOCK TO BE GRANTED:\n", + stderr); + + if (lock_get_type(lock) == LOCK_REC) { + lock_rec_print(stderr, lock); + } else { + lock_table_print(stderr, lock); + } + } + + wsrep_innobase_kill_one_trx(trx->mysql_thd, + (const trx_t*) trx, lock->trx, TRUE); + } + } +} +#endif /*********************************************************************//** Checks if some other transaction has a conflicting explicit lock request in the queue, so that we have to wait. @@ -1589,7 +1713,15 @@ lock_rec_other_has_conflicting( lock != NULL; lock = lock_rec_get_next_const(heap_no, lock)) { - if (lock_rec_has_to_wait(trx, mode, lock, is_supremum)) { +#ifdef WITH_WSREP + if (lock_rec_has_to_wait(TRUE, trx, mode, lock, is_supremum)) { + trx_mutex_enter(lock->trx); + wsrep_kill_victim((trx_t *)trx, (lock_t *)lock); + trx_mutex_exit(lock->trx); +#else + if (lock_rec_has_to_wait(trx, mode, lock, is_supremum)) { +#endif /* WITH_WSREP */ + return(lock); } } @@ -1782,6 +1914,28 @@ lock_number_of_rows_locked( /*============== RECORD LOCK CREATION AND QUEUE MANAGEMENT =============*/ +#ifdef WITH_WSREP +static +void +wsrep_print_wait_locks( +/*============*/ + lock_t* c_lock) /* conflicting lock to print */ +{ + if (wsrep_debug && c_lock->trx->lock.wait_lock != c_lock) { + fprintf(stderr, "WSREP: c_lock != wait lock\n"); + if (lock_get_type_low(c_lock) & LOCK_TABLE) + lock_table_print(stderr, c_lock); + else + lock_rec_print(stderr, c_lock); + + if (lock_get_type_low(c_lock->trx->lock.wait_lock) & LOCK_TABLE) + lock_table_print(stderr, c_lock->trx->lock.wait_lock); + else + lock_rec_print(stderr, c_lock->trx->lock.wait_lock); + } +} +#endif /* WITH_WSREP */ + /*********************************************************************//** Creates a new record lock and inserts it to the lock queue. Does NOT check for deadlocks or lock compatibility! @@ -1790,6 +1944,10 @@ static lock_t* lock_rec_create( /*============*/ +#ifdef WITH_WSREP + lock_t* const c_lock, /* conflicting lock */ + que_thr_t* thr, +#endif ulint type_mode,/*!< in: lock mode and wait flag, type is ignored and replaced by LOCK_REC */ @@ -1861,8 +2019,91 @@ lock_rec_create( ut_ad(index->table->n_ref_count > 0 || !index->table->can_be_evicted); +#ifdef WITH_WSREP + if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + lock_t *hash = (lock_t *)c_lock->hash; + lock_t *prev = NULL; + + while (hash && + wsrep_thd_is_BF(((lock_t *)hash)->trx->mysql_thd, TRUE) && + wsrep_trx_order_before( + ((lock_t *)hash)->trx->mysql_thd, + trx->mysql_thd)) { + prev = hash; + hash = (lock_t *)hash->hash; + } + lock->hash = hash; + if (prev) { + prev->hash = lock; + } else { + c_lock->hash = lock; + } + /* + * delayed conflict resolution '...kill_one_trx' was not called, + * if victim was waiting for some other lock + */ + trx_mutex_enter(c_lock->trx); + if (c_lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { + + c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE; + + if (wsrep_debug) { + wsrep_print_wait_locks(c_lock); + } + + trx->lock.que_state = TRX_QUE_LOCK_WAIT; + lock_set_lock_and_trx_wait(lock, trx); + UT_LIST_ADD_LAST(trx_locks, trx->lock.trx_locks, lock); + + ut_ad(thr != NULL); + trx->lock.wait_thr = thr; + thr->state = QUE_THR_LOCK_WAIT; + + /* have to release trx mutex for the duration of + victim lock release. This will eventually call + lock_grant, which wants to grant trx mutex again + */ + if (caller_owns_trx_mutex) { + trx_mutex_exit(trx); + } + lock_cancel_waiting_and_release( + c_lock->trx->lock.wait_lock); + + if (caller_owns_trx_mutex) { + trx_mutex_enter(trx); + } + + /* trx might not wait for c_lock, but some other lock + does not matter if wait_lock was released above + */ + if (c_lock->trx->lock.wait_lock == c_lock) { + lock_reset_lock_and_trx_wait(lock); + } + + trx_mutex_exit(c_lock->trx); + + if (wsrep_debug) { + fprintf( + stderr, + "WSREP: c_lock canceled %llu\n", + (ulonglong) c_lock->trx->id); + } + + /* have to bail out here to avoid lock_set_lock... */ + return(lock); + } + trx_mutex_exit(c_lock->trx); + } else if (wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + HASH_PREPEND(lock_t, hash, lock_sys->rec_hash, + lock_rec_fold(space, page_no), lock); + } else { + HASH_INSERT(lock_t, hash, lock_sys->rec_hash, + lock_rec_fold(space, page_no), lock); + } +#else HASH_INSERT(lock_t, hash, lock_sys->rec_hash, lock_rec_fold(space, page_no), lock); +#endif /* WITH_WSREP */ lock_sys->rec_num++; @@ -1872,7 +2113,6 @@ lock_rec_create( ut_ad(trx_mutex_own(trx)); if (type_mode & LOCK_WAIT) { - lock_set_lock_and_trx_wait(lock, trx); } @@ -1884,7 +2124,6 @@ lock_rec_create( MONITOR_INC(MONITOR_RECLOCK_CREATED); MONITOR_INC(MONITOR_NUM_RECLOCK); - return(lock); } @@ -1899,6 +2138,9 @@ static dberr_t lock_rec_enqueue_waiting( /*=====================*/ +#ifdef WITH_WSREP + lock_t* c_lock, /* conflicting lock */ +#endif ulint type_mode,/*!< in: lock mode this transaction is requesting: LOCK_S or LOCK_X, possibly @@ -1959,7 +2201,10 @@ lock_rec_enqueue_waiting( /* Enqueue the lock request that will wait to be granted, note that we already own the trx mutex. */ lock = lock_rec_create( - type_mode | LOCK_WAIT, block, heap_no, index, trx, TRUE); +#ifdef WITH_WSREP + c_lock, thr, +#endif /* WITH_WSREP */ + type_mode | LOCK_WAIT, block, heap_no, index, trx, TRUE); /* Release the mutex to obey the latching order. This is safe, because lock_deadlock_check_and_resolve() @@ -2064,7 +2309,19 @@ lock_rec_add_to_queue( const lock_t* other_lock = lock_rec_other_has_expl_req(mode, 0, LOCK_WAIT, block, heap_no, trx->id); +#ifdef WITH_WSREP + /* this can potentionally assert with wsrep */ + if (wsrep_thd_is_wsrep(trx->mysql_thd)) { + if (wsrep_debug && other_lock) { + fprintf(stderr, + "WSREP: InnoDB assert ignored\n"); + } + } else { + ut_a(!other_lock); + } +#else ut_a(!other_lock); +#endif /* WITH_WSREP */ } #endif /* UNIV_DEBUG */ @@ -2092,7 +2349,16 @@ lock_rec_add_to_queue( if (lock_get_wait(lock) && lock_rec_get_nth_bit(lock, heap_no)) { - +#ifdef WITH_WSREP + if (wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + if (wsrep_debug) { + fprintf(stderr, + "BF skipping wait: %lu\n", + trx->id); + lock_rec_print(stderr, lock); + } + } else +#endif goto somebody_waits; } } @@ -2115,9 +2381,15 @@ lock_rec_add_to_queue( } somebody_waits: +#ifdef WITH_WSREP + return(lock_rec_create(NULL, NULL, + type_mode, block, heap_no, index, trx, + caller_owns_trx_mutex)); +#else return(lock_rec_create( type_mode, block, heap_no, index, trx, caller_owns_trx_mutex)); +#endif /* WITH_WSREP */ } /** Record locking request status */ @@ -2180,8 +2452,13 @@ lock_rec_lock_fast( if (lock == NULL) { if (!impl) { /* Note that we don't own the trx mutex. */ +#ifdef WITH_WSREP + lock = lock_rec_create(NULL, thr, + mode, block, heap_no, index, trx, FALSE); +#else lock = lock_rec_create( mode, block, heap_no, index, trx, FALSE); +#endif } status = LOCK_REC_SUCCESS_CREATED; @@ -2235,6 +2512,9 @@ lock_rec_lock_slow( que_thr_t* thr) /*!< in: query thread */ { trx_t* trx; +#ifdef WITH_WSREP + lock_t* c_lock(NULL); +#endif dberr_t err = DB_SUCCESS; ut_ad(lock_mutex_own()); @@ -2259,17 +2539,31 @@ lock_rec_lock_slow( /* The trx already has a strong enough lock on rec: do nothing */ +#ifdef WITH_WSREP + } else if ((c_lock = (lock_t *)lock_rec_other_has_conflicting( + static_cast(mode), + block, heap_no, trx))) { +#else } else if (lock_rec_other_has_conflicting( static_cast(mode), block, heap_no, trx)) { +#endif /* WITH_WSREP */ /* If another transaction has a non-gap conflicting request in the queue, as this transaction does not have a lock strong enough already granted on the record, we have to wait. */ +#ifdef WITH_WSREP + /* c_lock is NULL here if jump to enqueue_waiting happened + but it's ok because lock is not NULL in that case and c_lock + is not used. */ + err = lock_rec_enqueue_waiting(c_lock, + mode, block, heap_no, index, thr); +#else err = lock_rec_enqueue_waiting( mode, block, heap_no, index, thr); +#endif /* WITH_WSREP */ } else if (!impl) { /* Set the requested lock on the record, note that @@ -2321,6 +2615,7 @@ lock_rec_lock( ut_ad(mode - (LOCK_MODE_MASK & mode) == LOCK_GAP || mode - (LOCK_MODE_MASK & mode) == LOCK_REC_NOT_GAP || mode - (LOCK_MODE_MASK & mode) == 0); + ut_ad(dict_index_is_clust(index) || !dict_index_is_online_ddl(index)); /* We try a simplified and faster subroutine for the most @@ -2375,7 +2670,13 @@ lock_rec_has_to_wait_in_queue( if (heap_no < lock_rec_get_n_bits(lock) && (p[bit_offset] & bit_mask) && lock_has_to_wait(wait_lock, lock)) { - +#ifdef WITH_WSREP + if (wsrep_thd_is_BF(wait_lock->trx->mysql_thd, FALSE) && + wsrep_thd_is_BF(lock->trx->mysql_thd, TRUE)) { + /* don't wait for another BF lock */ + continue; + } +#endif return(lock); } } @@ -3761,10 +4062,22 @@ lock_deadlock_select_victim( /* The joining transaction is 'smaller', choose it as the victim and roll it back. */ - return(ctx->start); +#ifdef WITH_WSREP + if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) { + return(ctx->wait_lock->trx); + } + else +#endif /* WITH_WSREP */ + return(ctx->start); } - return(ctx->wait_lock->trx); +#ifdef WITH_WSREP + if (wsrep_thd_is_BF(ctx->wait_lock->trx->mysql_thd, TRUE)) { + return(ctx->start); + } + else +#endif /* WITH_WSREP */ + return(ctx->wait_lock->trx); } /********************************************************************//** @@ -3893,8 +4206,14 @@ lock_deadlock_search( ctx->too_deep = TRUE; +#ifdef WITH_WSREP + if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) { + return(ctx->wait_lock->trx->id); + } + else +#endif /* WITH_WSREP */ /* Select the joining transaction as the victim. */ - return(ctx->start->id); + return(ctx->start->id); } else if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { @@ -3911,7 +4230,12 @@ lock_deadlock_search( ctx->too_deep = TRUE; - return(ctx->start->id); +#ifdef WITH_WSREP + if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) + return(lock->trx->id); + else +#endif /* WITH_WSREP */ + return(ctx->start->id); } ctx->wait_lock = lock->trx->lock.wait_lock; @@ -4029,9 +4353,18 @@ lock_deadlock_check_and_resolve( ut_a(trx == ctx.start); ut_a(victim_trx_id == trx->id); - if (!srv_read_only_mode) { - lock_deadlock_joining_trx_print(trx, lock); +#ifdef WITH_WSREP + if (!wsrep_thd_is_BF(ctx.start->mysql_thd, TRUE)) + { +#endif /* WITH_WSREP */ + if (!srv_read_only_mode) { + lock_deadlock_joining_trx_print(trx, lock); + } +#ifdef WITH_WSREP + } else { + /* BF processor */; } +#endif /* WITH_WSREP */ MONITOR_INC(MONITOR_DEADLOCK); @@ -4071,6 +4404,9 @@ UNIV_INLINE lock_t* lock_table_create( /*==============*/ +#ifdef WITH_WSREP + lock_t* c_lock, /*!< in: conflicting lock */ +#endif dict_table_t* table, /*!< in/out: database table in dictionary cache */ ulint type_mode,/*!< in: lock mode possibly ORed with @@ -4114,7 +4450,59 @@ lock_table_create( ut_ad(table->n_ref_count > 0 || !table->can_be_evicted); UT_LIST_ADD_LAST(trx_locks, trx->lock.trx_locks, lock); + +#ifdef WITH_WSREP + if (wsrep_thd_is_wsrep(trx->mysql_thd)) { + if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + UT_LIST_INSERT_AFTER( + un_member.tab_lock.locks, table->locks, c_lock, lock); + } else { + UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); + } + + if (c_lock) { + trx_mutex_enter(c_lock->trx); + } + + if (c_lock && c_lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { + + c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE; + + if (wsrep_debug) { + wsrep_print_wait_locks(c_lock); + wsrep_print_wait_locks(c_lock->trx->lock.wait_lock); + } + + /* have to release trx mutex for the duration of + victim lock release. This will eventually call + lock_grant, which wants to grant trx mutex again + */ + /* caller has trx_mutex, have to release for lock cancel */ + trx_mutex_exit(trx); + lock_cancel_waiting_and_release(c_lock->trx->lock.wait_lock); + trx_mutex_enter(trx); + + /* trx might not wait for c_lock, but some other lock + does not matter if wait_lock was released above + */ + if (c_lock->trx->lock.wait_lock == c_lock) { + lock_reset_lock_and_trx_wait(lock); + } + + if (wsrep_debug) { + fprintf(stderr, "WSREP: c_lock canceled %llu\n", + (ulonglong) c_lock->trx->id); + } + } + if (c_lock) { + trx_mutex_exit(c_lock->trx); + } + } else { + UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); + } +#else UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); +#endif /* WITH_WSREP */ if (UNIV_UNLIKELY(type_mode & LOCK_WAIT)) { @@ -4271,6 +4659,9 @@ static dberr_t lock_table_enqueue_waiting( /*=======================*/ +#ifdef WITH_WSREP + lock_t* c_lock, /*!< in: conflicting lock */ +#endif ulint mode, /*!< in: lock mode this transaction is requesting */ dict_table_t* table, /*!< in/out: table */ @@ -4317,7 +4708,14 @@ lock_table_enqueue_waiting( /* Enqueue the lock request that will wait to be granted */ +#ifdef WITH_WSREP + if (trx->lock.was_chosen_as_deadlock_victim) { + return(DB_DEADLOCK); + } + lock = lock_table_create(c_lock, table, mode | LOCK_WAIT, trx); +#else lock = lock_table_create(table, mode | LOCK_WAIT, trx); +#endif /* WITH_WSREP */ /* Release the mutex to obey the latching order. This is safe, because lock_deadlock_check_and_resolve() @@ -4394,6 +4792,18 @@ lock_table_other_has_incompatible( && !lock_mode_compatible(lock_get_mode(lock), mode) && (wait || !lock_get_wait(lock))) { +#ifdef WITH_WSREP + if(wsrep_thd_is_wsrep(trx->mysql_thd)) { + if (wsrep_debug) { + fprintf(stderr, "WSREP: trx %ld table lock abort\n", + trx->id); + } + trx_mutex_enter(lock->trx); + wsrep_kill_victim((trx_t *)trx, (lock_t *)lock); + trx_mutex_exit(lock->trx); + } +#endif + return(lock); } } @@ -4416,6 +4826,9 @@ lock_table( enum lock_mode mode, /*!< in: lock mode */ que_thr_t* thr) /*!< in: query thread */ { +#ifdef WITH_WSREP + lock_t *c_lock = NULL; +#endif trx_t* trx; dberr_t err; const lock_t* wait_for; @@ -4450,8 +4863,13 @@ lock_table( /* We have to check if the new lock is compatible with any locks other transactions have in the table lock queue. */ +#ifdef WITH_WSREP + wait_for = lock_table_other_has_incompatible( + trx, LOCK_WAIT, table, mode); +#else wait_for = lock_table_other_has_incompatible( trx, LOCK_WAIT, table, mode); +#endif trx_mutex_enter(trx); @@ -4459,9 +4877,17 @@ lock_table( mode: this trx may have to wait */ if (wait_for != NULL) { +#ifdef WITH_WSREP + err = lock_table_enqueue_waiting((ib_lock_t*)wait_for, mode | flags, table, thr); +#else err = lock_table_enqueue_waiting(mode | flags, table, thr); +#endif } else { +#ifdef WITH_WSREP + lock_table_create(c_lock, table, mode | flags, trx); +#else lock_table_create(table, mode | flags, trx); +#endif ut_a(!flags || mode == LOCK_S || mode == LOCK_X); @@ -4499,7 +4925,11 @@ lock_table_ix_resurrect( trx, LOCK_WAIT, table, LOCK_IX)); trx_mutex_enter(trx); +#ifdef WITH_WSREP + lock_table_create(NULL, table, LOCK_IX, trx); +#else lock_table_create(table, LOCK_IX, trx); +#endif lock_mutex_exit(); trx_mutex_exit(trx); } @@ -5640,16 +6070,20 @@ lock_rec_queue_validate( if (!lock_rec_get_gap(lock) && !lock_get_wait(lock)) { - enum lock_mode mode; +#ifndef WITH_WSREP + if (wsrep_thd_is_wsrep(lock->trx->mysql_thd)) { + enum lock_mode mode; - if (lock_get_mode(lock) == LOCK_S) { - mode = LOCK_X; - } else { - mode = LOCK_S; + + if (lock_get_mode(lock) == LOCK_S) { + mode = LOCK_X; + } else { + mode = LOCK_S; + } + ut_a(!lock_rec_other_has_expl_req( + mode, 0, 0, block, heap_no, lock->trx->id)); } - ut_a(!lock_rec_other_has_expl_req( - mode, 0, 0, block, heap_no, - lock->trx->id)); +#endif /* WITH_WSREP */ } else if (lock_get_wait(lock) && !lock_rec_get_gap(lock)) { @@ -5953,6 +6387,9 @@ lock_rec_insert_check_and_lock( lock_t* lock; dberr_t err; ulint next_rec_heap_no; +#ifdef WITH_WSREP + lock_t* c_lock=NULL; +#endif ut_ad(block->frame == page_align(rec)); ut_ad(!dict_index_is_online_ddl(index) @@ -6014,17 +6451,30 @@ lock_rec_insert_check_and_lock( had to wait for their insert. Both had waiting gap type lock requests on the successor, which produced an unnecessary deadlock. */ +#ifdef WITH_WSREP + if ((c_lock = (ib_lock_t*)lock_rec_other_has_conflicting( + static_cast( + LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION), + block, next_rec_heap_no, trx))) { +#else if (lock_rec_other_has_conflicting( static_cast( LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION), block, next_rec_heap_no, trx)) { +#endif /* WITH_WSREP */ /* Note that we may get DB_SUCCESS also here! */ trx_mutex_enter(trx); +#ifdef WITH_WSREP + err = lock_rec_enqueue_waiting(c_lock, + LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION, + block, next_rec_heap_no, index, thr); +#else err = lock_rec_enqueue_waiting( LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION, block, next_rec_heap_no, index, thr); +#endif /* WITH_WSREP */ trx_mutex_exit(trx); } else { diff --git a/storage/xtradb/lock/lock0wait.cc b/storage/xtradb/lock/lock0wait.cc index a1c35e20ead..388c847f580 100644 --- a/storage/xtradb/lock/lock0wait.cc +++ b/storage/xtradb/lock/lock0wait.cc @@ -184,6 +184,28 @@ lock_wait_table_reserve_slot( return(NULL); } +#ifdef WITH_WSREP +/*********************************************************************//** +check if lock timeout was for priority thread, +as a side effect trigger lock monitor +@return false for regular lock timeout */ +static ibool +wsrep_is_BF_lock_timeout( +/*====================*/ + trx_t* trx) /* in: trx to check for lock priority */ +{ + if (wsrep_on(trx->mysql_thd) && + wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + fprintf(stderr, "WSREP: BF lock wait long\n"); + srv_print_innodb_monitor = TRUE; + srv_print_innodb_lock_monitor = TRUE; + os_event_set(srv_monitor_event); + return TRUE; + } + return FALSE; + } +#endif /* WITH_WSREP */ + /***************************************************************//** Puts a user OS thread to wait for a lock to be released. If an error occurs during the wait trx->error_state associated with thr is @@ -375,9 +397,15 @@ lock_wait_suspend_thread( if (lock_wait_timeout < 100000000 && wait_time > (double) lock_wait_timeout) { +#ifdef WITH_WSREP + if (!wsrep_is_BF_lock_timeout(trx)) { +#endif /* WITH_WSREP */ trx->error_state = DB_LOCK_WAIT_TIMEOUT; +#ifdef WITH_WSREP + } +#endif /* WITH_WSREP */ MONITOR_INC(MONITOR_TIMEOUT); } @@ -461,8 +489,13 @@ lock_wait_check_and_cancel( if (trx->lock.wait_lock) { ut_a(trx->lock.que_state == TRX_QUE_LOCK_WAIT); - +#ifdef WITH_WSREP + if (!wsrep_is_BF_lock_timeout(trx)) { +#endif /* WITH_WSREP */ lock_cancel_waiting_and_release(trx->lock.wait_lock); +#ifdef WITH_WSREP + } +#endif /* WITH_WSREP */ } lock_mutex_exit(); diff --git a/storage/xtradb/os/os0file.cc b/storage/xtradb/os/os0file.cc index 394c3199f76..edcb6662fe9 100644 --- a/storage/xtradb/os/os0file.cc +++ b/storage/xtradb/os/os0file.cc @@ -110,6 +110,12 @@ UNIV_INTERN os_ib_mutex_t os_file_seek_mutexes[OS_FILE_N_SEEK_MUTEXES]; /* In simulated aio, merge at most this many consecutive i/os */ #define OS_AIO_MERGE_N_CONSECUTIVE 64 +#ifdef WITH_INNODB_DISALLOW_WRITES +#define WAIT_ALLOW_WRITES() os_event_wait(srv_allow_writes_event) +#else +#define WAIT_ALLOW_WRITES() do { } while (0) +#endif /* WITH_INNODB_DISALLOW_WRITES */ + /********************************************************************** InnoDB AIO Implementation: @@ -999,7 +1005,9 @@ os_file_create_tmpfile(void) /*========================*/ { FILE* file = NULL; - int fd = innobase_mysql_tmpfile(); + int fd; + WAIT_ALLOW_WRITES(); + fd = innobase_mysql_tmpfile(); ut_ad(!srv_read_only_mode); @@ -1325,6 +1333,7 @@ os_file_create_directory( return(TRUE); #else int rcode; + WAIT_ALLOW_WRITES(); rcode = mkdir(pathname, 0770); @@ -1451,6 +1460,8 @@ os_file_create_simple_func( #else /* __WIN__ */ int create_flag; + if (create_mode != OS_FILE_OPEN && create_mode != OS_FILE_OPEN_RAW) + WAIT_ALLOW_WRITES(); ut_a(!(create_mode & OS_FILE_ON_ERROR_SILENT)); ut_a(!(create_mode & OS_FILE_ON_ERROR_NO_EXIT)); @@ -1638,6 +1649,8 @@ os_file_create_simple_no_error_handling_func( int create_flag; ut_a(name); + if (create_mode != OS_FILE_OPEN && create_mode != OS_FILE_OPEN_RAW) + WAIT_ALLOW_WRITES(); ut_a(!(create_mode & OS_FILE_ON_ERROR_SILENT)); ut_a(!(create_mode & OS_FILE_ON_ERROR_NO_EXIT)); @@ -2013,6 +2026,8 @@ os_file_create_func( #else /* __WIN__ */ int create_flag; const char* mode_str = NULL; + if (create_mode != OS_FILE_OPEN && create_mode != OS_FILE_OPEN_RAW) + WAIT_ALLOW_WRITES(); on_error_no_exit = create_mode & OS_FILE_ON_ERROR_NO_EXIT ? TRUE : FALSE; @@ -2212,6 +2227,7 @@ loop: goto loop; #else int ret; + WAIT_ALLOW_WRITES(); ret = unlink(name); @@ -2276,6 +2292,7 @@ loop: goto loop; #else int ret; + WAIT_ALLOW_WRITES(); ret = unlink(name); @@ -2329,6 +2346,7 @@ os_file_rename_func( return(FALSE); #else int ret; + WAIT_ALLOW_WRITES(); ret = rename(oldpath, newpath); @@ -2562,6 +2580,7 @@ os_file_set_eof( HANDLE h = (HANDLE) _get_osfhandle(fileno(file)); return(SetEndOfFile(h)); #else /* __WIN__ */ + WAIT_ALLOW_WRITES(); return(!ftruncate(fileno(file), ftell(file))); #endif /* __WIN__ */ } @@ -2581,6 +2600,7 @@ os_file_set_eof_at( return(SetFilePointerEx(file, li, &li2,FILE_BEGIN) && SetEndOfFile(file)); #else + WAIT_ALLOW_WRITES(); /* TODO: works only with -D_FILE_OFFSET_BITS=64 ? */ return(!ftruncate(file, new_len)); #endif @@ -2680,6 +2700,7 @@ os_file_flush_func( return(FALSE); #else int ret; + WAIT_ALLOW_WRITES(); #if defined(HAVE_DARWIN_THREADS) # ifndef F_FULLFSYNC @@ -3382,6 +3403,7 @@ retry: return(FALSE); #else ssize_t ret; + WAIT_ALLOW_WRITES(); ret = os_file_pwrite(file, buf, n, offset); diff --git a/storage/xtradb/rem/rem0rec.cc b/storage/xtradb/rem/rem0rec.cc index 0d7b7c16785..ca9b0a6b841 100644 --- a/storage/xtradb/rem/rem0rec.cc +++ b/storage/xtradb/rem/rem0rec.cc @@ -33,6 +33,9 @@ Created 5/30/1994 Heikki Tuuri #include "mtr0mtr.h" #include "mtr0log.h" #include "fts0fts.h" +#ifdef WITH_WSREP +#include +#endif /* WITH_WSREP */ /* PHYSICAL RECORD (OLD STYLE) =========================== @@ -1917,6 +1920,138 @@ rec_print( } } } +#endif /* !UNIV_HOTBACKUP */ + +#ifdef WITH_WSREP +int +wsrep_rec_get_foreign_key( + byte *buf, /* out: extracted key */ + ulint *buf_len, /* in/out: length of buf */ + const rec_t* rec, /* in: physical record */ + dict_index_t* index_for, /* in: index in foreign table */ + dict_index_t* index_ref, /* in: index in referenced table */ + ibool new_protocol) /* in: protocol > 1 */ +{ + const byte* data; + ulint len; + ulint key_len = 0; + ulint i; + uint key_parts; + mem_heap_t* heap = NULL; + ulint offsets_[REC_OFFS_NORMAL_SIZE]; + const ulint* offsets; + + ut_ad(index_for); + ut_ad(index_ref); + + rec_offs_init(offsets_); + offsets = rec_get_offsets(rec, index_for, offsets_, + ULINT_UNDEFINED, &heap); + + ut_ad(rec_offs_validate(rec, NULL, offsets)); + + ut_ad(rec); + + key_parts = dict_index_get_n_unique_in_tree(index_for); + for (i = 0; + i < key_parts && + (index_for->type & DICT_CLUSTERED || i < key_parts - 1); + i++) { + dict_field_t* field_f = + dict_index_get_nth_field(index_for, i); + const dict_col_t* col_f = dict_field_get_col(field_f); + dict_field_t* field_r = + dict_index_get_nth_field(index_ref, i); + const dict_col_t* col_r = dict_field_get_col(field_r); + + data = rec_get_nth_field(rec, offsets, i, &len); + if (key_len + ((len != UNIV_SQL_NULL) ? len + 1 : 1) > + *buf_len) { + fprintf (stderr, + "WSREP: FK key len exceeded %lu %lu %lu\n", + key_len, len, *buf_len); + goto err_out; + } + + if (len == UNIV_SQL_NULL) { + ut_a(!(col_f->prtype & DATA_NOT_NULL)); + *buf++ = 1; + key_len++; + } else if (!new_protocol) { + if (!(col_r->prtype & DATA_NOT_NULL)) { + *buf++ = 0; + key_len++; + } + memcpy(buf, data, len); + *buf_len = wsrep_innobase_mysql_sort( + (int)(col_f->prtype & DATA_MYSQL_TYPE_MASK), + (uint)dtype_get_charset_coll(col_f->prtype), + buf, len, *buf_len); + } else { /* new protocol */ + if (!(col_r->prtype & DATA_NOT_NULL)) { + *buf++ = 0; + key_len++; + } + switch (col_f->mtype) { + case DATA_INT: { + byte* ptr = buf+len; + for (;;) { + ptr--; + *ptr = *data; + if (ptr == buf) { + break; + } + data++; + } + + if (!(col_f->prtype & DATA_UNSIGNED)) { + buf[len-1] = (byte) (buf[len-1] ^ 128); + } + + break; + } + case DATA_VARCHAR: + case DATA_VARMYSQL: + case DATA_CHAR: + case DATA_MYSQL: + /* Copy the actual data */ + ut_memcpy(buf, data, len); + len = wsrep_innobase_mysql_sort( + (int) + (col_f->prtype & DATA_MYSQL_TYPE_MASK), + (uint) + dtype_get_charset_coll(col_f->prtype), + buf, len, *buf_len); + break; + case DATA_BLOB: + case DATA_BINARY: + memcpy(buf, data, len); + break; + default: + break; + } + + key_len += len; + buf += len; + } + } + + rec_validate(rec, offsets); + + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); + } + + *buf_len = key_len; + return DB_SUCCESS; + + err_out: + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); + } + return DB_ERROR; +} +#endif /* WITH_WSREP */ # ifdef UNIV_DEBUG /************************************************************//** @@ -1959,5 +2094,5 @@ rec_get_trx_id( return(trx_read_trx_id(trx_id)); } -# endif /* UNIV_DEBUG */ -#endif /* !UNIV_HOTBACKUP */ +#endif /* UNIV_DEBUG */ + diff --git a/storage/xtradb/row/row0ins.cc b/storage/xtradb/row/row0ins.cc index f8ca40fac12..444fac87842 100644 --- a/storage/xtradb/row/row0ins.cc +++ b/storage/xtradb/row/row0ins.cc @@ -918,6 +918,14 @@ row_ins_invalidate_query_cache( innobase_invalidate_query_cache(thr_get_trx(thr), buf, len); mem_free(buf); } +#ifdef WITH_WSREP +dberr_t wsrep_append_foreign_key(trx_t *trx, + dict_foreign_t* foreign, + const rec_t* clust_rec, + dict_index_t* clust_index, + ibool referenced, + ibool shared); +#endif /* WITH_WSREP */ /*********************************************************************//** Perform referential actions or checks when a parent row is deleted or updated @@ -1269,7 +1277,19 @@ row_ins_foreign_check_on_constraint( cascade->state = UPD_NODE_UPDATE_CLUSTERED; - err = row_update_cascade_for_mysql(thr, cascade, +#ifdef WITH_WSREP + err = wsrep_append_foreign_key( + thr_get_trx(thr), + foreign, + clust_rec, + clust_index, + FALSE, FALSE); + if (err != DB_SUCCESS) { + fprintf(stderr, + "WSREP: foreign key append failed: %d\n", err); + } else +#endif /* WITH_WSREP */ + err = row_update_cascade_for_mysql(thr, cascade, foreign->foreign_table); if (foreign->foreign_table->n_foreign_key_checks_running == 0) { @@ -1607,7 +1627,14 @@ run_again: if (check_ref) { err = DB_SUCCESS; - +#ifdef WITH_WSREP + err = wsrep_append_foreign_key( + thr_get_trx(thr), + foreign, + rec, + check_index, + check_ref, TRUE); +#endif /* WITH_WSREP */ goto end_scan; } else if (foreign->type != 0) { /* There is an ON UPDATE or ON DELETE diff --git a/storage/xtradb/row/row0upd.cc b/storage/xtradb/row/row0upd.cc index 3ead385c2cd..bdd2a691368 100644 --- a/storage/xtradb/row/row0upd.cc +++ b/storage/xtradb/row/row0upd.cc @@ -53,6 +53,9 @@ Created 12/27/1996 Heikki Tuuri #include "pars0sym.h" #include "eval0eval.h" #include "buf0lru.h" +#ifdef WITH_WSREP +extern my_bool wsrep_debug; +#endif /* What kind of latch and lock can we assume when the control comes to @@ -172,6 +175,50 @@ func_exit: return(is_referenced); } +#ifdef WITH_WSREP +static +ibool +wsrep_row_upd_index_is_foreign( +/*========================*/ + dict_index_t* index, /*!< in: index */ + trx_t* trx) /*!< in: transaction */ +{ + dict_table_t* table = index->table; + dict_foreign_t* foreign; + ibool froze_data_dict = FALSE; + ibool is_referenced = FALSE; + + if (!UT_LIST_GET_FIRST(table->foreign_list)) { + + return(FALSE); + } + + if (trx->dict_operation_lock_mode == 0) { + row_mysql_freeze_data_dictionary(trx); + froze_data_dict = TRUE; + } + + foreign = UT_LIST_GET_FIRST(table->foreign_list); + + while (foreign) { + if (foreign->foreign_index == index) { + + is_referenced = TRUE; + goto func_exit; + } + + foreign = UT_LIST_GET_NEXT(foreign_list, foreign); + } + +func_exit: + if (froze_data_dict) { + row_mysql_unfreeze_data_dictionary(trx); + } + + return(is_referenced); +} +#endif /* WITH_WSREP */ + /*********************************************************************//** Checks if possible foreign key constraints hold after a delete of the record under pcur. @@ -289,7 +336,123 @@ run_again: } err = DB_SUCCESS; +func_exit: + if (got_s_lock) { + row_mysql_unfreeze_data_dictionary(trx); + } + mem_heap_free(heap); + + return(err); +} +#ifdef WITH_WSREP +static +dberr_t +wsrep_row_upd_check_foreign_constraints( +/*=================================*/ + upd_node_t* node, /*!< in: row update node */ + btr_pcur_t* pcur, /*!< in: cursor positioned on a record; NOTE: the + cursor position is lost in this function! */ + dict_table_t* table, /*!< in: table in question */ + dict_index_t* index, /*!< in: index of the cursor */ + ulint* offsets,/*!< in/out: rec_get_offsets(pcur.rec, index) */ + que_thr_t* thr, /*!< in: query thread */ + mtr_t* mtr) /*!< in: mtr */ +{ + dict_foreign_t* foreign; + mem_heap_t* heap; + dtuple_t* entry; + trx_t* trx; + const rec_t* rec; + ulint n_ext; + dberr_t err; + ibool got_s_lock = FALSE; + ibool opened = FALSE; + + if (UT_LIST_GET_FIRST(table->foreign_list) == NULL) { + + return(DB_SUCCESS); + } + + trx = thr_get_trx(thr); + + /* TODO: make native slave thread bail out here */ + + rec = btr_pcur_get_rec(pcur); + ut_ad(rec_offs_validate(rec, index, offsets)); + + heap = mem_heap_create(500); + + entry = row_rec_to_index_entry(rec, index, offsets, + &n_ext, heap); + + mtr_commit(mtr); + + mtr_start(mtr); + + if (trx->dict_operation_lock_mode == 0) { + got_s_lock = TRUE; + + row_mysql_freeze_data_dictionary(trx); + } + + foreign = UT_LIST_GET_FIRST(table->foreign_list); + + while (foreign) { + /* Note that we may have an update which updates the index + record, but does NOT update the first fields which are + referenced in a foreign key constraint. Then the update does + NOT break the constraint. */ + + if (foreign->foreign_index == index + && (node->is_delete + || row_upd_changes_first_fields_binary( + entry, index, node->update, + foreign->n_fields))) { + + if (foreign->referenced_table == NULL) { + foreign->referenced_table = + dict_table_open_on_name( + foreign->referenced_table_name_lookup, + FALSE, FALSE, DICT_ERR_IGNORE_NONE); + opened = TRUE; + } + + if (foreign->referenced_table) { + os_inc_counter(dict_sys->mutex, + foreign->referenced_table + ->n_foreign_key_checks_running); + } + + /* NOTE that if the thread ends up waiting for a lock + we will release dict_operation_lock temporarily! + But the counter on the table protects 'foreign' from + being dropped while the check is running. */ + + err = row_ins_check_foreign_constraint( + TRUE, foreign, table, entry, thr); + + if (foreign->referenced_table) { + os_dec_counter(dict_sys->mutex, + foreign->referenced_table + ->n_foreign_key_checks_running); + + if (opened == TRUE) { + dict_table_close(foreign->referenced_table, TRUE, FALSE); + opened = FALSE; + } + } + + if (err != DB_SUCCESS) { + + goto func_exit; + } + } + + foreign = UT_LIST_GET_NEXT(foreign_list, foreign); + } + + err = DB_SUCCESS; func_exit: if (got_s_lock) { row_mysql_unfreeze_data_dictionary(trx); @@ -301,6 +464,7 @@ func_exit: return(err); } +#endif /* WITH_WSREP */ /*********************************************************************//** Creates an update node for a query graph. @@ -1675,6 +1839,9 @@ row_upd_sec_index_entry( index = node->index; referenced = row_upd_index_is_referenced(index, trx); +#ifdef WITH_WSREP + ibool foreign = wsrep_row_upd_index_is_foreign(index, trx); +#endif /* WITH_WSREP */ heap = mem_heap_create(1024); @@ -1805,6 +1972,9 @@ row_upd_sec_index_entry( row_ins_sec_index_entry() below */ if (!rec_get_deleted_flag( rec, dict_table_is_comp(index->table))) { +#ifdef WITH_WSREP + que_node_t *parent = que_node_get_parent(node); +#endif /* WITH_WSREP */ err = btr_cur_del_mark_set_sec_rec( 0, btr_cur, TRUE, thr, &mtr); @@ -1822,6 +1992,37 @@ row_upd_sec_index_entry( node, &pcur, index->table, index, offsets, thr, &mtr); } +#ifdef WITH_WSREP + if (err == DB_SUCCESS && !referenced && + !(parent && que_node_get_type(parent) == + QUE_NODE_UPDATE && + ((upd_node_t*)parent)->cascade_node == node) && + foreign + ) { + ulint* offsets = + rec_get_offsets( + rec, index, NULL, ULINT_UNDEFINED, + &heap); + err = wsrep_row_upd_check_foreign_constraints( + node, &pcur, index->table, + index, offsets, thr, &mtr); + switch (err) { + case DB_SUCCESS: + case DB_NO_REFERENCED_ROW: + err = DB_SUCCESS; + break; + case DB_DEADLOCK: + if (wsrep_debug) fprintf (stderr, + "WSREP: sec index FK check fail for deadlock"); + break; + default: + fprintf (stderr, + "WSREP: referenced FK check fail: %d", + (int)err); + break; + } + } +#endif /* WITH_WSREP */ } break; } @@ -1976,6 +2177,9 @@ row_upd_clust_rec_by_insert( que_thr_t* thr, /*!< in: query thread */ ibool referenced,/*!< in: TRUE if index may be referenced in a foreign key constraint */ +#ifdef WITH_WSREP + ibool foreign, /*!< in: TRUE if index is foreign key index */ +#endif /* WITH_WSREP */ mtr_t* mtr) /*!< in/out: mtr; gets committed here */ { mem_heap_t* heap; @@ -1989,6 +2193,9 @@ row_upd_clust_rec_by_insert( rec_t* rec; ulint* offsets = NULL; +#ifdef WITH_WSREP + que_node_t *parent = que_node_get_parent(node); +#endif /* WITH_WSREP */ ut_ad(node); ut_ad(dict_index_is_clust(index)); @@ -2074,6 +2281,34 @@ err_exit: goto err_exit; } } +#ifdef WITH_WSREP + if (!referenced && + !(parent && que_node_get_type(parent) == QUE_NODE_UPDATE && + ((upd_node_t*)parent)->cascade_node == node) && + foreign + ) { + err = wsrep_row_upd_check_foreign_constraints( + node, pcur, table, index, offsets, thr, mtr); + switch (err) { + case DB_SUCCESS: + case DB_NO_REFERENCED_ROW: + err = DB_SUCCESS; + break; + case DB_DEADLOCK: + if (wsrep_debug) fprintf (stderr, + "WSREP: insert FK check fail for deadlock"); + break; + default: + fprintf (stderr, + "WSREP: referenced FK check fail: %d", + (int)err); + break; + } + if (err != DB_SUCCESS) { + goto err_exit; + } + } +#endif /* WITH_WSREP */ } mtr_commit(mtr); @@ -2269,11 +2504,18 @@ row_upd_del_mark_clust_rec( ibool referenced, /*!< in: TRUE if index may be referenced in a foreign key constraint */ +#ifdef WITH_WSREP + ibool foreign,/*!< in: TRUE if index is foreign key index */ +#endif /* WITH_WSREP */ mtr_t* mtr) /*!< in: mtr; gets committed here */ { btr_pcur_t* pcur; btr_cur_t* btr_cur; dberr_t err; +#ifdef WITH_WSREP + rec_t* rec; + que_node_t *parent = que_node_get_parent(node); +#endif /* WITH_WSREP */ ut_ad(node); ut_ad(dict_index_is_clust(index)); @@ -2290,8 +2532,16 @@ row_upd_del_mark_clust_rec( /* Mark the clustered index record deleted; we do not have to check locks, because we assume that we have an x-lock on the record */ +#ifdef WITH_WSREP + rec = btr_cur_get_rec(btr_cur); +#endif /* WITH_WSREP */ + err = btr_cur_del_mark_set_clust_rec( +#ifdef WITH_WSREP + btr_cur_get_block(btr_cur), rec, +#else btr_cur_get_block(btr_cur), btr_cur_get_rec(btr_cur), +#endif /* WITH_WSREP */ index, offsets, thr, mtr); if (err == DB_SUCCESS && referenced) { /* NOTE that the following call loses the position of pcur ! */ @@ -2299,6 +2549,32 @@ row_upd_del_mark_clust_rec( err = row_upd_check_references_constraints( node, pcur, index->table, index, offsets, thr, mtr); } +#ifdef WITH_WSREP + if (err == DB_SUCCESS && !referenced && + !(parent && que_node_get_type(parent) == QUE_NODE_UPDATE && + ((upd_node_t*)parent)->cascade_node == node) && + thr_get_trx(thr) && + foreign + ) { + err = wsrep_row_upd_check_foreign_constraints( + node, pcur, index->table, index, offsets, thr, mtr); + switch (err) { + case DB_SUCCESS: + case DB_NO_REFERENCED_ROW: + err = DB_SUCCESS; + break; + case DB_DEADLOCK: + if (wsrep_debug) fprintf (stderr, + "WSREP: clust rec FK check fail for deadlock"); + break; + default: + fprintf (stderr, + "WSREP: clust rec referenced FK check fail: %d", + (int)err); + break; + } + } +#endif /* WITH_WSREP */ mtr_commit(mtr); @@ -2331,6 +2607,10 @@ row_upd_clust_step( index = dict_table_get_first_index(node->table); referenced = row_upd_index_is_referenced(index, thr_get_trx(thr)); +#ifdef WITH_WSREP + ibool foreign = wsrep_row_upd_index_is_foreign( + index, thr_get_trx(thr)); +#endif /* WITH_WSREP */ pcur = node->pcur; @@ -2427,7 +2707,11 @@ row_upd_clust_step( if (node->is_delete) { err = row_upd_del_mark_clust_rec( +#ifdef WITH_WSREP + node, index, offsets, thr, referenced, foreign, &mtr); +#else node, index, offsets, thr, referenced, &mtr); +#endif /* WITH_WSREP */ if (err == DB_SUCCESS) { node->state = UPD_NODE_UPDATE_ALL_SEC; @@ -2472,7 +2756,11 @@ row_upd_clust_step( externally! */ err = row_upd_clust_rec_by_insert( +#ifdef WITH_WSREP + node, index, thr, referenced, foreign, &mtr); +#else node, index, thr, referenced, &mtr); +#endif /* WITH_WSREP */ if (err != DB_SUCCESS) { diff --git a/storage/xtradb/srv/srv0conc.cc b/storage/xtradb/srv/srv0conc.cc index 6c15753246a..5868e4e012b 100644 --- a/storage/xtradb/srv/srv0conc.cc +++ b/storage/xtradb/srv/srv0conc.cc @@ -43,6 +43,10 @@ Created 2011/04/18 Sunny Bains #include "trx0trx.h" #include "mysql/plugin.h" +#ifdef WITH_WSREP +extern "C" int wsrep_trx_is_aborting(void *thd_ptr); +extern my_bool wsrep_debug; +#endif /** Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket. */ @@ -87,6 +91,9 @@ struct srv_conc_slot_t{ reserved may still be TRUE at that point */ srv_conc_node_t srv_conc_queue; /*!< queue node */ +#ifdef WITH_WSREP + void *thd; /*!< to see priority */ +#endif }; /** Queue of threads waiting to get in */ @@ -146,6 +153,9 @@ srv_conc_init(void) conc_slot->event = os_event_create(); ut_a(conc_slot->event); +#ifdef WITH_WSREP + conc_slot->thd = NULL; +#endif /* WITH_WSREP */ } #endif /* !HAVE_ATOMIC_BUILTINS */ } @@ -203,6 +213,16 @@ srv_conc_enter_innodb_with_atomics( for (;;) { ulint sleep_in_us; +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd) && + wsrep_trx_is_aborting(trx->mysql_thd)) { + if (wsrep_debug) + fprintf(stderr, + "srv_conc_enter due to MUST_ABORT"); + srv_conc_force_enter_innodb(trx); + return; + } +#endif /* WITH_WSREP */ if (srv_conc.n_active < (lint) srv_thread_concurrency) { ulint n_active; @@ -321,6 +341,9 @@ srv_conc_exit_innodb_without_atomics( slot = NULL; if (srv_conc.n_active < (lint) srv_thread_concurrency) { +#ifdef WITH_WSREP + srv_conc_slot_t* wsrep_slot; +#endif /* Look for a slot where a thread is waiting and no other thread has yet released the thread */ @@ -331,6 +354,19 @@ srv_conc_exit_innodb_without_atomics( /* No op */ } +#ifdef WITH_WSREP + /* look for aborting trx, they must be released asap */ + wsrep_slot= slot; + while (wsrep_slot && (wsrep_slot->wait_ended == TRUE || + !wsrep_trx_is_aborting(wsrep_slot->thd))) { + wsrep_slot = UT_LIST_GET_NEXT(srv_conc_queue, wsrep_slot); + } + if (wsrep_slot) { + slot = wsrep_slot; + if (wsrep_debug) + fprintf(stderr, "WSREP: releasing aborting thd\n"); + } +#endif if (slot != NULL) { slot->wait_ended = TRUE; @@ -390,6 +426,13 @@ retry: return; } +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd) && + wsrep_thd_is_brute_force(trx->mysql_thd)) { + srv_conc_force_enter_innodb(trx); + return; + } +#endif /* If the transaction is not holding resources, let it sleep for srv_thread_sleep_delay microseconds, and try again then */ @@ -457,6 +500,9 @@ retry: /* Add to the queue */ slot->reserved = TRUE; slot->wait_ended = FALSE; +#ifdef WITH_WSREP + slot->thd = trx->mysql_thd; +#endif UT_LIST_ADD_LAST(srv_conc_queue, srv_conc_queue, slot); @@ -464,6 +510,18 @@ retry: srv_conc.n_waiting++; +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd) && + wsrep_trx_is_aborting(trx->mysql_thd)) { + os_fast_mutex_unlock(&srv_conc_mutex); + if (wsrep_debug) + fprintf(stderr, "srv_conc_enter due to MUST_ABORT"); + trx->declared_to_be_inside_innodb = TRUE; + trx->n_tickets_to_enter_innodb = srv_n_free_tickets_to_enter; + return; + } + trx->wsrep_event = slot->event; +#endif /* WITH_WSREP */ os_fast_mutex_unlock(&srv_conc_mutex); /* Go to wait for the event; when a thread leaves InnoDB it will @@ -487,6 +545,9 @@ retry: os_event_wait(slot->event); thd_wait_end(trx->mysql_thd); +#ifdef WITH_WSREP + trx->wsrep_event = NULL; +#endif /* WITH_WSREP */ trx->op_info = ""; @@ -504,6 +565,9 @@ retry: incremented the thread counter on behalf of this thread */ slot->reserved = FALSE; +#ifdef WITH_WSREP + slot->thd = NULL; +#endif UT_LIST_REMOVE(srv_conc_queue, srv_conc_queue, slot); @@ -614,5 +678,32 @@ srv_conc_get_active_threads(void) /*==============================*/ { return(srv_conc.n_active); - } +} + +#ifdef WITH_WSREP +UNIV_INTERN +void +wsrep_srv_conc_cancel_wait( +/*==================*/ + trx_t* trx) /*!< in: transaction object associated with the + thread */ +{ +#ifdef HAVE_ATOMIC_BUILTINS + /* aborting transactions will enter innodb by force in + srv_conc_enter_innodb_with_atomics(). No need to cancel here, + thr will wake up after os_sleep and let to enter innodb + */ + if (wsrep_debug) + fprintf(stderr, "WSREP: conc slot cancel, no atomics\n"); +#else + os_fast_mutex_lock(&srv_conc_mutex); + if (trx->wsrep_event) { + if (wsrep_debug) + fprintf(stderr, "WSREP: conc slot cancel\n"); + os_event_set(trx->wsrep_event); + } + os_fast_mutex_unlock(&srv_conc_mutex); +#endif +} +#endif /* WITH_WSREP */ diff --git a/storage/xtradb/srv/srv0srv.cc b/storage/xtradb/srv/srv0srv.cc index 8e01ea7402e..d421980d41a 100644 --- a/storage/xtradb/srv/srv0srv.cc +++ b/storage/xtradb/srv/srv0srv.cc @@ -84,6 +84,14 @@ ulong innobase_thd_get_thread_id(const void* thd); /* prototypes for new functions added to ha_innodb.cc */ ibool innobase_get_slow_log(); +#ifdef WITH_WSREP +extern int wsrep_debug; +extern int wsrep_trx_is_aborting(void *thd_ptr); +#endif +/* The following counter is incremented whenever there is some user activity +in the server */ +UNIV_INTERN ulint srv_activity_count = 0; + /* The following is the maximum allowed duration of a lock wait. */ UNIV_INTERN ulint srv_fatal_semaphore_wait_threshold = 600; @@ -254,6 +262,10 @@ srv_printf_innodb_monitor() will request mutex acquisition with mutex_enter(), which will wait until it gets the mutex. */ #define MUTEX_NOWAIT(mutex_skipped) ((mutex_skipped) < MAX_MUTEX_NOWAIT) +#ifdef WITH_INNODB_DISALLOW_WRITES +UNIV_INTERN os_event_t srv_allow_writes_event; +#endif /* WITH_INNODB_DISALLOW_WRITES */ + /** The sort order table of the MySQL latin1_swedish_ci character set collation */ UNIV_INTERN const byte* srv_latin1_ordering; @@ -1150,6 +1162,14 @@ srv_init(void) dict_ind_init(); srv_conc_init(); +#ifdef WITH_INNODB_DISALLOW_WRITES + /* Writes have to be enabled on init or else we hang. Thus, we + always set the event here regardless of innobase_disallow_writes. + That flag will always be 0 at this point because it isn't settable + via my.cnf or command line arg. */ + srv_allow_writes_event = os_event_create(); + os_event_set(srv_allow_writes_event); +#endif /* WITH_INNODB_DISALLOW_WRITES */ /* Initialize some INFORMATION SCHEMA internal structures */ trx_i_s_cache_init(trx_i_s_cache); @@ -2158,7 +2178,20 @@ loop: if (sync_array_print_long_waits(&waiter, &sema) && sema == old_sema && os_thread_eq(waiter, old_waiter)) { +#if defined(WITH_WSREP) && defined(WITH_INNODB_DISALLOW_WRITES) + if (srv_allow_writes_event->is_set) { +#endif /* WITH_WSREP */ fatal_cnt++; +#if defined(WITH_WSREP) && defined(WITH_INNODB_DISALLOW_WRITES) + } else { + fprintf(stderr, + "WSREP: avoiding InnoDB self crash due to long " + "semaphore wait of > %lu seconds\n" + "Server is processing SST donor operation, " + "fatal_cnt now: %lu", + (ulong) srv_fatal_semaphore_wait_threshold, fatal_cnt); + } +#endif /* WITH_WSREP */ if (fatal_cnt > 10) { fprintf(stderr, diff --git a/storage/xtradb/trx/trx0roll.cc b/storage/xtradb/trx/trx0roll.cc index 1089607c6d1..eb2af877a6d 100644 --- a/storage/xtradb/trx/trx0roll.cc +++ b/storage/xtradb/trx/trx0roll.cc @@ -45,6 +45,9 @@ Created 3/26/1996 Heikki Tuuri #include "pars0pars.h" #include "srv0mon.h" #include "trx0sys.h" +#ifdef WITH_WSREP +#include "ha_prototypes.h" +#endif /* WITH_WSREP */ /** This many pages must be undone before a truncate is tried within rollback */ @@ -382,6 +385,13 @@ trx_rollback_to_savepoint_for_mysql_low( trx->op_info = ""; +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd) && + trx->lock.was_chosen_as_deadlock_victim) { + trx->lock.was_chosen_as_deadlock_victim = FALSE; + } +#endif + return(err); } @@ -1020,6 +1030,12 @@ trx_roll_try_truncate( if (trx->update_undo) { trx_undo_truncate_end(trx, trx->update_undo, limit); } + +#ifdef WITH_WSREP_OUT + if (wsrep_on(trx->mysql_thd)) { + trx->lock.was_chosen_as_deadlock_victim = FALSE; + } +#endif /* WITH_WSREP */ } /***********************************************************************//** diff --git a/storage/xtradb/trx/trx0sys.cc b/storage/xtradb/trx/trx0sys.cc index aab99a793f6..19d14bf6f38 100644 --- a/storage/xtradb/trx/trx0sys.cc +++ b/storage/xtradb/trx/trx0sys.cc @@ -44,6 +44,10 @@ Created 3/26/1996 Heikki Tuuri #include "os0file.h" #include "read0read.h" +#ifdef WITH_WSREP +#include "ha_prototypes.h" /* wsrep_is_wsrep_xid() */ +#endif /* */ + /** The file format tag structure with id and name. */ struct file_format_t { ulint id; /*!< id of the file format */ @@ -174,7 +178,12 @@ trx_sys_flush_max_trx_id(void) mtr_t mtr; trx_sysf_t* sys_header; +#ifndef WITH_WSREP + /* wsrep_fake_trx_id violates this assert + * Copied from trx_sys_get_new_trx_id + */ ut_ad(mutex_own(&trx_sys->mutex)); +#endif /* WITH_WSREP */ if (!srv_read_only_mode) { mtr_start(&mtr); @@ -202,9 +211,14 @@ trx_sys_update_mysql_binlog_offset( ib_int64_t offset, /*!< in: position in that log file */ ulint field, /*!< in: offset of the MySQL log info field in the trx sys header */ +#ifdef WITH_WSREP + trx_sysf_t* sys_header, /*!< in: trx sys header */ +#endif /* WITH_WSREP */ mtr_t* mtr) /*!< in: mtr */ { +#ifndef WITH_WSREP trx_sysf_t* sys_header; +#endif /* !WITH_WSREP */ if (ut_strlen(file_name) >= TRX_SYS_MYSQL_LOG_NAME_LEN) { @@ -213,7 +227,9 @@ trx_sys_update_mysql_binlog_offset( return; } +#ifndef WITH_WSREP sys_header = trx_sysf_get(mtr); +#endif /* !WITH_WSREP */ if (mach_read_from_4(sys_header + field + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD) @@ -300,6 +316,124 @@ trx_sys_print_mysql_binlog_offset(void) mtr_commit(&mtr); } +#ifdef WITH_WSREP + +#ifdef UNIV_DEBUG +static long long trx_sys_cur_xid_seqno = -1; +static unsigned char trx_sys_cur_xid_uuid[16]; + +long long read_wsrep_xid_seqno(const XID* xid) +{ + long long seqno; + memcpy(&seqno, xid->data + 24, sizeof(long long)); + return seqno; +} + +void read_wsrep_xid_uuid(const XID* xid, unsigned char* buf) +{ + memcpy(buf, xid->data + 8, 16); +} + +#endif /* UNIV_DEBUG */ + +void +trx_sys_update_wsrep_checkpoint( + const XID* xid, /*!< in: transaction XID */ + trx_sysf_t* sys_header, /*!< in: sys_header */ + mtr_t* mtr) /*!< in: mtr */ +{ +#ifdef UNIV_DEBUG + { + /* Check that seqno is monotonically increasing */ + unsigned char xid_uuid[16]; + long long xid_seqno = read_wsrep_xid_seqno(xid); + read_wsrep_xid_uuid(xid, xid_uuid); + if (!memcmp(xid_uuid, trx_sys_cur_xid_uuid, 8)) + { + ut_ad(xid_seqno > trx_sys_cur_xid_seqno); + trx_sys_cur_xid_seqno = xid_seqno; + } + else + { + memcpy(trx_sys_cur_xid_uuid, xid_uuid, 16); + } + trx_sys_cur_xid_seqno = xid_seqno; + } +#endif /* UNIV_DEBUG */ + + ut_ad(xid && mtr); + ut_a(xid->formatID == -1 || wsrep_is_wsrep_xid((const void *)xid)); + + if (mach_read_from_4(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_MAGIC_N_FLD) + != TRX_SYS_WSREP_XID_MAGIC_N) { + mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_MAGIC_N_FLD, + TRX_SYS_WSREP_XID_MAGIC_N, + MLOG_4BYTES, mtr); + } + + mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_FORMAT, + (int)xid->formatID, + MLOG_4BYTES, mtr); + mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_GTRID_LEN, + (int)xid->gtrid_length, + MLOG_4BYTES, mtr); + mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_BQUAL_LEN, + (int)xid->bqual_length, + MLOG_4BYTES, mtr); + mlog_write_string(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_DATA, + (const unsigned char*) xid->data, + XIDDATASIZE, mtr); + +} + +void +trx_sys_read_wsrep_checkpoint(XID* xid) +/*===================================*/ +{ + trx_sysf_t* sys_header; + mtr_t mtr; + ulint magic; + + ut_ad(xid); + + mtr_start(&mtr); + + sys_header = trx_sysf_get(&mtr); + + if ((magic = mach_read_from_4(sys_header + TRX_SYS_WSREP_XID_INFO + + TRX_SYS_WSREP_XID_MAGIC_N_FLD)) + != TRX_SYS_WSREP_XID_MAGIC_N) { + memset(xid, 0, sizeof(*xid)); + xid->formatID = -1; + trx_sys_update_wsrep_checkpoint(xid, sys_header, &mtr); + mtr_commit(&mtr); + return; + } + + xid->formatID = (int)mach_read_from_4( + sys_header + + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_FORMAT); + xid->gtrid_length = (int)mach_read_from_4( + sys_header + + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_GTRID_LEN); + xid->bqual_length = (int)mach_read_from_4( + sys_header + + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_BQUAL_LEN); + ut_memcpy(xid->data, + sys_header + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_DATA, + XIDDATASIZE); + + mtr_commit(&mtr); +} + +#endif /* WITH_WSREP */ + /*****************************************************************//** Prints to stderr the MySQL master log offset info in the trx system header if the magic number shows it valid. */ diff --git a/storage/xtradb/trx/trx0trx.cc b/storage/xtradb/trx/trx0trx.cc index f2c78bafd86..d26517637cd 100644 --- a/storage/xtradb/trx/trx0trx.cc +++ b/storage/xtradb/trx/trx0trx.cc @@ -294,6 +294,9 @@ trx_create(void) trx->lock.table_locks = ib_vector_create( heap_alloc, sizeof(void**), 32); +#ifdef WITH_WSREP + trx->wsrep_event = NULL; +#endif /* WITH_WSREP */ return(trx); } @@ -1041,6 +1044,11 @@ trx_start_low( srv_undo_logs, srv_undo_tablespaces); } +#ifdef WITH_WSREP + memset(&trx->xid, 0, sizeof(trx->xid)); + trx->xid.formatID = -1; +#endif /* WITH_WSREP */ + /* The initial value for trx->no: TRX_ID_MAX is used in read_view_open_now: */ @@ -1166,6 +1174,9 @@ trx_write_serialisation_history( trx_t* trx, /*!< in/out: transaction */ mtr_t* mtr) /*!< in/out: mini-transaction */ { +#ifdef WITH_WSREP + trx_sysf_t* sys_header; +#endif /* WITH_WSREP */ trx_rseg_t* rseg; rseg = trx->rseg; @@ -1212,6 +1223,15 @@ trx_write_serialisation_history( MONITOR_INC(MONITOR_TRX_COMMIT_UNDO); +#ifdef WITH_WSREP + sys_header = trx_sysf_get(mtr); + /* Update latest MySQL wsrep XID in trx sys header. */ + if (wsrep_is_wsrep_xid((const void *)&trx->xid)) + { + trx_sys_update_wsrep_checkpoint(&trx->xid, sys_header, mtr); + } +#endif /* WITH_WSREP */ + /* Update the latest MySQL binlog name and offset info in trx sys header if MySQL binlogging is on or the database server is a MySQL replication slave */ @@ -1222,7 +1242,11 @@ trx_write_serialisation_history( trx_sys_update_mysql_binlog_offset( trx->mysql_log_file_name, trx->mysql_log_offset, - TRX_SYS_MYSQL_LOG_INFO, mtr); + TRX_SYS_MYSQL_LOG_INFO, +#ifdef WITH_WSREP + sys_header, +#endif /* WITH_WSREP */ + mtr); trx->mysql_log_file_name = NULL; } @@ -1527,6 +1551,11 @@ trx_commit_in_memory( ut_ad(!trx->in_ro_trx_list); ut_ad(!trx->in_rw_trx_list); +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd)) { + trx->lock.was_chosen_as_deadlock_victim = FALSE; + } +#endif trx->dict_operation = TRX_DICT_OP_NONE; trx->error_state = DB_SUCCESS; @@ -1709,6 +1738,10 @@ trx_commit_or_rollback_prepare( switch (trx->state) { case TRX_STATE_NOT_STARTED: +#ifdef WITH_WSREP + ut_d(trx->start_file = __FILE__); + ut_d(trx->start_line = __LINE__); +#endif /* WITH_WSREP */ trx_start_low(trx); /* fall through */ case TRX_STATE_ACTIVE: @@ -2480,6 +2513,10 @@ trx_start_if_not_started_low( { switch (trx->state) { case TRX_STATE_NOT_STARTED: +#ifdef WITH_WSREP + ut_d(trx->start_file = __FILE__); + ut_d(trx->start_line = __LINE__); +#endif /* WITH_WSREP */ trx_start_low(trx); /* fall through */ case TRX_STATE_ACTIVE: @@ -2514,6 +2551,10 @@ trx_start_for_ddl_low( trx->ddl = true; +#ifdef WITH_WSREP + ut_d(trx->start_file = __FILE__); + ut_d(trx->start_line = __LINE__); +#endif /* WITH_WSREP */ trx_start_low(trx); return; diff --git a/storage/xtradb/wsrep/md5.cc b/storage/xtradb/wsrep/md5.cc new file mode 100644 index 00000000000..30be6ab7dd3 --- /dev/null +++ b/storage/xtradb/wsrep/md5.cc @@ -0,0 +1,74 @@ +/* + Copyright (c) 2014 SkySQL AB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifdef WITH_WSREP + +#if defined(HAVE_YASSL) +#include "my_config.h" +#include "md5.hpp" +#elif defined(HAVE_OPENSSL) +#include +#endif /* HAVE_YASSL */ + +/* Initialize md5 object. */ +void *wsrep_md5_init() +{ +#if defined(HAVE_YASSL) + TaoCrypt::MD5 *hasher= new TaoCrypt::MD5; + return (void*)hasher; +#elif defined(HAVE_OPENSSL) + MD5_CTX *ctx = new MD5_CTX(); + MD5_Init (ctx); + return (void *)ctx; +#endif /* HAVE_YASSL */ +} + +/** + Supply message to be hashed. + + @param ctx [IN] Pointer to MD5 context + @param buf [IN] Message to be computed. + @param len [IN] Length of the message. +*/ +void wsrep_md5_update(void *ctx, char* buf, int len) +{ +#if defined(HAVE_YASSL) + ((TaoCrypt::MD5 *)ctx)->Update((TaoCrypt::byte *) buf, len); +#elif defined(HAVE_OPENSSL) + MD5_Update((MD5_CTX*)(ctx), buf, len); +#endif /* HAVE_YASSL */ +} + +/** + Place computed MD5 digest into the given buffer. + + @param digest [OUT] Computed MD5 digest + @param ctx [IN] Pointer to MD5 context +*/ +void wsrep_compute_md5_hash(char *digest, void *ctx) +{ +#if defined(HAVE_YASSL) + ((TaoCrypt::MD5*)ctx)->Final((TaoCrypt::byte *) digest); + delete (TaoCrypt::MD5*)ctx; +#elif defined(HAVE_OPENSSL) + MD5_Final ((unsigned char*)digest, (MD5_CTX*)ctx); + delete (MD5_CTX*)ctx; +#endif /* HAVE_YASSL */ +} + +#endif /* WITH_WSREP */ + diff --git a/storage/xtradb/wsrep/wsrep_md5.h b/storage/xtradb/wsrep/wsrep_md5.h new file mode 100644 index 00000000000..1339f7f4b86 --- /dev/null +++ b/storage/xtradb/wsrep/wsrep_md5.h @@ -0,0 +1,26 @@ +#ifndef WSREP_MD5_INCLUDED +#define WSREP_MD5_INCLUDED + +/* Copyright (c) 2014 SkySQL AB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +*/ + +#ifdef WITH_WSREP +void *wsrep_md5_init(); +void wsrep_md5_update(void *ctx, char* buf, int len); +void wsrep_compute_md5_hash(char *digest, void *ctx); +#endif /* WITH_WSREP */ + +#endif /* WSREP_MD5_INCLUDED */ diff --git a/support-files/CMakeLists.txt b/support-files/CMakeLists.txt index 698d06d1889..19f6bc14663 100644 --- a/support-files/CMakeLists.txt +++ b/support-files/CMakeLists.txt @@ -41,7 +41,7 @@ ELSE() SET(inst_location ${INSTALL_SUPPORTFILESDIR}) ENDIF() -FOREACH(inifile my-huge my-innodb-heavy-4G my-large my-medium my-small) +FOREACH(inifile my-huge my-innodb-heavy-4G my-large my-medium my-small wsrep) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/${inifile}.cnf.sh ${CMAKE_CURRENT_BINARY_DIR}/${inifile}.${ini_file_extension} @ONLY) INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${inifile}.${ini_file_extension} @@ -65,6 +65,7 @@ IF(UNIX) IF(INSTALL_SUPPORTFILESDIR) INSTALL(FILES magic DESTINATION ${inst_location} COMPONENT SupportFiles) INSTALL(DIRECTORY RHEL4-SElinux/ DESTINATION ${inst_location}/SELinux/RHEL4 COMPONENT SupportFiles) + INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/wsrep_notify DESTINATION ${inst_location} COMPONENT SupportFiles) ENDIF() INSTALL(FILES mysql.m4 DESTINATION ${INSTALL_SHAREDIR}/aclocal COMPONENT Development) diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh index a1ee5c4c653..c98c8284a97 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -253,6 +253,8 @@ wait_for_gone () { wait_for_ready () { + sst_progress_file=$datadir/sst_in_progress + i=0 while test $i -ne $service_startup_timeout ; do @@ -261,6 +263,11 @@ wait_for_ready () { return 0 fi + if test -e $sst_progress_file && [ $startup_sleep -ne 10 ];then + echo $echo_n "SST in progress, setting sleep higher" + startup_sleep=10 + fi + echo $echo_n ".$echo_c" i=`expr $i + 1` sleep 1 @@ -349,7 +356,10 @@ case "$mode" in # Stop the service and regardless of whether it was # running or not, start it again. if $0 stop $other_args; then - $0 start $other_args + if ! $0 start $other_args; then + log_failure_msg "Failed to restart server." + exit 1 + fi else log_failure_msg "Failed to stop running server, so refusing to try to start." exit 1 @@ -426,10 +436,16 @@ case "$mode" in fi exit $r ;; + 'bootstrap') + # Bootstrap the cluster, start the first node + # that initiate the cluster + echo $echo_n "Bootstrapping the cluster" + $0 start $other_args --wsrep-new-cluster + ;; *) # usage basename=`basename "$0"` - echo "Usage: $basename {start|stop|restart|reload|force-reload|status|configtest} [ MySQL server options ]" + echo "Usage: $basename {start|stop|restart|reload|force-reload|status|configtest|bootstrap} [ MySQL server options ]" exit 1 ;; esac diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index d8de3a41e7f..0a158b4fe49 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -68,6 +68,14 @@ # $ rpmbuild --define="option " ... # +# ---------------------------------------------------------------------------- +# wsrep builds +# ---------------------------------------------------------------------------- +%if %{defined with_wsrep} +%define mysql_version @VERSION@_wsrep_@WSREP_API_VERSION@.@WSREP_PATCH_VERSION@ +%define wsrep_version @WSREP_VERSION@ +%endif + # ---------------------------------------------------------------------------- # Commercial builds # ---------------------------------------------------------------------------- @@ -283,9 +291,16 @@ documentation and the manual for more information. ############################################################################## %package -n MySQL-server%{product_suffix} +%if %{defined with_wsrep} +Version: %{mysql_version} +%endif Summary: MySQL: a very fast and reliable SQL database server Group: Applications/Databases +%if %{defined with_wsrep} +Requires: %{distro_requires} rsync lsof +%else Requires: %{distro_requires} +%endif %if 0%{?commercial} Obsoletes: MySQL-server %else @@ -319,6 +334,9 @@ and the manual for more information. This package includes the MySQL server binary as well as related utilities to run and administer a MySQL server. +%if %{defined with_wsrep} +Built with wsrep patch %{wsrep_version}. +%endif If you want to access and work with the database, you have to install package "MySQL-client%{product_suffix}" as well! @@ -410,6 +428,7 @@ This package contains the shared libraries (*.so*) which certain languages and applications need to dynamically load and use MySQL. # ---------------------------------------------------------------------------- +%if %{undefined with_wsrep} %package -n MySQL-embedded%{product_suffix} Summary: MySQL - Embedded library Group: Applications/Databases @@ -439,6 +458,7 @@ The API is identical for the embedded MySQL version and the client/server version. For a description of MySQL see the base MySQL RPM or http://www.mysql.com/ +%endif ############################################################################## %prep @@ -514,6 +534,9 @@ mkdir debug -DMYSQL_UNIX_ADDR="%{mysqldatadir}/mysql.sock" \ -DFEATURE_SET="%{feature_set}" \ -DCOMPILATION_COMMENT="%{compilation_comment_debug}" \ +%if %{defined with_wsrep} + -DWITH_WSREP=1 \ +%endif -DMYSQL_SERVER_SUFFIX="%{server_suffix}" echo BEGIN_DEBUG_CONFIG ; egrep '^#define' include/config.h ; echo END_DEBUG_CONFIG make ${MAKE_JFLAG} VERBOSE=1 @@ -529,6 +552,9 @@ mkdir release -DMYSQL_UNIX_ADDR="%{mysqldatadir}/mysql.sock" \ -DFEATURE_SET="%{feature_set}" \ -DCOMPILATION_COMMENT="%{compilation_comment_release}" \ +%if %{defined with_wsrep} + -DWITH_WSREP=1 \ +%endif -DMYSQL_SERVER_SUFFIX="%{server_suffix}" echo BEGIN_NORMAL_CONFIG ; egrep '^#define' include/config.h ; echo END_NORMAL_CONFIG make ${MAKE_JFLAG} VERBOSE=1 @@ -591,11 +617,20 @@ install -m 755 $MBD/release/support-files/mysql.server $RBR%{_sysconfdir}/init.d # Create a symlink "rcmysql", pointing to the init.script. SuSE users # will appreciate that, as all services usually offer this. -ln -s %{_sysconfdir}/init.d/mysql $RBR%{_sbindir}/rcmysql +ln -sf %{_sysconfdir}/init.d/mysql $RBR%{_sbindir}/rcmysql + +%if %{defined with_wsrep} +# Create a wsrep_sst_rsync_wan symlink. +install -d $RBR%{_bindir} +ln -sf wsrep_sst_rsync $RBR%{_bindir}/wsrep_sst_rsync_wan +%endif # Touch the place where the my.cnf config file might be located # Just to make sure it's in the file list and marked as a config file touch $RBR%{_sysconfdir}/my.cnf +%if %{defined with_wsrep} +touch $RBR%{_sysconfdir}/wsrep.cnf +%endif # Install SELinux files in datadir install -m 600 $MBD/%{src_dir}/support-files/RHEL4-SElinux/mysql.{fc,te} \ @@ -1057,6 +1092,11 @@ echo "=====" >> $STATUS_HISTORY %doc %{src_dir}/Docs/INFO_SRC* %doc release/Docs/INFO_BIN* %doc release/support-files/my-*.cnf +%if %{defined with_wsrep} +%doc %{src_dir}/Docs/README-wsrep +%doc release/support-files/wsrep.cnf +%doc release/support-files/wsrep_notify +%endif %if 0%{?commercial} %doc %attr(644, root, root) %{_infodir}/mysql.info* @@ -1092,6 +1132,9 @@ echo "=====" >> $STATUS_HISTORY %doc %attr(644, root, man) %{_mandir}/man1/resolveip.1* %ghost %config(noreplace,missingok) %{_sysconfdir}/my.cnf +%if %{defined with_wsrep} +%ghost %config(noreplace,missingok) %{_sysconfdir}/wsrep.cnf +%endif %attr(755, root, root) %{_bindir}/innochecksum %attr(755, root, root) %{_bindir}/my_print_defaults @@ -1118,6 +1161,14 @@ echo "=====" >> $STATUS_HISTORY %attr(755, root, root) %{_bindir}/replace %attr(755, root, root) %{_bindir}/resolve_stack_dump %attr(755, root, root) %{_bindir}/resolveip +%if %{defined with_wsrep} +%attr(755, root, root) %{_bindir}/wsrep_sst_common +%attr(755, root, root) %{_bindir}/wsrep_sst_mysqldump +%attr(755, root, root) %{_bindir}/wsrep_sst_rsync +%attr(755, root, root) %{_bindir}/wsrep_sst_rsync_wan +%attr(755, root, root) %{_bindir}/wsrep_sst_xtrabackup +%attr(755, root, root) %{_bindir}/wsrep_sst_xtrabackup-v2 +%endif %attr(755, root, root) %{_sbindir}/mysqld %attr(755, root, root) %{_sbindir}/mysqld-debug @@ -1196,8 +1247,10 @@ echo "=====" >> $STATUS_HISTORY %defattr(-, root, root, 0755) %attr(-, root, root) %{_datadir}/mysql-test %attr(755, root, root) %{_bindir}/mysql_client_test +%if %{undefined with_wsrep} %attr(755, root, root) %{_bindir}/mysql_client_test_embedded %attr(755, root, root) %{_bindir}/mysqltest_embedded +%endif %doc %attr(644, root, man) %{_mandir}/man1/mysql_client_test.1* %doc %attr(644, root, man) %{_mandir}/man1/mysql-stress-test.pl.1* %doc %attr(644, root, man) %{_mandir}/man1/mysql-test-run.pl.1* @@ -1205,11 +1258,13 @@ echo "=====" >> $STATUS_HISTORY %doc %attr(644, root, man) %{_mandir}/man1/mysqltest_embedded.1* # ---------------------------------------------------------------------------- +%if %{undefined with_wsrep} %files -n MySQL-embedded%{product_suffix} %defattr(-, root, root, 0755) %attr(755, root, root) %{_bindir}/mysql_embedded %attr(644, root, root) %{_libdir}/mysql/libmysqld.a %attr(644, root, root) %{_libdir}/mysql/libmysqld-debug.a +%endif ############################################################################## # The spec file changelog only includes changes made to the spec file @@ -1241,6 +1296,10 @@ echo "=====" >> $STATUS_HISTORY - Make sure newly added "SPECIFIC-ULN/" directory does not disturb packaging. +* Wed Dec 07 2011 Alexey Yurchenko + +- wsrep-related cleanups. + * Wed Sep 28 2011 Joerg Bruehe - Fix duplicate mentioning of "mysql_plugin" and its manual page, diff --git a/support-files/rpm/server.cnf b/support-files/rpm/server.cnf index fb52635d4d8..6170a2e4c49 100644 --- a/support-files/rpm/server.cnf +++ b/support-files/rpm/server.cnf @@ -11,6 +11,22 @@ # this is only for the mysqld standalone daemon [mysqld] +# +# * Galera-related settings +# +[galera] +# Mandatory settings +#wsrep_provider= +#wsrep_cluster_address= +#wsrep_slave_threads=1 +#binlog_format=row +#default_storage_engine=InnoDB +#innodb_autoinc_lock_mode=2 +#query_cache_size=0 +# +# Optional setting +#innodb_flush_log_at_trx_commit=0 + # this is only for embedded server [embedded] diff --git a/support-files/wsrep.cnf b/support-files/wsrep.cnf new file mode 100644 index 00000000000..756d4f6783b --- /dev/null +++ b/support-files/wsrep.cnf @@ -0,0 +1,129 @@ +# This file contains wsrep-related mysqld options. It should be included +# in the main MySQL configuration file. +# +# Options that need to be customized: +# - wsrep_provider +# - wsrep_cluster_address +# - wsrep_sst_auth +# The rest of defaults should work out of the box. + +## +## mysqld options _MANDATORY_ for correct opration of the cluster +## +[mysqld] + +# (This must be substituted by wsrep_format) +binlog_format=ROW + +# Currently only InnoDB storage engine is supported +default-storage-engine=innodb + +# to avoid issues with 'bulk mode inserts' using autoinc +innodb_autoinc_lock_mode=2 + +# This is a must for paralell applying +innodb_locks_unsafe_for_binlog=1 + +# Query Cache is not supported with wsrep +query_cache_size=0 +query_cache_type=0 + +# Override bind-address +# In some systems bind-address defaults to 127.0.0.1, and with mysqldump SST +# it will have (most likely) disastrous consequences on donor node +bind-address=0.0.0.0 + +## +## WSREP options +## + +# Full path to wsrep provider library or 'none' +wsrep_provider=none + +# Provider specific configuration options +#wsrep_provider_options= + +# Logical cluster name. Should be the same for all nodes. +wsrep_cluster_name="my_wsrep_cluster" + +# Group communication system handle +#wsrep_cluster_address="dummy://" + +# Human-readable node name (non-unique). Hostname by default. +#wsrep_node_name= + +# Base replication [:port] of the node. +# The values supplied will be used as defaults for state transfer receiving, +# listening ports and so on. Default: address of the first network interface. +#wsrep_node_address= + +# Address for incoming client connections. Autodetect by default. +#wsrep_node_incoming_address= + +# How many threads will process writesets from other nodes +wsrep_slave_threads=1 + +# DBUG options for wsrep provider +#wsrep_dbug_option + +# Generate fake primary keys for non-PK tables (required for multi-master +# and parallel applying operation) +wsrep_certify_nonPK=1 + +# Maximum number of rows in write set +wsrep_max_ws_rows=131072 + +# Maximum size of write set +wsrep_max_ws_size=1073741824 + +# to enable debug level logging, set this to 1 +wsrep_debug=0 + +# convert locking sessions into transactions +wsrep_convert_LOCK_to_trx=0 + +# how many times to retry deadlocked autocommits +wsrep_retry_autocommit=1 + +# change auto_increment_increment and auto_increment_offset automatically +wsrep_auto_increment_control=1 + +# retry autoinc insert, which failed for duplicate key error +wsrep_drupal_282555_workaround=0 + +# enable "strictly synchronous" semantics for read operations +wsrep_causal_reads=0 + +# Command to call when node status or cluster membership changes. +# Will be passed all or some of the following options: +# --status - new status of this node +# --uuid - UUID of the cluster +# --primary - whether the component is primary or not ("yes"/"no") +# --members - comma-separated list of members +# --index - index of this node in the list +wsrep_notify_cmd= + +## +## WSREP State Transfer options +## + +# State Snapshot Transfer method +wsrep_sst_method=rsync + +# Address which donor should send State Snapshot to. +# Should be the address of THIS node. DON'T SET IT TO DONOR ADDRESS!!! +# (SST method dependent. Defaults to the first IP of the first interface) +#wsrep_sst_receive_address= + +# SST authentication string. This will be used to send SST to joining nodes. +# Depends on SST method. For mysqldump method it is root: +wsrep_sst_auth=root: + +# Desired SST donor name. +#wsrep_sst_donor= + +# Reject client queries when donating SST (false) +#wsrep_sst_donor_rejects_queries=0 + +# Protocol version to use +# wsrep_protocol_version= diff --git a/support-files/wsrep.cnf.sh b/support-files/wsrep.cnf.sh new file mode 100644 index 00000000000..756d4f6783b --- /dev/null +++ b/support-files/wsrep.cnf.sh @@ -0,0 +1,129 @@ +# This file contains wsrep-related mysqld options. It should be included +# in the main MySQL configuration file. +# +# Options that need to be customized: +# - wsrep_provider +# - wsrep_cluster_address +# - wsrep_sst_auth +# The rest of defaults should work out of the box. + +## +## mysqld options _MANDATORY_ for correct opration of the cluster +## +[mysqld] + +# (This must be substituted by wsrep_format) +binlog_format=ROW + +# Currently only InnoDB storage engine is supported +default-storage-engine=innodb + +# to avoid issues with 'bulk mode inserts' using autoinc +innodb_autoinc_lock_mode=2 + +# This is a must for paralell applying +innodb_locks_unsafe_for_binlog=1 + +# Query Cache is not supported with wsrep +query_cache_size=0 +query_cache_type=0 + +# Override bind-address +# In some systems bind-address defaults to 127.0.0.1, and with mysqldump SST +# it will have (most likely) disastrous consequences on donor node +bind-address=0.0.0.0 + +## +## WSREP options +## + +# Full path to wsrep provider library or 'none' +wsrep_provider=none + +# Provider specific configuration options +#wsrep_provider_options= + +# Logical cluster name. Should be the same for all nodes. +wsrep_cluster_name="my_wsrep_cluster" + +# Group communication system handle +#wsrep_cluster_address="dummy://" + +# Human-readable node name (non-unique). Hostname by default. +#wsrep_node_name= + +# Base replication [:port] of the node. +# The values supplied will be used as defaults for state transfer receiving, +# listening ports and so on. Default: address of the first network interface. +#wsrep_node_address= + +# Address for incoming client connections. Autodetect by default. +#wsrep_node_incoming_address= + +# How many threads will process writesets from other nodes +wsrep_slave_threads=1 + +# DBUG options for wsrep provider +#wsrep_dbug_option + +# Generate fake primary keys for non-PK tables (required for multi-master +# and parallel applying operation) +wsrep_certify_nonPK=1 + +# Maximum number of rows in write set +wsrep_max_ws_rows=131072 + +# Maximum size of write set +wsrep_max_ws_size=1073741824 + +# to enable debug level logging, set this to 1 +wsrep_debug=0 + +# convert locking sessions into transactions +wsrep_convert_LOCK_to_trx=0 + +# how many times to retry deadlocked autocommits +wsrep_retry_autocommit=1 + +# change auto_increment_increment and auto_increment_offset automatically +wsrep_auto_increment_control=1 + +# retry autoinc insert, which failed for duplicate key error +wsrep_drupal_282555_workaround=0 + +# enable "strictly synchronous" semantics for read operations +wsrep_causal_reads=0 + +# Command to call when node status or cluster membership changes. +# Will be passed all or some of the following options: +# --status - new status of this node +# --uuid - UUID of the cluster +# --primary - whether the component is primary or not ("yes"/"no") +# --members - comma-separated list of members +# --index - index of this node in the list +wsrep_notify_cmd= + +## +## WSREP State Transfer options +## + +# State Snapshot Transfer method +wsrep_sst_method=rsync + +# Address which donor should send State Snapshot to. +# Should be the address of THIS node. DON'T SET IT TO DONOR ADDRESS!!! +# (SST method dependent. Defaults to the first IP of the first interface) +#wsrep_sst_receive_address= + +# SST authentication string. This will be used to send SST to joining nodes. +# Depends on SST method. For mysqldump method it is root: +wsrep_sst_auth=root: + +# Desired SST donor name. +#wsrep_sst_donor= + +# Reject client queries when donating SST (false) +#wsrep_sst_donor_rejects_queries=0 + +# Protocol version to use +# wsrep_protocol_version= diff --git a/support-files/wsrep.cnf.sh.moved b/support-files/wsrep.cnf.sh.moved new file mode 100644 index 00000000000..756d4f6783b --- /dev/null +++ b/support-files/wsrep.cnf.sh.moved @@ -0,0 +1,129 @@ +# This file contains wsrep-related mysqld options. It should be included +# in the main MySQL configuration file. +# +# Options that need to be customized: +# - wsrep_provider +# - wsrep_cluster_address +# - wsrep_sst_auth +# The rest of defaults should work out of the box. + +## +## mysqld options _MANDATORY_ for correct opration of the cluster +## +[mysqld] + +# (This must be substituted by wsrep_format) +binlog_format=ROW + +# Currently only InnoDB storage engine is supported +default-storage-engine=innodb + +# to avoid issues with 'bulk mode inserts' using autoinc +innodb_autoinc_lock_mode=2 + +# This is a must for paralell applying +innodb_locks_unsafe_for_binlog=1 + +# Query Cache is not supported with wsrep +query_cache_size=0 +query_cache_type=0 + +# Override bind-address +# In some systems bind-address defaults to 127.0.0.1, and with mysqldump SST +# it will have (most likely) disastrous consequences on donor node +bind-address=0.0.0.0 + +## +## WSREP options +## + +# Full path to wsrep provider library or 'none' +wsrep_provider=none + +# Provider specific configuration options +#wsrep_provider_options= + +# Logical cluster name. Should be the same for all nodes. +wsrep_cluster_name="my_wsrep_cluster" + +# Group communication system handle +#wsrep_cluster_address="dummy://" + +# Human-readable node name (non-unique). Hostname by default. +#wsrep_node_name= + +# Base replication [:port] of the node. +# The values supplied will be used as defaults for state transfer receiving, +# listening ports and so on. Default: address of the first network interface. +#wsrep_node_address= + +# Address for incoming client connections. Autodetect by default. +#wsrep_node_incoming_address= + +# How many threads will process writesets from other nodes +wsrep_slave_threads=1 + +# DBUG options for wsrep provider +#wsrep_dbug_option + +# Generate fake primary keys for non-PK tables (required for multi-master +# and parallel applying operation) +wsrep_certify_nonPK=1 + +# Maximum number of rows in write set +wsrep_max_ws_rows=131072 + +# Maximum size of write set +wsrep_max_ws_size=1073741824 + +# to enable debug level logging, set this to 1 +wsrep_debug=0 + +# convert locking sessions into transactions +wsrep_convert_LOCK_to_trx=0 + +# how many times to retry deadlocked autocommits +wsrep_retry_autocommit=1 + +# change auto_increment_increment and auto_increment_offset automatically +wsrep_auto_increment_control=1 + +# retry autoinc insert, which failed for duplicate key error +wsrep_drupal_282555_workaround=0 + +# enable "strictly synchronous" semantics for read operations +wsrep_causal_reads=0 + +# Command to call when node status or cluster membership changes. +# Will be passed all or some of the following options: +# --status - new status of this node +# --uuid - UUID of the cluster +# --primary - whether the component is primary or not ("yes"/"no") +# --members - comma-separated list of members +# --index - index of this node in the list +wsrep_notify_cmd= + +## +## WSREP State Transfer options +## + +# State Snapshot Transfer method +wsrep_sst_method=rsync + +# Address which donor should send State Snapshot to. +# Should be the address of THIS node. DON'T SET IT TO DONOR ADDRESS!!! +# (SST method dependent. Defaults to the first IP of the first interface) +#wsrep_sst_receive_address= + +# SST authentication string. This will be used to send SST to joining nodes. +# Depends on SST method. For mysqldump method it is root: +wsrep_sst_auth=root: + +# Desired SST donor name. +#wsrep_sst_donor= + +# Reject client queries when donating SST (false) +#wsrep_sst_donor_rejects_queries=0 + +# Protocol version to use +# wsrep_protocol_version= diff --git a/support-files/wsrep_notify b/support-files/wsrep_notify new file mode 100644 index 00000000000..bdbe3d12a39 --- /dev/null +++ b/support-files/wsrep_notify @@ -0,0 +1,102 @@ +#!/bin/sh -eu + +# This is a simple example of wsrep notification script (wsrep_notify_cmd). +# It will create 'wsrep' schema and two tables in it: 'membeship' and 'status' +# and fill them on every membership or node status change. +# +# Edit parameters below to specify the address and login to server. + +USER=root +PSWD=rootpass +HOST=127.0.0.1 +PORT=3306 + +SCHEMA="wsrep" +MEMB_TABLE="$SCHEMA.membership" +STATUS_TABLE="$SCHEMA.status" + +BEGIN=" +SET wsrep_on=0; +DROP SCHEMA IF EXISTS $SCHEMA; CREATE SCHEMA $SCHEMA; +CREATE TABLE $MEMB_TABLE ( + idx INT UNIQUE PRIMARY KEY, + uuid CHAR(40) UNIQUE, /* node UUID */ + name VARCHAR(32), /* node name */ + addr VARCHAR(256) /* node address */ +) ENGINE=MEMORY; +CREATE TABLE $STATUS_TABLE ( + size INT, /* component size */ + idx INT, /* this node index */ + status CHAR(16), /* this node status */ + uuid CHAR(40), /* cluster UUID */ + prim BOOLEAN /* if component is primary */ +) ENGINE=MEMORY; +BEGIN; +DELETE FROM $MEMB_TABLE; +DELETE FROM $STATUS_TABLE; +" +END="COMMIT;" + +configuration_change() +{ + echo "$BEGIN;" + + local idx=0 + + for NODE in $(echo $MEMBERS | sed s/,/\ /g) + do + echo "INSERT INTO $MEMB_TABLE VALUES ( $idx, " + # Don't forget to properly quote string values + echo "'$NODE'" | sed s/\\//\',\'/g + echo ");" + idx=$(( $idx + 1 )) + done + + echo "INSERT INTO $STATUS_TABLE VALUES($idx, $INDEX, '$STATUS', '$CLUSTER_UUID', $PRIMARY);" + + echo "$END" +} + +status_update() +{ + echo "SET wsrep_on=0; BEGIN; UPDATE $STATUS_TABLE SET status='$STATUS'; COMMIT;" +} + +COM=status_update # not a configuration change by default + +while [ $# -gt 0 ] +do + case $1 in + --status) + STATUS=$2 + shift + ;; + --uuid) + CLUSTER_UUID=$2 + shift + ;; + --primary) + [ "$2" = "yes" ] && PRIMARY="1" || PRIMARY="0" + COM=configuration_change + shift + ;; + --index) + INDEX=$2 + shift + ;; + --members) + MEMBERS=$2 + shift + ;; + esac + shift +done + +# Undefined means node is shutting down +if [ "$STATUS" != "Undefined" ] +then + $COM | mysql -B -u$USER -p$PSWD -h$HOST -P$PORT +fi + +exit 0 +# diff --git a/support-files/wsrep_notify.sh b/support-files/wsrep_notify.sh new file mode 100644 index 00000000000..bdbe3d12a39 --- /dev/null +++ b/support-files/wsrep_notify.sh @@ -0,0 +1,102 @@ +#!/bin/sh -eu + +# This is a simple example of wsrep notification script (wsrep_notify_cmd). +# It will create 'wsrep' schema and two tables in it: 'membeship' and 'status' +# and fill them on every membership or node status change. +# +# Edit parameters below to specify the address and login to server. + +USER=root +PSWD=rootpass +HOST=127.0.0.1 +PORT=3306 + +SCHEMA="wsrep" +MEMB_TABLE="$SCHEMA.membership" +STATUS_TABLE="$SCHEMA.status" + +BEGIN=" +SET wsrep_on=0; +DROP SCHEMA IF EXISTS $SCHEMA; CREATE SCHEMA $SCHEMA; +CREATE TABLE $MEMB_TABLE ( + idx INT UNIQUE PRIMARY KEY, + uuid CHAR(40) UNIQUE, /* node UUID */ + name VARCHAR(32), /* node name */ + addr VARCHAR(256) /* node address */ +) ENGINE=MEMORY; +CREATE TABLE $STATUS_TABLE ( + size INT, /* component size */ + idx INT, /* this node index */ + status CHAR(16), /* this node status */ + uuid CHAR(40), /* cluster UUID */ + prim BOOLEAN /* if component is primary */ +) ENGINE=MEMORY; +BEGIN; +DELETE FROM $MEMB_TABLE; +DELETE FROM $STATUS_TABLE; +" +END="COMMIT;" + +configuration_change() +{ + echo "$BEGIN;" + + local idx=0 + + for NODE in $(echo $MEMBERS | sed s/,/\ /g) + do + echo "INSERT INTO $MEMB_TABLE VALUES ( $idx, " + # Don't forget to properly quote string values + echo "'$NODE'" | sed s/\\//\',\'/g + echo ");" + idx=$(( $idx + 1 )) + done + + echo "INSERT INTO $STATUS_TABLE VALUES($idx, $INDEX, '$STATUS', '$CLUSTER_UUID', $PRIMARY);" + + echo "$END" +} + +status_update() +{ + echo "SET wsrep_on=0; BEGIN; UPDATE $STATUS_TABLE SET status='$STATUS'; COMMIT;" +} + +COM=status_update # not a configuration change by default + +while [ $# -gt 0 ] +do + case $1 in + --status) + STATUS=$2 + shift + ;; + --uuid) + CLUSTER_UUID=$2 + shift + ;; + --primary) + [ "$2" = "yes" ] && PRIMARY="1" || PRIMARY="0" + COM=configuration_change + shift + ;; + --index) + INDEX=$2 + shift + ;; + --members) + MEMBERS=$2 + shift + ;; + esac + shift +done + +# Undefined means node is shutting down +if [ "$STATUS" != "Undefined" ] +then + $COM | mysql -B -u$USER -p$PSWD -h$HOST -P$PORT +fi + +exit 0 +# diff --git a/wsrep/CMakeLists.txt b/wsrep/CMakeLists.txt new file mode 100644 index 00000000000..d9e66739fcc --- /dev/null +++ b/wsrep/CMakeLists.txt @@ -0,0 +1,25 @@ +# Copyright (c) 2012, Codership Oy. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +INCLUDE_DIRECTORIES( "." ) +BUILD_WITH_WSREP() + +SET(WSREP_SOURCES wsrep_gtid.c wsrep_uuid.c wsrep_loader.c wsrep_dummy.c) + +ADD_CONVENIENCE_LIBRARY(wsrep ${WSREP_SOURCES}) +DTRACE_INSTRUMENT(wsrep) + +#ADD_EXECUTABLE(listener wsrep_listener.c ${WSREP_SOURCES}) +#TARGET_LINK_LIBRARIES(listener ${LIBDL}) diff --git a/wsrep/wsrep_api.h b/wsrep/wsrep_api.h new file mode 100644 index 00000000000..c3304d7ed7c --- /dev/null +++ b/wsrep/wsrep_api.h @@ -0,0 +1,1118 @@ +/* Copyright (C) 2009-2013 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/*! + @file wsrep API declaration. + + HOW TO READ THIS FILE. + + Due to C language rules this header layout doesn't lend itself to intuitive + reading. So here's the scoop: in the end this header declares two main types: + + * struct wsrep_init_args + + and + + * struct wsrep + + wsrep_init_args contains initialization parameters for wsrep provider like + names, addresses, etc. and pointers to callbacks. The callbacks will be called + by provider when it needs to do something application-specific, like log a + message or apply a writeset. It should be passed to init() call from + wsrep API. It is an application part of wsrep API contract. + + struct wsrep is the interface to wsrep provider. It contains all wsrep API + calls. It is a provider part of wsrep API contract. + + Finally, wsrep_load() method loads (dlopens) wsrep provider library. It is + defined in wsrep_loader.c unit and is part of libwsrep.a (which is not a + wsrep provider, but a convenience library). + + wsrep_unload() does the reverse. + +*/ +#ifndef WSREP_H +#define WSREP_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************** + * * + * wsrep replication API * + * * + **************************************************************************/ + +#define WSREP_INTERFACE_VERSION "25" + +/*! Empty backend spec */ +#define WSREP_NONE "none" + + +/*! + * @brief log severity levels, passed as first argument to log handler + */ +typedef enum wsrep_log_level +{ + WSREP_LOG_FATAL, //!< Unrecoverable error, application must quit. + WSREP_LOG_ERROR, //!< Operation failed, must be repeated. + WSREP_LOG_WARN, //!< Unexpected condition, but no operational failure. + WSREP_LOG_INFO, //!< Informational message. + WSREP_LOG_DEBUG //!< Debug message. Shows only of compiled with debug. +} wsrep_log_level_t; + +/*! + * @brief error log handler + * + * All messages from wsrep provider are directed to this + * handler, if present. + * + * @param level log level + * @param message log message + */ +typedef void (*wsrep_log_cb_t)(wsrep_log_level_t, const char *); + + +/*! + * Certain provider capabilities application may want to know about + */ +#define WSREP_CAP_MULTI_MASTER ( 1ULL << 0 ) +#define WSREP_CAP_CERTIFICATION ( 1ULL << 1 ) +#define WSREP_CAP_PARALLEL_APPLYING ( 1ULL << 2 ) +#define WSREP_CAP_TRX_REPLAY ( 1ULL << 3 ) +#define WSREP_CAP_ISOLATION ( 1ULL << 4 ) +#define WSREP_CAP_PAUSE ( 1ULL << 5 ) +#define WSREP_CAP_CAUSAL_READS ( 1ULL << 6 ) +#define WSREP_CAP_CAUSAL_TRX ( 1ULL << 7 ) +#define WSREP_CAP_INCREMENTAL_WRITESET ( 1ULL << 8 ) +#define WSREP_CAP_SESSION_LOCKS ( 1ULL << 9 ) +#define WSREP_CAP_DISTRIBUTED_LOCKS ( 1ULL << 10 ) +#define WSREP_CAP_CONSISTENCY_CHECK ( 1ULL << 11 ) +#define WSREP_CAP_UNORDERED ( 1ULL << 12 ) +#define WSREP_CAP_ANNOTATION ( 1ULL << 13 ) +#define WSREP_CAP_PREORDERED ( 1ULL << 14 ) + + +/*! + * Writeset flags + * + * COMMIT the writeset and all preceding writesets must be committed + * ROLLBACK all preceding writesets in a transaction must be rolled back + * ISOLATION the writeset must be applied AND committed in isolation + * PA_UNSAFE the writeset cannot be applied in parallel + * COMMUTATIVE the order in which the writeset is applied does not matter + * NATIVE the writeset contains another writeset in this provider format + * + * Note that some of the flags are mutually exclusive (e.g. COMMIT and + * ROLLBACK). + */ +#define WSREP_FLAG_COMMIT ( 1ULL << 0 ) +#define WSREP_FLAG_ROLLBACK ( 1ULL << 1 ) +#define WSREP_FLAG_ISOLATION ( 1ULL << 2 ) +#define WSREP_FLAG_PA_UNSAFE ( 1ULL << 3 ) +#define WSREP_FLAG_COMMUTATIVE ( 1ULL << 4 ) +#define WSREP_FLAG_NATIVE ( 1ULL << 5 ) + + +typedef uint64_t wsrep_trx_id_t; //!< application transaction ID +typedef uint64_t wsrep_conn_id_t; //!< application connection ID +typedef int64_t wsrep_seqno_t; //!< sequence number of a writeset, etc. +#ifdef __cplusplus +typedef bool wsrep_bool_t; +#else +typedef _Bool wsrep_bool_t; //!< should be the same as standard (C99) bool +#endif /* __cplusplus */ + +/*! undefined seqno */ +#define WSREP_SEQNO_UNDEFINED (-1) + + +/*! wsrep provider status codes */ +typedef enum wsrep_status +{ + WSREP_OK = 0, //!< success + WSREP_WARNING, //!< minor warning, error logged + WSREP_TRX_MISSING, //!< transaction is not known by wsrep + WSREP_TRX_FAIL, //!< transaction aborted, server can continue + WSREP_BF_ABORT, //!< trx was victim of brute force abort + WSREP_SIZE_EXCEEDED, //!< data exceeded maximum supported size + WSREP_CONN_FAIL, //!< error in client connection, must abort + WSREP_NODE_FAIL, //!< error in node state, wsrep must reinit + WSREP_FATAL, //!< fatal error, server must abort + WSREP_NOT_IMPLEMENTED //!< feature not implemented +} wsrep_status_t; + + +/*! wsrep callbacks status codes */ +typedef enum wsrep_cb_status +{ + WSREP_CB_SUCCESS = 0, //!< success (as in "not critical failure") + WSREP_CB_FAILURE //!< critical failure (consistency violation) + /* Technically, wsrep provider has no use for specific failure codes since + * there is nothing it can do about it but abort execution. Therefore any + * positive number shall indicate a critical failure. Optionally that value + * may be used by provider to come to a consensus about state consistency + * in a group of nodes. */ +} wsrep_cb_status_t; + + +/*! + * UUID type - for all unique IDs + */ +typedef struct wsrep_uuid { + uint8_t data[16]; +} wsrep_uuid_t; + +/*! Undefined UUID */ +static const wsrep_uuid_t WSREP_UUID_UNDEFINED = {{0,}}; + +/*! UUID string representation length, terminating '\0' not included */ +#define WSREP_UUID_STR_LEN 36 + +/*! + * Scan UUID from string + * @return length of UUID string representation or negative error code + */ +extern int +wsrep_uuid_scan (const char* str, size_t str_len, wsrep_uuid_t* uuid); + +/*! + * Print UUID to string + * @return length of UUID string representation or negative error code + */ +extern int +wsrep_uuid_print (const wsrep_uuid_t* uuid, char* str, size_t str_len); + +#define WSREP_MEMBER_NAME_LEN 32 //!< maximum logical member name length +#define WSREP_INCOMING_LEN 256 //!< max Domain Name length + 0x00 + + +/*! + * Global transaction identifier + */ +typedef struct wsrep_gtid +{ + wsrep_uuid_t uuid; /*!< History UUID */ + wsrep_seqno_t seqno; /*!< Sequence number */ +} wsrep_gtid_t; + +/*! Undefined GTID */ +static const wsrep_gtid_t WSREP_GTID_UNDEFINED = {{{0, }}, -1}; + +/*! Minimum number of bytes guaranteed to store GTID string representation, + * terminating '\0' not included (36 + 1 + 20) */ +#define WSREP_GTID_STR_LEN 57 + + +/*! + * Scan GTID from string + * @return length of GTID string representation or negative error code + */ +extern int +wsrep_gtid_scan(const char* str, size_t str_len, wsrep_gtid_t* gtid); + +/*! + * Print GTID to string + * @return length of GTID string representation or negative error code + */ +extern int +wsrep_gtid_print(const wsrep_gtid_t* gtid, char* str, size_t str_len); + + +/*! + * Transaction meta data + */ +typedef struct wsrep_trx_meta +{ + wsrep_gtid_t gtid; /*!< Global transaction identifier */ + wsrep_seqno_t depends_on; /*!< Sequence number part of the last transaction + this transaction depends on */ +} wsrep_trx_meta_t; + + +/*! + * member status + */ +typedef enum wsrep_member_status { + WSREP_MEMBER_UNDEFINED, //!< undefined state + WSREP_MEMBER_JOINER, //!< incomplete state, requested state transfer + WSREP_MEMBER_DONOR, //!< complete state, donates state transfer + WSREP_MEMBER_JOINED, //!< complete state + WSREP_MEMBER_SYNCED, //!< complete state, synchronized with group + WSREP_MEMBER_ERROR, //!< this and above is provider-specific error code + WSREP_MEMBER_MAX +} wsrep_member_status_t; + +/*! + * static information about a group member (some fields are tentative yet) + */ +typedef struct wsrep_member_info { + wsrep_uuid_t id; //!< group-wide unique member ID + char name[WSREP_MEMBER_NAME_LEN]; //!< human-readable name + char incoming[WSREP_INCOMING_LEN]; //!< address for client requests +} wsrep_member_info_t; + +/*! + * group status + */ +typedef enum wsrep_view_status { + WSREP_VIEW_PRIMARY, //!< primary group configuration (quorum present) + WSREP_VIEW_NON_PRIMARY, //!< non-primary group configuration (quorum lost) + WSREP_VIEW_DISCONNECTED, //!< not connected to group, retrying. + WSREP_VIEW_MAX +} wsrep_view_status_t; + +/*! + * view of the group + */ +typedef struct wsrep_view_info { + wsrep_gtid_t state_id; //!< global state ID + wsrep_seqno_t view; //!< global view number + wsrep_view_status_t status; //!< view status + wsrep_bool_t state_gap; //!< gap between global and local states + int my_idx; //!< index of this member in the view + int memb_num; //!< number of members in the view + int proto_ver; //!< application protocol agreed on the view + wsrep_member_info_t members[1];//!< array of member information +} wsrep_view_info_t; + +/*! + * Magic string to tell provider to engage into trivial (empty) state transfer. + * No data will be passed, but the node shall be considered JOINED. + * Should be passed in sst_req parameter of wsrep_view_cb_t. + */ +#define WSREP_STATE_TRANSFER_TRIVIAL "trivial" + +/*! + * Magic string to tell provider not to engage in state transfer at all. + * The member will stay in WSREP_MEMBER_UNDEFINED state but will keep on + * receiving all writesets. + * Should be passed in sst_req parameter of wsrep_view_cb_t. + */ +#define WSREP_STATE_TRANSFER_NONE "none" + +/*! + * @brief group view handler + * + * This handler is called in total order corresponding to the group + * configuration change. It is to provide a vital information about + * new group view. If view info indicates existence of discontinuity + * between group and member states, state transfer request message + * should be filled in by the callback implementation. + * + * @note Currently it is assumed that sst_req is allocated using + * malloc()/calloc()/realloc() and it will be freed by + * wsrep implementation. + * + * @param app_ctx application context + * @param recv_ctx receiver context + * @param view new view on the group + * @param state current state + * @param state_len lenght of current state + * @param sst_req location to store SST request + * @param sst_req_len location to store SST request length or error code, + * value of 0 means no SST. + */ +typedef enum wsrep_cb_status (*wsrep_view_cb_t) ( + void* app_ctx, + void* recv_ctx, + const wsrep_view_info_t* view, + const char* state, + size_t state_len, + void** sst_req, + size_t* sst_req_len +); + + +/*! + * @brief apply callback + * + * This handler is called from wsrep library to apply replicated writeset + * Must support brute force applying for multi-master operation + * + * @param recv_ctx receiver context pointer provided by the application + * @param data data buffer containing the writeset + * @param size data buffer size + * @param flags WSREP_FLAG_... flags + * @param meta transaction meta data of the writeset to be applied + * + * @return success code: + * @retval WSREP_OK + * @retval WSREP_NOT_IMPLEMENTED appl. does not support the writeset format + * @retval WSREP_ERROR failed to apply the writeset + */ +typedef enum wsrep_cb_status (*wsrep_apply_cb_t) ( + void* recv_ctx, + const void* data, + size_t size, + uint32_t flags, + const wsrep_trx_meta_t* meta +); + + +/*! + * @brief commit callback + * + * This handler is called to commit the changes made by apply callback. + * + * @param recv_ctx receiver context pointer provided by the application + * @param flags WSREP_FLAG_... flags + * @param meta transaction meta data of the writeset to be committed + * @param exit set to true to exit recv loop + * @param commit true - commit writeset, false - rollback writeset + * + * @return success code: + * @retval WSREP_OK + * @retval WSREP_ERROR call failed + */ +typedef enum wsrep_cb_status (*wsrep_commit_cb_t) ( + void* recv_ctx, + uint32_t flags, + const wsrep_trx_meta_t* meta, + wsrep_bool_t* exit, + wsrep_bool_t commit +); + + +/*! + * @brief unordered callback + * + * This handler is called to execute unordered actions (actions that need not + * to be executed in any particular order) attached to writeset. + * + * @param recv_ctx receiver context pointer provided by the application + * @param data data buffer containing the writeset + * @param size data buffer size + */ +typedef enum wsrep_cb_status (*wsrep_unordered_cb_t) ( + void* recv_ctx, + const void* data, + size_t size +); + + +/*! + * @brief a callback to donate state snapshot + * + * This handler is called from wsrep library when it needs this node + * to deliver state to a new cluster member. + * No state changes will be committed for the duration of this call. + * Wsrep implementation may provide internal state to be transmitted + * to new cluster member for initial state. + * + * @param app_ctx application context + * @param recv_ctx receiver context + * @param msg state transfer request message + * @param msg_len state transfer request message length + * @param gtid current state ID on this node + * @param state current wsrep internal state buffer + * @param state_len current wsrep internal state buffer len + * @param bypass bypass snapshot transfer, only transfer uuid:seqno pair + */ +typedef enum wsrep_cb_status (*wsrep_sst_donate_cb_t) ( + void* app_ctx, + void* recv_ctx, + const void* msg, + size_t msg_len, + const wsrep_gtid_t* state_id, + const char* state, + size_t state_len, + wsrep_bool_t bypass +); + + +/*! + * @brief a callback to signal application that wsrep state is synced + * with cluster + * + * This callback is called after wsrep library has got in sync with + * rest of the cluster. + * + * @param app_ctx application context + */ +typedef void (*wsrep_synced_cb_t) (void* app_ctx); + + +/*! + * Initialization parameters for wsrep provider. + */ +struct wsrep_init_args +{ + void* app_ctx; //!< Application context for callbacks + + /* Configuration parameters */ + const char* node_name; //!< Symbolic name of this node (e.g. hostname) + const char* node_address; //!< Address to be used by wsrep provider + const char* node_incoming; //!< Address for incoming client connections + const char* data_dir; //!< Directory where wsrep files are kept if any + const char* options; //!< Provider-specific configuration string + int proto_ver; //!< Max supported application protocol version + + /* Application initial state information. */ + const wsrep_gtid_t* state_id; //!< Application state GTID + const char* state; //!< Initial state for wsrep provider + size_t state_len; //!< Length of state buffer + + /* Application callbacks */ + wsrep_log_cb_t logger_cb; //!< logging handler + wsrep_view_cb_t view_handler_cb; //!< group view change handler + + /* Applier callbacks */ + wsrep_apply_cb_t apply_cb; //!< apply callback + wsrep_commit_cb_t commit_cb; //!< commit callback + wsrep_unordered_cb_t unordered_cb; //!< callback for unordered actions + + /* State Snapshot Transfer callbacks */ + wsrep_sst_donate_cb_t sst_donate_cb; //!< starting to donate + wsrep_synced_cb_t synced_cb; //!< synced with group +}; + + +/*! Type of the stats variable value in struct wsrep_status_var */ +typedef enum wsrep_var_type +{ + WSREP_VAR_STRING, //!< pointer to null-terminated string + WSREP_VAR_INT64, //!< int64_t + WSREP_VAR_DOUBLE //!< double +} +wsrep_var_type_t; + +/*! Generalized stats variable representation */ +struct wsrep_stats_var +{ + const char* name; //!< variable name + wsrep_var_type_t type; //!< variable value type + union { + int64_t _int64; + double _double; + const char* _string; + } value; //!< variable value +}; + + +/*! Abstract data buffer structure */ +typedef struct wsrep_buf +{ + const void* ptr; /*!< Pointer to data buffer */ + size_t len; /*!< Length of buffer */ +} wsrep_buf_t; + +/*! Key struct used to pass certification keys for transaction handling calls. + * A key consists of zero or more key parts. */ +typedef struct wsrep_key +{ + const wsrep_buf_t* key_parts; /*!< Array of key parts */ + size_t key_parts_num; /*!< Number of key parts */ +} wsrep_key_t; + +/*! Key type: + * EXCLUSIVE conflicts with any key type + * SEMI reserved. If not supported, should be interpeted as EXCLUSIVE + * SHARED conflicts only with EXCLUSIVE keys */ +typedef enum wsrep_key_type +{ + WSREP_KEY_SHARED = 0, + WSREP_KEY_SEMI, + WSREP_KEY_EXCLUSIVE +} wsrep_key_type_t; + +/*! Data type: + * ORDERED state modification event that should be applied and committed + * in order. + * UNORDERED some action that does not modify state and execution of which is + * optional and does not need to happen in order. + * ANNOTATION (human readable) writeset annotation. */ +typedef enum wsrep_data_type +{ + WSREP_DATA_ORDERED = 0, + WSREP_DATA_UNORDERED, + WSREP_DATA_ANNOTATION +} wsrep_data_type_t; + + +/*! Transaction handle struct passed for wsrep transaction handling calls */ +typedef struct wsrep_ws_handle +{ + wsrep_trx_id_t trx_id; //!< transaction ID + void* opaque; //!< opaque provider transaction context data +} wsrep_ws_handle_t; + +/*! + * @brief Helper method to reset trx writeset handle state when trx id changes + * + * Instead of passing wsrep_ws_handle_t directly to wsrep calls, + * wrapping handle with this call offloads bookkeeping from + * application. + */ +static inline wsrep_ws_handle_t* wsrep_ws_handle_for_trx( + wsrep_ws_handle_t* ws_handle, + wsrep_trx_id_t trx_id) +{ + if (ws_handle->trx_id != trx_id) + { + ws_handle->trx_id = trx_id; + ws_handle->opaque = NULL; + } + return ws_handle; +} + + +/*! + * A handle for processing preordered actions. + * Must be initialized to WSREP_PO_INITIALIZER before use. + */ +typedef struct wsrep_po_handle { void* opaque; } wsrep_po_handle_t; + +static const wsrep_po_handle_t WSREP_PO_INITIALIZER = { NULL }; + + +typedef struct wsrep wsrep_t; +/*! + * wsrep interface for dynamically loadable libraries + */ +struct wsrep { + + const char *version; //!< interface version string + + /*! + * @brief Initializes wsrep provider + * + * @param wsrep provider handle + * @param args wsrep initialization parameters + */ + wsrep_status_t (*init) (wsrep_t* wsrep, + const struct wsrep_init_args* args); + + /*! + * @brief Returns provider capabilities flag bitmap + * + * @param wsrep provider handle + */ + uint64_t (*capabilities) (wsrep_t* wsrep); + + /*! + * @brief Passes provider-specific configuration string to provider. + * + * @param wsrep provider handle + * @param conf configuration string + * + * @retval WSREP_OK configuration string was parsed successfully + * @retval WSREP_WARNING could't not parse conf string, no action taken + */ + wsrep_status_t (*options_set) (wsrep_t* wsrep, const char* conf); + + /*! + * @brief Returns provider-specific string with current configuration values. + * + * @param wsrep provider handle + * + * @return a dynamically allocated string with current configuration + * parameter values + */ + char* (*options_get) (wsrep_t* wsrep); + + /*! + * @brief Opens connection to cluster + * + * Returns when either node is ready to operate as a part of the clsuter + * or fails to reach operating status. + * + * @param wsrep provider handle + * @param cluster_name unique symbolic cluster name + * @param cluster_url URL-like cluster address (backend://address) + * @param state_donor name of the node to be asked for state transfer. + * @param bootstrap a flag to request initialization of a new wsrep + * service rather then a connection to the existing one. + * clister_url may still carry important initialization + * parameters, like backend spec and/or listen address. + */ + wsrep_status_t (*connect) (wsrep_t* wsrep, + const char* cluster_name, + const char* cluster_url, + const char* state_donor, + wsrep_bool_t bootstrap); + + /*! + * @brief Closes connection to cluster. + * + * If state_uuid and/or state_seqno is not NULL, will store final state + * in there. + * + * @param wsrep this wsrep handler + */ + wsrep_status_t (*disconnect)(wsrep_t* wsrep); + + /*! + * @brief start receiving replication events + * + * This function never returns + * + * @param wsrep provider handle + * @param recv_ctx receiver context + */ + wsrep_status_t (*recv)(wsrep_t* wsrep, void* recv_ctx); + + /*! + * @brief Replicates/logs result of transaction to other nodes and allocates + * required resources. + * + * Must be called before transaction commit. Returns success code, which + * caller must check. + * In case of WSREP_OK, starts commit critical section, transaction can + * commit. Otherwise transaction must rollback. + * + * @param wsrep provider handle + * @param ws_handle writeset of committing transaction + * @param conn_id connection ID + * @param flags fine tuning the replication WSREP_FLAG_* + * @param meta transaction meta data + * + * @retval WSREP_OK cluster-wide commit succeeded + * @retval WSREP_TRX_FAIL must rollback transaction + * @retval WSREP_CONN_FAIL must close client connection + * @retval WSREP_NODE_FAIL must close all connections and reinit + */ + wsrep_status_t (*pre_commit)(wsrep_t* wsrep, + wsrep_conn_id_t conn_id, + wsrep_ws_handle_t* ws_handle, + uint32_t flags, + wsrep_trx_meta_t* meta); + + /*! + * @brief Releases resources after transaction commit. + * + * Ends commit critical section. + * + * @param wsrep provider handle + * @param ws_handle writeset of committing transaction + * @retval WSREP_OK post_commit succeeded + */ + wsrep_status_t (*post_commit) (wsrep_t* wsrep, + wsrep_ws_handle_t* ws_handle); + + /*! + * @brief Releases resources after transaction rollback. + * + * @param wsrep provider handle + * @param ws_handle writeset of committing transaction + * @retval WSREP_OK post_rollback succeeded + */ + wsrep_status_t (*post_rollback)(wsrep_t* wsrep, + wsrep_ws_handle_t* ws_handle); + + /*! + * @brief Replay trx as a slave writeset + * + * If local trx has been aborted by brute force, and it has already + * replicated before this abort, we must try if we can apply it as + * slave trx. Note that slave nodes see only trx writesets and certification + * test based on write set content can be different to DBMS lock conflicts. + * + * @param wsrep provider handle + * @param ws_handle writeset of committing transaction + * @param trx_ctx transaction context + * + * @retval WSREP_OK cluster commit succeeded + * @retval WSREP_TRX_FAIL must rollback transaction + * @retval WSREP_BF_ABORT brute force abort happened after trx replicated + * must rollback transaction and try to replay + * @retval WSREP_CONN_FAIL must close client connection + * @retval WSREP_NODE_FAIL must close all connections and reinit + */ + wsrep_status_t (*replay_trx)(wsrep_t* wsrep, + wsrep_ws_handle_t* ws_handle, + void* trx_ctx); + + /*! + * @brief Abort pre_commit() call of another thread. + * + * It is possible, that some high-priority transaction needs to abort + * another transaction which is in pre_commit() call waiting for resources. + * + * The kill routine checks that abort is not attmpted against a transaction + * which is front of the caller (in total order). + * + * @param wsrep provider handle + * @param bf_seqno seqno of brute force trx, running this cancel + * @param victim_trx transaction to be aborted, and which is committing + * + * @retval WSREP_OK abort secceded + * @retval WSREP_WARNING abort failed + */ + wsrep_status_t (*abort_pre_commit)(wsrep_t* wsrep, + wsrep_seqno_t bf_seqno, + wsrep_trx_id_t victim_trx); + + /*! + * @brief Appends a row reference to transaction writeset + * + * Both copy flag and key_type can be ignored by provider (key type + * interpreted as WSREP_KEY_EXCLUSIVE). + * + * @param wsrep provider handle + * @param ws_handle writeset handle + * @param keys array of keys + * @param count length of the array of keys + * @param type type ot the key + * @param copy can be set to FALSE if keys persist through commit. + */ + wsrep_status_t (*append_key)(wsrep_t* wsrep, + wsrep_ws_handle_t* ws_handle, + const wsrep_key_t* keys, + size_t count, + enum wsrep_key_type type, + wsrep_bool_t copy); + + /*! + * @brief Appends data to transaction writeset + * + * This method can be called any time before commit and it + * appends a number of data buffers to transaction writeset. + * + * Both copy and unordered flags can be ignored by provider. + * + * @param wsrep provider handle + * @param ws_handle writeset handle + * @param data array of data buffers + * @param count buffer count + * @param type type of data + * @param copy can be set to FALSE if data persists through commit. + */ + wsrep_status_t (*append_data)(wsrep_t* wsrep, + wsrep_ws_handle_t* ws_handle, + const struct wsrep_buf* data, + size_t count, + enum wsrep_data_type type, + wsrep_bool_t copy); + + /*! + * @brief Get causal ordering for read operation + * + * This call will block until causal ordering with all possible + * preceding writes in the cluster is guaranteed. If pointer to + * gtid is non-null, the call stores the global transaction ID + * of the last transaction which is guaranteed to be ordered + * causally before this call. + * + * @param wsrep provider handle + * @param gtid location to store GTID + */ + wsrep_status_t (*causal_read)(wsrep_t* wsrep, wsrep_gtid_t* gtid); + + /*! + * @brief Clears allocated connection context. + * + * Whenever a new connection ID is passed to wsrep provider through + * any of the API calls, a connection context is allocated for this + * connection. This call is to explicitly notify provider fo connection + * closing. + * + * @param wsrep provider handle + * @param conn_id connection ID + * @param query the 'set database' query + * @param query_len length of query (does not end with 0) + */ + wsrep_status_t (*free_connection)(wsrep_t* wsrep, + wsrep_conn_id_t conn_id); + + /*! + * @brief Replicates a query and starts "total order isolation" section. + * + * Replicates the action spec and returns success code, which caller must + * check. Total order isolation continues until to_execute_end() is called. + * + * @param wsrep provider handle + * @param conn_id connection ID + * @param keys array of keys + * @param keys_num lenght of the array of keys + * @param action action buffer array to be executed + * @param count action buffer count + * @param meta transaction meta data + * + * @retval WSREP_OK cluster commit succeeded + * @retval WSREP_CONN_FAIL must close client connection + * @retval WSREP_NODE_FAIL must close all connections and reinit + */ + wsrep_status_t (*to_execute_start)(wsrep_t* wsrep, + wsrep_conn_id_t conn_id, + const wsrep_key_t* keys, + size_t keys_num, + const struct wsrep_buf* action, + size_t count, + wsrep_trx_meta_t* meta); + + /*! + * @brief Ends the total order isolation section. + * + * Marks the end of total order isolation. TO locks are freed + * and other transactions are free to commit from this point on. + * + * @param wsrep provider handle + * @param conn_id connection ID + * + * @retval WSREP_OK cluster commit succeeded + * @retval WSREP_CONN_FAIL must close client connection + * @retval WSREP_NODE_FAIL must close all connections and reinit + */ + wsrep_status_t (*to_execute_end)(wsrep_t* wsrep, wsrep_conn_id_t conn_id); + + /*! + * @brief Collects preordered replication events into a writeset. + * + * @param wsrep wsrep provider handle + * @param handle a handle associated with a given writeset + * @param data an array of data buffers. + * @param count length of data buffer array. + * @param copy whether provider needs to make a copy of events. + * + * @retval WSREP_OK cluster-wide commit succeeded + * @retval WSREP_TRX_FAIL operation failed (e.g. trx size exceeded limit) + * @retval WSREP_NODE_FAIL must close all connections and reinit + */ + wsrep_status_t (*preordered_collect) (wsrep_t* wsrep, + wsrep_po_handle_t* handle, + const struct wsrep_buf* data, + size_t count, + wsrep_bool_t copy); + + /*! + * @brief "Commits" preordered writeset to cluster. + * + * The contract is that the writeset will be committed in the same (partial) + * order this method was called. Frees resources associated with the writeset + * handle and reinitializes the handle. + * + * @param wsrep wsrep provider handle + * @param po_handle a handle associated with a given writeset + * @param source_id ID of the event producer, also serves as the partial order + * or stream ID - events with different source_ids won't be + * ordered with respect to each other. + * @param flags WSREP_FLAG_... flags + * @param pa_range the number of preceding events this event can be processed + * in parallel with. A value of 0 means strict serial + * processing. Note: commits always happen in wsrep order. + * @param commit 'true' to commit writeset to cluster (replicate) or + * 'false' to rollback (cancel) the writeset. + * + * @retval WSREP_OK cluster-wide commit succeeded + * @retval WSREP_TRX_FAIL operation failed (e.g. NON-PRIMARY component) + * @retval WSREP_NODE_FAIL must close all connections and reinit + */ + wsrep_status_t (*preordered_commit) (wsrep_t* wsrep, + wsrep_po_handle_t* handle, + const wsrep_uuid_t* source_id, + uint32_t flags, + int pa_range, + wsrep_bool_t commit); + + /*! + * @brief Signals to wsrep provider that state snapshot has been sent to + * joiner. + * + * @param wsrep provider handle + * @param state_id state ID + * @param rcode 0 or negative error code of the operation. + */ + wsrep_status_t (*sst_sent)(wsrep_t* wsrep, + const wsrep_gtid_t* state_id, + int rcode); + + /*! + * @brief Signals to wsrep provider that new state snapshot has been received. + * May deadlock if called from sst_prepare_cb. + * + * @param wsrep provider handle + * @param state_id state ID + * @param state initial state provided by SST donor + * @param state_len length of state buffer + * @param rcode 0 or negative error code of the operation. + */ + wsrep_status_t (*sst_received)(wsrep_t* wsrep, + const wsrep_gtid_t* state_id, + const void* state, + size_t state_len, + int rcode); + + + /*! + * @brief Generate request for consistent snapshot. + * + * If successfull, this call will generate internally SST request + * which in turn triggers calling SST donate callback on the nodes + * specified in donor_spec. If donor_spec is null, callback is + * called only locally. This call will block until sst_sent is called + * from callback. + * + * @param wsrep provider handle + * @param msg context message for SST donate callback + * @param msg_len length of context message + * @param donor_spec list of snapshot donors + */ + wsrep_status_t (*snapshot)(wsrep_t* wsrep, + const void* msg, + size_t msg_len, + const char* donor_spec); + + /*! + * @brief Returns an array fo status variables. + * Array is terminated by Null variable name. + * + * @param wsrep provider handle + * @return array of struct wsrep_status_var. + */ + struct wsrep_stats_var* (*stats_get) (wsrep_t* wsrep); + + /*! + * @brief Release resources that might be associated with the array. + * + * @param wsrep provider handle. + * @param var_array array returned by stats_get(). + */ + void (*stats_free) (wsrep_t* wsrep, struct wsrep_stats_var* var_array); + + /*! + * @brief Reset some stats variables to inital value, provider-dependent. + * + * @param wsrep provider handle. + */ + void (*stats_reset) (wsrep_t* wsrep); + + /*! + * @brief Pauses writeset applying/committing. + * + * @return global sequence number of the paused state or negative error code. + */ + wsrep_seqno_t (*pause) (wsrep_t* wsrep); + + /*! + * @brief Resumes writeset applying/committing. + */ + wsrep_status_t (*resume) (wsrep_t* wsrep); + + /*! + * @brief Desynchronize from cluster + * + * Effectively turns off flow control for this node, allowing it + * to fall behind the cluster. + */ + wsrep_status_t (*desync) (wsrep_t* wsrep); + + /*! + * @brief Request to resynchronize with cluster. + * + * Effectively turns on flow control. Asynchronous - actual synchronization + * event to be deliverred via sync_cb. + */ + wsrep_status_t (*resync) (wsrep_t* wsrep); + + /*! + * @brief Acquire global named lock + * + * @param wsrep wsrep provider handle + * @param name lock name + * @param shared shared or exclusive lock + * @param owner 64-bit owner ID + * @param tout timeout in nanoseconds. + * 0 - return immediately, -1 wait forever. + * @return wsrep status or negative error code + * @retval -EDEADLK lock was already acquired by this thread + * @retval -EBUSY lock was busy + */ + wsrep_status_t (*lock) (wsrep_t* wsrep, + const char* name, wsrep_bool_t shared, + uint64_t owner, int64_t tout); + + /*! + * @brief Release global named lock + * + * @param wsrep wsrep provider handle + * @param name lock name + * @param owner 64-bit owner ID + * @return wsrep status or negative error code + * @retval -EPERM lock does not belong to this owner + */ + wsrep_status_t (*unlock) (wsrep_t* wsrep, const char* name, uint64_t owner); + + /*! + * @brief Check if global named lock is locked + * + * @param wsrep wsrep provider handle + * @param name lock name + * @param owner if not NULL will contain 64-bit owner ID + * @param node if not NULL will contain owner's node UUID + * @return true if lock is locked + */ + wsrep_bool_t (*is_locked) (wsrep_t* wsrep, const char* name, uint64_t* conn, + wsrep_uuid_t* node); + + /*! + * wsrep provider name + */ + const char* provider_name; + + /*! + * wsrep provider version + */ + const char* provider_version; + + /*! + * wsrep provider vendor name + */ + const char* provider_vendor; + + /*! + * @brief Frees allocated resources before unloading the library. + * @param wsrep provider handle + */ + void (*free)(wsrep_t* wsrep); + + void *dlh; //!< reserved for future use + void *ctx; //!< reserved for implemetation private context +}; + + +/*! + * + * @brief Loads wsrep library + * + * @param spec path to wsrep library. If NULL or WSREP_NONE initialises dummy + * pass-through implementation. + * @param hptr wsrep handle + * @param log_cb callback to handle loader messages. Otherwise writes to stderr. + * + * @return zero on success, errno on failure + */ +int wsrep_load(const char* spec, wsrep_t** hptr, wsrep_log_cb_t log_cb); + +/*! + * @brief Unloads wsrep library and frees associated resources + * + * @param hptr wsrep handler pointer + */ +void wsrep_unload(wsrep_t* hptr); + +#ifdef __cplusplus +} +#endif + +#endif /* WSREP_H */ diff --git a/wsrep/wsrep_dummy.c b/wsrep/wsrep_dummy.c new file mode 100644 index 00000000000..bab5329dc02 --- /dev/null +++ b/wsrep/wsrep_dummy.c @@ -0,0 +1,407 @@ +/* Copyright (C) 2009-2010 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/*! @file Dummy wsrep API implementation. */ + +#include "wsrep_api.h" + +#include +#include +#include + +/*! Dummy backend context. */ +typedef struct wsrep_dummy +{ + wsrep_log_cb_t log_fn; + char* options; +} wsrep_dummy_t; + +/* Get pointer to wsrep_dummy context from wsrep_t pointer */ +#define WSREP_DUMMY(_p) ((wsrep_dummy_t *) (_p)->ctx) + +/* Trace function usage a-la DBUG */ +#define WSREP_DBUG_ENTER(_w) do { \ + if (WSREP_DUMMY(_w)) { \ + if (WSREP_DUMMY(_w)->log_fn) \ + WSREP_DUMMY(_w)->log_fn(WSREP_LOG_DEBUG, __FUNCTION__); \ + } \ + } while (0) + + +static void dummy_free(wsrep_t *w) +{ + WSREP_DBUG_ENTER(w); + if (WSREP_DUMMY(w)->options) { + free(WSREP_DUMMY(w)->options); + WSREP_DUMMY(w)->options = NULL; + } + free(w->ctx); + w->ctx = NULL; +} + +static wsrep_status_t dummy_init (wsrep_t* w, + const struct wsrep_init_args* args) +{ + WSREP_DUMMY(w)->log_fn = args->logger_cb; + WSREP_DBUG_ENTER(w); + if (args->options) { + WSREP_DUMMY(w)->options = strdup(args->options); + } + return WSREP_OK; +} + +static uint64_t dummy_capabilities (wsrep_t* w __attribute__((unused))) +{ + return 0; +} + +static wsrep_status_t dummy_options_set( + wsrep_t* w, + const char* conf) +{ + WSREP_DBUG_ENTER(w); + if (WSREP_DUMMY(w)->options) { + free(WSREP_DUMMY(w)->options); + WSREP_DUMMY(w)->options = NULL; + } + if (conf) { + WSREP_DUMMY(w)->options = strdup(conf); + } + return WSREP_OK; +} + +static char* dummy_options_get (wsrep_t* w) +{ + WSREP_DBUG_ENTER(w); + return WSREP_DUMMY(w)->options; +} + +static wsrep_status_t dummy_connect( + wsrep_t* w, + const char* name __attribute__((unused)), + const char* url __attribute__((unused)), + const char* donor __attribute__((unused)), + wsrep_bool_t bootstrap __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_disconnect(wsrep_t* w) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_recv(wsrep_t* w, + void* recv_ctx __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_pre_commit( + wsrep_t* w, + const wsrep_conn_id_t conn_id __attribute__((unused)), + wsrep_ws_handle_t* ws_handle __attribute__((unused)), + uint32_t flags __attribute__((unused)), + wsrep_trx_meta_t* meta __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_post_commit( + wsrep_t* w, + wsrep_ws_handle_t* ws_handle __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_post_rollback( + wsrep_t* w, + wsrep_ws_handle_t* ws_handle __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_replay_trx( + wsrep_t* w, + wsrep_ws_handle_t* ws_handle __attribute__((unused)), + void* trx_ctx __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_abort_pre_commit( + wsrep_t* w, + const wsrep_seqno_t bf_seqno __attribute__((unused)), + const wsrep_trx_id_t trx_id __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_append_key( + wsrep_t* w, + wsrep_ws_handle_t* ws_handle __attribute__((unused)), + const wsrep_key_t* key __attribute__((unused)), + const size_t key_num __attribute__((unused)), + const wsrep_key_type_t key_type __attribute__((unused)), + const bool copy __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_append_data( + wsrep_t* w, + wsrep_ws_handle_t* ws_handle __attribute__((unused)), + const struct wsrep_buf* data __attribute__((unused)), + const size_t count __attribute__((unused)), + const wsrep_data_type_t type __attribute__((unused)), + const bool copy __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_causal_read( + wsrep_t* w, + wsrep_gtid_t* gtid __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_free_connection( + wsrep_t* w, + const wsrep_conn_id_t conn_id __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_to_execute_start( + wsrep_t* w, + const wsrep_conn_id_t conn_id __attribute__((unused)), + const wsrep_key_t* key __attribute__((unused)), + const size_t key_num __attribute__((unused)), + const struct wsrep_buf* data __attribute__((unused)), + const size_t count __attribute__((unused)), + wsrep_trx_meta_t* meta __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_to_execute_end( + wsrep_t* w, + const wsrep_conn_id_t conn_id __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_preordered_collect( + wsrep_t* w, + wsrep_po_handle_t* handle __attribute__((unused)), + const struct wsrep_buf* data __attribute__((unused)), + size_t count __attribute__((unused)), + wsrep_bool_t copy __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_preordered_commit( + wsrep_t* w, + wsrep_po_handle_t* handle __attribute__((unused)), + const wsrep_uuid_t* source_id __attribute__((unused)), + uint32_t flags __attribute__((unused)), + int pa_range __attribute__((unused)), + wsrep_bool_t commit __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_sst_sent( + wsrep_t* w, + const wsrep_gtid_t* state_id __attribute__((unused)), + const int rcode __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_sst_received( + wsrep_t* w, + const wsrep_gtid_t* state_id __attribute__((unused)), + const void* state __attribute__((unused)), + const size_t state_len __attribute__((unused)), + const int rcode __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_snapshot( + wsrep_t* w, + const void* msg __attribute__((unused)), + const size_t msg_len __attribute__((unused)), + const char* donor_spec __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static struct wsrep_stats_var dummy_stats[] = { + { NULL, WSREP_VAR_STRING, { 0 } } +}; + +static struct wsrep_stats_var* dummy_stats_get (wsrep_t* w) +{ + WSREP_DBUG_ENTER(w); + return dummy_stats; +} + +static void dummy_stats_free ( + wsrep_t* w, + struct wsrep_stats_var* stats __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); +} + +static void dummy_stats_reset (wsrep_t* w) +{ + WSREP_DBUG_ENTER(w); +} + +static wsrep_seqno_t dummy_pause (wsrep_t* w) +{ + WSREP_DBUG_ENTER(w); + return -ENOSYS; +} + +static wsrep_status_t dummy_resume (wsrep_t* w) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_desync (wsrep_t* w) +{ + WSREP_DBUG_ENTER(w); + return WSREP_NOT_IMPLEMENTED; +} + +static wsrep_status_t dummy_resync (wsrep_t* w) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static wsrep_status_t dummy_lock (wsrep_t* w, + const char* s __attribute__((unused)), + bool r __attribute__((unused)), + uint64_t o __attribute__((unused)), + int64_t t __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_NOT_IMPLEMENTED; +} + +static wsrep_status_t dummy_unlock (wsrep_t* w, + const char* s __attribute__((unused)), + uint64_t o __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return WSREP_OK; +} + +static bool dummy_is_locked (wsrep_t* w, + const char* s __attribute__((unused)), + uint64_t* o __attribute__((unused)), + wsrep_uuid_t* t __attribute__((unused))) +{ + WSREP_DBUG_ENTER(w); + return false; +} + +static wsrep_t dummy_iface = { + WSREP_INTERFACE_VERSION, + &dummy_init, + &dummy_capabilities, + &dummy_options_set, + &dummy_options_get, + &dummy_connect, + &dummy_disconnect, + &dummy_recv, + &dummy_pre_commit, + &dummy_post_commit, + &dummy_post_rollback, + &dummy_replay_trx, + &dummy_abort_pre_commit, + &dummy_append_key, + &dummy_append_data, + &dummy_causal_read, + &dummy_free_connection, + &dummy_to_execute_start, + &dummy_to_execute_end, + &dummy_preordered_collect, + &dummy_preordered_commit, + &dummy_sst_sent, + &dummy_sst_received, + &dummy_snapshot, + &dummy_stats_get, + &dummy_stats_free, + &dummy_stats_reset, + &dummy_pause, + &dummy_resume, + &dummy_desync, + &dummy_resync, + &dummy_lock, + &dummy_unlock, + &dummy_is_locked, + WSREP_NONE, + WSREP_INTERFACE_VERSION, + "Codership Oy ", + &dummy_free, + NULL, + NULL +}; + +int wsrep_dummy_loader(wsrep_t* w) +{ + if (!w) + return EINVAL; + + *w = dummy_iface; + + // allocate private context + if (!(w->ctx = malloc(sizeof(wsrep_dummy_t)))) + return ENOMEM; + + // initialize private context + WSREP_DUMMY(w)->log_fn = NULL; + WSREP_DUMMY(w)->options = NULL; + + return 0; +} diff --git a/wsrep/wsrep_gtid.c b/wsrep/wsrep_gtid.c new file mode 100644 index 00000000000..e618c5ab7d0 --- /dev/null +++ b/wsrep/wsrep_gtid.c @@ -0,0 +1,74 @@ +/* Copyright (C) 2013 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/*! @file Helper functions to deal with GTID string representations */ + +#include +#include +#include +#include + +#include "wsrep_api.h" + +/*! + * Read GTID from string + * @return length of GTID string representation or -EINVAL in case of error + */ +int +wsrep_gtid_scan(const char* str, size_t str_len, wsrep_gtid_t* gtid) +{ + unsigned int offset; + char* endptr; + + if ((offset = wsrep_uuid_scan(str, str_len, >id->uuid)) > 0 && + offset < str_len && str[offset] == ':') { + ++offset; + if (offset < str_len) + { + errno = 0; + gtid->seqno = strtoll(str + offset, &endptr, 0); + + if (errno == 0) { + offset = endptr - str; + return offset; + } + } + } + *gtid = WSREP_GTID_UNDEFINED; + return -EINVAL; +} + +/*! + * Write GTID to string + * @return length of GTID stirng representation of -EMSGSIZE if string is too + * short + */ +int +wsrep_gtid_print(const wsrep_gtid_t* gtid, char* str, size_t str_len) +{ + unsigned int offset, ret; + if ((offset = wsrep_uuid_print(>id->uuid, str, str_len)) > 0) + { + ret = snprintf(str + offset, str_len - offset, + ":%" PRId64, gtid->seqno); + if (ret <= str_len - offset) { + return (offset + ret); + } + + } + + return -EMSGSIZE; +} diff --git a/wsrep/wsrep_loader.c b/wsrep/wsrep_loader.c new file mode 100644 index 00000000000..8ae6ea962ec --- /dev/null +++ b/wsrep/wsrep_loader.c @@ -0,0 +1,203 @@ +/* Copyright (C) 2009-2011 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/*! @file wsrep implementation loader */ + +#include +#include +#include +#include + +#include "wsrep_api.h" + +// Logging stuff for the loader +static const char* log_levels[] = {"FATAL", "ERROR", "WARN", "INFO", "DEBUG"}; + +static void default_logger (wsrep_log_level_t lvl, const char* msg) +{ + fprintf (stderr, "wsrep loader: [%s] %s\n", log_levels[lvl], msg); +} + +static wsrep_log_cb_t logger = default_logger; + +/************************************************************************** + * Library loader + **************************************************************************/ + +static int verify(const wsrep_t *wh, const char *iface_ver) +{ + const size_t msg_len = 128; + char msg[msg_len]; + +#define VERIFY(_p) if (!(_p)) { \ + snprintf(msg, msg_len, "wsrep_load(): verify(): %s\n", # _p); \ + logger (WSREP_LOG_ERROR, msg); \ + return EINVAL; \ + } + + VERIFY(wh); + VERIFY(wh->version); + + if (strcmp(wh->version, iface_ver)) { + snprintf (msg, msg_len, + "provider interface version mismatch: need '%s', found '%s'", + iface_ver, wh->version); + logger (WSREP_LOG_ERROR, msg); + return EINVAL; + } + + VERIFY(wh->init); + VERIFY(wh->options_set); + VERIFY(wh->options_get); + VERIFY(wh->connect); + VERIFY(wh->disconnect); + VERIFY(wh->recv); + VERIFY(wh->pre_commit); + VERIFY(wh->post_commit); + VERIFY(wh->post_rollback); + VERIFY(wh->replay_trx); + VERIFY(wh->abort_pre_commit); + VERIFY(wh->append_key); + VERIFY(wh->append_data); + VERIFY(wh->free_connection); + VERIFY(wh->to_execute_start); + VERIFY(wh->to_execute_end); + VERIFY(wh->preordered_collect); + VERIFY(wh->preordered_commit); + VERIFY(wh->sst_sent); + VERIFY(wh->sst_received); + VERIFY(wh->stats_get); + VERIFY(wh->stats_free); + VERIFY(wh->stats_reset); + VERIFY(wh->pause); + VERIFY(wh->resume); + VERIFY(wh->desync); + VERIFY(wh->resync); + VERIFY(wh->lock); + VERIFY(wh->unlock); + VERIFY(wh->is_locked); + VERIFY(wh->provider_name); + VERIFY(wh->provider_version); + VERIFY(wh->provider_vendor); + VERIFY(wh->free); + return 0; +} + +typedef int (*wsrep_loader_fun)(wsrep_t*); + +static wsrep_loader_fun wsrep_dlf(void *dlh, const char *sym) +{ + union { + wsrep_loader_fun dlfun; + void *obj; + } alias; + alias.obj = dlsym(dlh, sym); + return alias.dlfun; +} + +extern int wsrep_dummy_loader(wsrep_t *w); + +int wsrep_load(const char *spec, wsrep_t **hptr, wsrep_log_cb_t log_cb) +{ + int ret = 0; + void *dlh = NULL; + wsrep_loader_fun dlfun; + const size_t msg_len = 1024; + char msg[msg_len + 1]; + msg[msg_len] = 0; + + if (NULL != log_cb) + logger = log_cb; + + if (!(spec && hptr)) + return EINVAL; + + snprintf (msg, msg_len, + "wsrep_load(): loading provider library '%s'", spec); + logger (WSREP_LOG_INFO, msg); + + if (!(*hptr = malloc(sizeof(wsrep_t)))) { + logger (WSREP_LOG_FATAL, "wsrep_load(): out of memory"); + return ENOMEM; + } + + if (!spec || strcmp(spec, WSREP_NONE) == 0) { + if ((ret = wsrep_dummy_loader(*hptr)) != 0) { + free (*hptr); + *hptr = NULL; + } + return ret; + } + + if (!(dlh = dlopen(spec, RTLD_NOW | RTLD_LOCAL))) { + snprintf(msg, msg_len, "wsrep_load(): dlopen(): %s", dlerror()); + logger (WSREP_LOG_ERROR, msg); + ret = EINVAL; + goto out; + } + + if (!(dlfun = wsrep_dlf(dlh, "wsrep_loader"))) { + ret = EINVAL; + goto out; + } + + if ((ret = (*dlfun)(*hptr)) != 0) { + snprintf(msg, msg_len, "wsrep_load(): loader failed: %s", + strerror(ret)); + logger (WSREP_LOG_ERROR, msg); + goto out; + } + + if ((ret = verify(*hptr, WSREP_INTERFACE_VERSION)) != 0) { + snprintf (msg, msg_len, + "wsrep_load(): interface version mismatch: my version %s, " + "provider version %s", WSREP_INTERFACE_VERSION, + (*hptr)->version); + logger (WSREP_LOG_ERROR, msg); + goto out; + } + + (*hptr)->dlh = dlh; + +out: + if (ret != 0) { + if (dlh) dlclose(dlh); + free(*hptr); + *hptr = NULL; + } else { + snprintf (msg, msg_len, + "wsrep_load(): %s %s by %s loaded successfully.", + (*hptr)->provider_name, (*hptr)->provider_version, + (*hptr)->provider_vendor); + logger (WSREP_LOG_INFO, msg); + } + + return ret; +} + +void wsrep_unload(wsrep_t *hptr) +{ + if (!hptr) { + logger (WSREP_LOG_WARN, "wsrep_unload(): null pointer."); + } else { + if (hptr->free) + hptr->free(hptr); + if (hptr->dlh) + dlclose(hptr->dlh); + free(hptr); + } +} + diff --git a/wsrep/wsrep_uuid.c b/wsrep/wsrep_uuid.c new file mode 100644 index 00000000000..baa95b2578a --- /dev/null +++ b/wsrep/wsrep_uuid.c @@ -0,0 +1,83 @@ +/* Copyright (C) 2009 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/*! @file Helper functions to deal with history UUID string representations */ + +#include +#include +#include + +#include "wsrep_api.h" + +/*! + * Read UUID from string + * @return length of UUID string representation or -EINVAL in case of error + */ +int +wsrep_uuid_scan (const char* str, size_t str_len, wsrep_uuid_t* uuid) +{ + unsigned int uuid_len = 0; + unsigned int uuid_offt = 0; + + while (uuid_len + 1 < str_len) { + /* We are skipping potential '-' after uuid_offt == 4, 6, 8, 10 + * which means + * (uuid_offt >> 1) == 2, 3, 4, 5, + * which in turn means + * (uuid_offt >> 1) - 2 <= 3 + * since it is always >= 0, because uuid_offt is unsigned */ + if (((uuid_offt >> 1) - 2) <= 3 && str[uuid_len] == '-') { + // skip dashes after 4th, 6th, 8th and 10th positions + uuid_len += 1; + continue; + } + + if (isxdigit(str[uuid_len]) && isxdigit(str[uuid_len + 1])) { + // got hex digit, scan another byte to uuid, increment uuid_offt + sscanf (str + uuid_len, "%2hhx", uuid->data + uuid_offt); + uuid_len += 2; + uuid_offt += 1; + if (sizeof (uuid->data) == uuid_offt) + return uuid_len; + } + else { + break; + } + } + + *uuid = WSREP_UUID_UNDEFINED; + return -EINVAL; +} + +/*! + * Write UUID to string + * @return length of UUID string representation or -EMSGSIZE if string is too + * short + */ +int +wsrep_uuid_print (const wsrep_uuid_t* uuid, char* str, size_t str_len) +{ + if (str_len > 36) { + const unsigned char* u = uuid->data; + return snprintf(str, str_len, "%02x%02x%02x%02x-%02x%02x-%02x%02x-" + "%02x%02x-%02x%02x%02x%02x%02x%02x", + u[ 0], u[ 1], u[ 2], u[ 3], u[ 4], u[ 5], u[ 6], u[ 7], + u[ 8], u[ 9], u[10], u[11], u[12], u[13], u[14], u[15]); + } + else { + return -EMSGSIZE; + } +} From a60ea193ba00f5af1492d1bc2b15946a330438a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 27 Aug 2014 15:19:45 +0300 Subject: [PATCH 021/153] Fix compiler error when WITH_WSREP is not used. --- storage/innobase/lock/lock0lock.cc | 17 ++++++++--------- storage/xtradb/lock/lock0lock.cc | 17 ++++++++--------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index fbac412c4e8..564e43e9bfa 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -6063,16 +6063,15 @@ lock_rec_queue_validate( if (!lock_rec_get_gap(lock) && !lock_get_wait(lock)) { #ifndef WITH_WSREP - if (wsrep_thd_is_wsrep(lock->trx->mysql_thd)) { - enum lock_mode mode; + enum lock_mode mode; - if (lock_get_mode(lock) == LOCK_S) { - mode = LOCK_X; - } else { - mode = LOCK_S; - } - ut_a(!lock_rec_other_has_expl_req( - mode, 0, 0, block, heap_no, lock->trx)); + if (lock_get_mode(lock) == LOCK_S) { + mode = LOCK_X; + } else { + mode = LOCK_S; + } + ut_a(!lock_rec_other_has_expl_req( + mode, 0, 0, block, heap_no, lock->trx)); } #endif /* WITH_WSREP */ diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc index 532bd6232b7..ede6dd47b90 100644 --- a/storage/xtradb/lock/lock0lock.cc +++ b/storage/xtradb/lock/lock0lock.cc @@ -6112,17 +6112,16 @@ lock_rec_queue_validate( if (!lock_rec_get_gap(lock) && !lock_get_wait(lock)) { #ifndef WITH_WSREP - if (wsrep_thd_is_wsrep(lock->trx->mysql_thd)) { - enum lock_mode mode; + enum lock_mode mode; - if (lock_get_mode(lock) == LOCK_S) { - mode = LOCK_X; - } else { - mode = LOCK_S; - } - ut_a(!lock_rec_other_has_expl_req( - mode, 0, 0, block, heap_no, lock->trx->id)); + if (lock_get_mode(lock) == LOCK_S) { + mode = LOCK_X; + } else { + mode = LOCK_S; + } + ut_a(!lock_rec_other_has_expl_req( + mode, 0, 0, block, heap_no, lock->trx->id)); } #endif /* WITH_WSREP */ From 6907da234138e0983b6f553228590dfeef3633ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 27 Aug 2014 15:35:49 +0300 Subject: [PATCH 022/153] Fix small error on LZMA compression error printout. --- storage/innobase/fil/fil0pagecompress.cc | 4 +--- storage/xtradb/fil/fil0pagecompress.cc | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/storage/innobase/fil/fil0pagecompress.cc b/storage/innobase/fil/fil0pagecompress.cc index 65d5317a1b1..b6eb2e73b30 100644 --- a/storage/innobase/fil/fil0pagecompress.cc +++ b/storage/innobase/fil/fil0pagecompress.cc @@ -493,9 +493,7 @@ fil_decompress_page( ulint actual_size = 0; ulint compression_alg = 0; byte *in_buf; -#ifdef HAVE_LZO ulint olen=0; -#endif ulint ptype; ut_ad(buf); @@ -649,7 +647,7 @@ fil_decompress_page( "InnoDB: Corruption: Page is marked as compressed\n" "InnoDB: but decompression read only %ld bytes.\n" "InnoDB: size %lu len %lu\n", - olen, actual_size, len); + dst_pos, actual_size, len); fflush(stderr); ut_error; diff --git a/storage/xtradb/fil/fil0pagecompress.cc b/storage/xtradb/fil/fil0pagecompress.cc index 59d45d5af62..e92f3587236 100644 --- a/storage/xtradb/fil/fil0pagecompress.cc +++ b/storage/xtradb/fil/fil0pagecompress.cc @@ -490,9 +490,7 @@ fil_decompress_page( ulint actual_size = 0; ulint compression_alg = 0; byte *in_buf; -#ifdef HAVE_LZO ulint olen=0; -#endif ulint ptype; ut_ad(buf); @@ -646,7 +644,7 @@ fil_decompress_page( "InnoDB: Corruption: Page is marked as compressed\n" "InnoDB: but decompression read only %ld bytes.\n" "InnoDB: size %lu len %lu\n", - olen, actual_size, len); + dst_pos, actual_size, len); fflush(stderr); ut_error; From be00e279c6061134a33a8099fd69d4304735d02e Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Wed, 27 Aug 2014 18:47:33 +0400 Subject: [PATCH 023/153] MDEV-6480: Remove conditions for which range optimizer returned SEL_ARG::IMPOSSIBLE Let range optimizer remove parts of OR-clauses for which range analysis produced SEL_TREE(IMPOSSIBLE). There is no need to remove parts of AND-clauses: either they are inside of OR (and the whole AND-clause will be removed), or the AND-clause is at the top level, in which case the whole WHERE (or ON) is always FALSE and this is a degenerate case which receives special treatment. The removal process takes care not to produce 1-way ORs (in that case we substitute the OR for its remaining member). --- mysql-test/r/index_merge_myisam.result | 2 +- mysql-test/r/join_outer.result | 4 +- mysql-test/r/join_outer_jcl6.result | 4 +- mysql-test/r/range.result | 45 +++++++++++ mysql-test/r/range_mrr_icp.result | 45 +++++++++++ mysql-test/t/range.test | 32 ++++++++ sql/opt_range.cc | 101 +++++++++++++++++++++---- sql/opt_range.h | 6 +- sql/sql_select.cc | 40 ++++++---- 9 files changed, 241 insertions(+), 38 deletions(-) diff --git a/mysql-test/r/index_merge_myisam.result b/mysql-test/r/index_merge_myisam.result index c907997573a..9820170aa59 100644 --- a/mysql-test/r/index_merge_myisam.result +++ b/mysql-test/r/index_merge_myisam.result @@ -74,7 +74,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL 17 Using sort_union(i1,i2); Using where explain select * from t0 where key2 = 45 or key1 <=> null; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 range i1,i2 i2 4 NULL 1 Using where +1 SIMPLE t0 range i1,i2 i2 4 NULL 1 Using index condition explain select * from t0 where key2 = 45 or key1 is not null; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t0 ALL i1,i2 NULL NULL NULL 1024 Using where diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index c4770182598..36c2f1898f8 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -2090,10 +2090,10 @@ SELECT t1.b, t2.c, t2.d FROM t2 LEFT JOIN t1 ON t2.c = t1.a WHERE t1.pk BETWEEN 5 AND 6 AND t1.b IS NULL OR t1.b = 5 ORDER BY t1.b; id select_type table type possible_keys key key_len ref rows filtered Extra -1 SIMPLE t1 ref PRIMARY,idx idx 4 const 2 100.00 Using where; Using filesort +1 SIMPLE t1 ref PRIMARY,idx idx 4 const 2 100.00 Using where 1 SIMPLE t2 ref c c 5 test.t1.a 2 100.00 Warnings: -Note 1003 select `test`.`t1`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` join `test`.`t1` where ((`test`.`t2`.`c` = `test`.`t1`.`a`) and (((`test`.`t1`.`pk` between 5 and 6) and isnull(`test`.`t1`.`b`)) or (`test`.`t1`.`b` = 5))) order by `test`.`t1`.`b` +Note 1003 select `test`.`t1`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` join `test`.`t1` where ((`test`.`t2`.`c` = `test`.`t1`.`a`) and (`test`.`t1`.`b` = 5)) order by `test`.`t1`.`b` SELECT t1.b, t2.c, t2.d FROM t2 LEFT JOIN t1 ON t2.c = t1.a WHERE t1.pk BETWEEN 5 AND 6 AND t1.b IS NULL OR t1.b = 5 ORDER BY t1.b; diff --git a/mysql-test/r/join_outer_jcl6.result b/mysql-test/r/join_outer_jcl6.result index 862fc194a7a..6f3da3efdd7 100644 --- a/mysql-test/r/join_outer_jcl6.result +++ b/mysql-test/r/join_outer_jcl6.result @@ -2101,10 +2101,10 @@ SELECT t1.b, t2.c, t2.d FROM t2 LEFT JOIN t1 ON t2.c = t1.a WHERE t1.pk BETWEEN 5 AND 6 AND t1.b IS NULL OR t1.b = 5 ORDER BY t1.b; id select_type table type possible_keys key key_len ref rows filtered Extra -1 SIMPLE t1 ref PRIMARY,idx idx 4 const 2 100.00 Using where; Using filesort +1 SIMPLE t1 ref PRIMARY,idx idx 4 const 2 100.00 Using where 1 SIMPLE t2 ref c c 5 test.t1.a 2 100.00 Warnings: -Note 1003 select `test`.`t1`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` join `test`.`t1` where ((`test`.`t2`.`c` = `test`.`t1`.`a`) and (((`test`.`t1`.`pk` between 5 and 6) and isnull(`test`.`t1`.`b`)) or (`test`.`t1`.`b` = 5))) order by `test`.`t1`.`b` +Note 1003 select `test`.`t1`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` join `test`.`t1` where ((`test`.`t2`.`c` = `test`.`t1`.`a`) and (`test`.`t1`.`b` = 5)) order by `test`.`t1`.`b` SELECT t1.b, t2.c, t2.d FROM t2 LEFT JOIN t1 ON t2.c = t1.a WHERE t1.pk BETWEEN 5 AND 6 AND t1.b IS NULL OR t1.b = 5 ORDER BY t1.b; diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index f2ad42ebc8d..fe528e1b2e9 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -2196,3 +2196,48 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t3 const PRIMARY PRIMARY 4 const 1 1 SIMPLE t2 range a a 5 NULL 1 Using where; Using index drop table t1,t2,t3; +# +# MDEV-6480: Remove conditions for which range optimizer returned SEL_ARG::IMPOSSIBLE. +# +create table t1(a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2 (a int, b int, c int, key(a), key(b)); +insert into t2 +select +A.a + B.a* 10 + C.a * 100, +A.a + B.a* 10 + C.a * 100, +12345 +from +t1 A, t1 B, t1 C; +# EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE: +explain extended select * from t2 where (b > 25 and b < 15) or a<44; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 range a,b a 5 NULL 43 100.00 Using index condition +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where (`test`.`t2`.`a` < 44) +# EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE: +explain extended select * from t2 where a < 44 or (b > 25 and b < 15); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 range a,b a 5 NULL 43 100.00 Using index condition +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where (`test`.`t2`.`a` < 44) +# Here, conditions b will not be removed, because "c<44" is not sargable +# and hence (b.. and .. b) part is not analyzed at all: +explain extended select * from t2 where c < 44 or (b > 25 and b < 15); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 ALL b NULL NULL NULL 1000 100.00 Using where +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where ((`test`.`t2`.`c` < 44) or ((`test`.`t2`.`b` > 25) and (`test`.`t2`.`b` < 15))) +# EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE: +explain extended select * from t2 where (b > 25 and b < 15) or c < 44; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 ALL b NULL NULL NULL 1000 100.00 Using where +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where ((`test`.`t2`.`c` < 44)) +# Try a case where both OR parts produce SEL_ARG::IMPOSSIBLE: +explain extended select * from t2 where (b > 25 and b < 15) or (a>55 and a<44); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where 0 +drop table t1,t2; diff --git a/mysql-test/r/range_mrr_icp.result b/mysql-test/r/range_mrr_icp.result index 16b35448c50..62bea71173c 100644 --- a/mysql-test/r/range_mrr_icp.result +++ b/mysql-test/r/range_mrr_icp.result @@ -2198,4 +2198,49 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t3 const PRIMARY PRIMARY 4 const 1 1 SIMPLE t2 range a a 5 NULL 1 Using where; Using index drop table t1,t2,t3; +# +# MDEV-6480: Remove conditions for which range optimizer returned SEL_ARG::IMPOSSIBLE. +# +create table t1(a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2 (a int, b int, c int, key(a), key(b)); +insert into t2 +select +A.a + B.a* 10 + C.a * 100, +A.a + B.a* 10 + C.a * 100, +12345 +from +t1 A, t1 B, t1 C; +# EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE: +explain extended select * from t2 where (b > 25 and b < 15) or a<44; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 range a,b a 5 NULL 43 100.00 Using index condition; Rowid-ordered scan +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where (`test`.`t2`.`a` < 44) +# EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE: +explain extended select * from t2 where a < 44 or (b > 25 and b < 15); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 range a,b a 5 NULL 43 100.00 Using index condition; Rowid-ordered scan +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where (`test`.`t2`.`a` < 44) +# Here, conditions b will not be removed, because "c<44" is not sargable +# and hence (b.. and .. b) part is not analyzed at all: +explain extended select * from t2 where c < 44 or (b > 25 and b < 15); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 ALL b NULL NULL NULL 1000 100.00 Using where +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where ((`test`.`t2`.`c` < 44) or ((`test`.`t2`.`b` > 25) and (`test`.`t2`.`b` < 15))) +# EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE: +explain extended select * from t2 where (b > 25 and b < 15) or c < 44; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 ALL b NULL NULL NULL 1000 100.00 Using where +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where ((`test`.`t2`.`c` < 44)) +# Try a case where both OR parts produce SEL_ARG::IMPOSSIBLE: +explain extended select * from t2 where (b > 25 and b < 15) or (a>55 and a<44); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where 0 +drop table t1,t2; set optimizer_switch=@mrr_icp_extra_tmp; diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index 7b68f42c4cb..6249d2b5e4f 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -1745,3 +1745,35 @@ explain select * from t3, t2 where t2.a < t3.b and t3.a=1; --echo # The second table should use 'range': explain select * from t3, t2 where t3.b > t2.a and t3.a=1; drop table t1,t2,t3; + +--echo # +--echo # MDEV-6480: Remove conditions for which range optimizer returned SEL_ARG::IMPOSSIBLE. +--echo # +create table t1(a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2 (a int, b int, c int, key(a), key(b)); +insert into t2 +select + A.a + B.a* 10 + C.a * 100, + A.a + B.a* 10 + C.a * 100, + 12345 +from + t1 A, t1 B, t1 C; + +--echo # EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE: +explain extended select * from t2 where (b > 25 and b < 15) or a<44; + +--echo # EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE: +explain extended select * from t2 where a < 44 or (b > 25 and b < 15); + +--echo # Here, conditions b will not be removed, because "c<44" is not sargable +--echo # and hence (b.. and .. b) part is not analyzed at all: +explain extended select * from t2 where c < 44 or (b > 25 and b < 15); + +--echo # EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE: +explain extended select * from t2 where (b > 25 and b < 15) or c < 44; + +--echo # Try a case where both OR parts produce SEL_ARG::IMPOSSIBLE: +explain extended select * from t2 where (b > 25 and b < 15) or (a>55 and a<44); + +drop table t1,t2; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 2616e044025..b795411130d 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -829,6 +829,12 @@ public: */ bool remove_jump_scans; + /* + TRUE <=> Range analyzer should remove parts of condition that are found + to be always FALSE. + */ + bool remove_false_where_parts; + /* used_key_no -> table_key_no translation table. Only makes sense if using_real_indexes==TRUE @@ -908,7 +914,7 @@ static SEL_TREE * get_mm_parts(RANGE_OPT_PARAM *param,COND *cond_func,Field *fie static SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param,COND *cond_func,Field *field, KEY_PART *key_part, Item_func::Functype type,Item *value); -static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond); +static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond); static bool is_key_scan_ror(PARAM *param, uint keynr, uint8 nparts); static ha_rows check_quick_select(PARAM *param, uint idx, bool index_only, @@ -2941,7 +2947,8 @@ static int fill_used_fields_bitmap(PARAM *param) int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, table_map prev_tables, ha_rows limit, bool force_quick_range, - bool ordered_output) + bool ordered_output, + bool remove_false_parts_of_where) { uint idx; double scan_time; @@ -3000,6 +3007,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, param.imerge_cost_buff_size= 0; param.using_real_indexes= TRUE; param.remove_jump_scans= TRUE; + param.remove_false_where_parts= remove_false_parts_of_where; param.force_default_mrr= ordered_output; param.possible_keys.clear_all(); @@ -3073,7 +3081,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, if (cond) { - if ((tree= get_mm_tree(¶m,cond))) + if ((tree= get_mm_tree(¶m, &cond))) { if (tree->type == SEL_TREE::IMPOSSIBLE) { @@ -3415,7 +3423,7 @@ double records_in_column_ranges(PARAM *param, uint idx, TRUE otherwise */ -bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item *cond) +bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond) { uint keynr; uint max_quick_key_parts= 0; @@ -3425,7 +3433,7 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item *cond) table->cond_selectivity= 1.0; - if (!cond || table_records == 0) + if (!*cond || table_records == 0) DBUG_RETURN(FALSE); if (table->pos_in_table_list->schema_table) @@ -3529,6 +3537,7 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item *cond) param.old_root= thd->mem_root; param.table= table; param.is_ror_scan= FALSE; + param.remove_false_where_parts= true; if (create_key_parts_for_pseudo_indexes(¶m, used_fields)) goto free_alloc; @@ -3606,7 +3615,7 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item *cond) ulong check_rows= MY_MIN(thd->variables.optimizer_selectivity_sampling_limit, (ulong) (table_records * SELECTIVITY_SAMPLING_SHARE)); - if (cond && check_rows > SELECTIVITY_SAMPLING_THRESHOLD && + if (*cond && check_rows > SELECTIVITY_SAMPLING_THRESHOLD && thd->variables.optimizer_use_condition_selectivity > 4) { find_selective_predicates_list_processor_data *dt= @@ -3617,8 +3626,8 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item *cond) DBUG_RETURN(TRUE); dt->list.empty(); dt->table= table; - if (cond->walk(&Item::find_selective_predicates_list_processor, 0, - (uchar*) dt)) + if ((*cond)->walk(&Item::find_selective_predicates_list_processor, 0, + (uchar*) dt)) DBUG_RETURN(TRUE); if (dt->list.elements > 0) { @@ -3951,6 +3960,8 @@ bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond) /* range_par->cond doesn't need initialization */ range_par->prev_tables= range_par->read_tables= 0; range_par->current_table= table->map; + /* It should be possible to switch the following ON: */ + range_par->remove_false_where_parts= false; range_par->keys= 1; // one index range_par->using_real_indexes= FALSE; @@ -3967,7 +3978,7 @@ bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond) SEL_TREE *tree; int res; - tree= get_mm_tree(range_par, pprune_cond); + tree= get_mm_tree(range_par, &pprune_cond); if (!tree) goto all_used; @@ -7855,15 +7866,33 @@ static SEL_TREE *get_full_func_mm_tree(RANGE_OPT_PARAM *param, DBUG_RETURN(ftree); } - /* make a select tree of all keys in condition */ +/* + make a select tree of all keys in condition + + @param param Context + @param cond INOUT condition to perform range analysis on. -static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond) + @detail + Range analysis may infer that some conditions are never true. + - If the condition is never true, SEL_TREE(type=IMPOSSIBLE) is returned + - if parts of condition are never true, the function may remove these parts + from the condition 'cond'. Sometimes, this will cause the condition to + be substituted for something else. + + + @return + NULL - Could not infer anything from condition cond. + SEL_TREE with type=IMPOSSIBLE - condition can never be true. +*/ + +static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr) { SEL_TREE *tree=0; SEL_TREE *ftree= 0; Item_field *field_item= 0; bool inv= FALSE; Item *value= 0; + Item *cond= *cond_ptr; DBUG_ENTER("get_mm_tree"); if (cond->type() == Item::COND_ITEM) @@ -7876,31 +7905,75 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond) Item *item; while ((item=li++)) { - SEL_TREE *new_tree= get_mm_tree(param,item); + SEL_TREE *new_tree= get_mm_tree(param,li.ref()); if (param->statement_should_be_aborted()) DBUG_RETURN(NULL); tree= tree_and(param,tree,new_tree); if (tree && tree->type == SEL_TREE::IMPOSSIBLE) + { + /* + Do not remove 'item' from 'cond'. We return a SEL_TREE::IMPOSSIBLE + and that is sufficient for the caller to see that the whole + condition is never true. + */ break; + } } } else { // COND OR - tree= get_mm_tree(param,li++); + bool replace_cond= false; + Item *replacement_item= li++; + tree= get_mm_tree(param, li.ref()); if (param->statement_should_be_aborted()) DBUG_RETURN(NULL); if (tree) { + if (tree->type == SEL_TREE::IMPOSSIBLE && + param->remove_false_where_parts) + { + /* See the other li.remove() call below */ + li.remove(); + if (((Item_cond*)cond)->argument_list()->elements <= 1) + replace_cond= true; + } + Item *item; while ((item=li++)) { - SEL_TREE *new_tree=get_mm_tree(param,item); + SEL_TREE *new_tree=get_mm_tree(param,li.ref()); if (new_tree == NULL || param->statement_should_be_aborted()) DBUG_RETURN(NULL); tree= tree_or(param,tree,new_tree); if (tree == NULL || tree->type == SEL_TREE::ALWAYS) + { + replacement_item= *li.ref(); break; + } + + if (new_tree && new_tree->type == SEL_TREE::IMPOSSIBLE && + param->remove_false_where_parts) + { + /* + This is a condition in form + + cond = item1 OR ... OR item_i OR ... itemN + + and item_i produces SEL_TREE(IMPOSSIBLE). We should remove item_i + from cond. This may cause 'cond' to become a degenerate, + one-way OR. In that case, we replace 'cond' with the remaining + item_i. + */ + li.remove(); + if (((Item_cond*)cond)->argument_list()->elements <= 1) + replace_cond= true; + } + else + replacement_item= *li.ref(); } + + if (replace_cond) + *cond_ptr= replacement_item; } } DBUG_RETURN(tree); diff --git a/sql/opt_range.h b/sql/opt_range.h index 1ca245ea420..f602408ea82 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -994,7 +994,7 @@ class SQL_SELECT :public Sql_alloc { { key_map tmp; tmp.set_all(); - return test_quick_select(thd, tmp, 0, limit, force_quick_range, FALSE) < 0; + return test_quick_select(thd, tmp, 0, limit, force_quick_range, FALSE, FALSE) < 0; } /* RETURN @@ -1011,7 +1011,7 @@ class SQL_SELECT :public Sql_alloc { } int test_quick_select(THD *thd, key_map keys, table_map prev_tables, ha_rows limit, bool force_quick_range, - bool ordered_output); + bool ordered_output, bool remove_false_parts_of_where); }; @@ -1036,7 +1036,7 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables, table_map read_tables, COND *conds, bool allow_null_cond, int *error); -bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item *cond); +bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond); #ifdef WITH_PARTITION_STORAGE_ENGINE bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 05c88a5f534..52f05e46e40 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -69,7 +69,7 @@ struct st_sargable_param; static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array); static bool make_join_statistics(JOIN *join, List &leaves, - COND *conds, DYNAMIC_ARRAY *keyuse); + DYNAMIC_ARRAY *keyuse); static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse, JOIN_TAB *join_tab, uint tables, COND *conds, @@ -1338,7 +1338,7 @@ TODO: make view to decide if it is possible to write to WHERE directly or make S /* Calculate how to do the join */ THD_STAGE_INFO(thd, stage_statistics); - if (make_join_statistics(this, select_lex->leaf_tables, conds, &keyuse) || + if (make_join_statistics(this, select_lex->leaf_tables, &keyuse) || thd->is_fatal_error) { DBUG_PRINT("error",("Error: make_join_statistics() failed")); @@ -3355,7 +3355,8 @@ static ha_rows get_quick_record_count(THD *thd, SQL_SELECT *select, select->head=table; table->reginfo.impossible_range=0; if ((error= select->test_quick_select(thd, *(key_map *)keys,(table_map) 0, - limit, 0, FALSE)) == 1) + limit, 0, FALSE, + TRUE /* remove_where_parts*/)) == 1) DBUG_RETURN(select->quick->records); if (error == -1) { @@ -3393,7 +3394,7 @@ typedef struct st_sargable_param static bool make_join_statistics(JOIN *join, List &tables_list, - COND *conds, DYNAMIC_ARRAY *keyuse_array) + DYNAMIC_ARRAY *keyuse_array) { int error= 0; TABLE *table; @@ -3597,10 +3598,10 @@ make_join_statistics(JOIN *join, List &tables_list, } } - if (conds || outer_join) + if (join->conds || outer_join) { if (update_ref_and_keys(join->thd, keyuse_array, stat, join->table_count, - conds, ~outer_join, join->select_lex, &sargables)) + join->conds, ~outer_join, join->select_lex, &sargables)) goto error; /* Keyparts without prefixes may be useful if this JOIN is a subquery, and @@ -3844,8 +3845,9 @@ make_join_statistics(JOIN *join, List &tables_list, } join->impossible_where= false; - if (conds && const_count) - { + if (join->conds && const_count) + { + Item* &conds= join->conds; conds->update_used_tables(); conds= remove_eq_conds(join->thd, conds, &join->cond_value); if (conds && conds->type() == Item::COND_ITEM && @@ -3857,7 +3859,7 @@ make_join_statistics(JOIN *join, List &tables_list, join->impossible_where= true; conds=new Item_int((longlong) 0,1); } - join->conds= conds; + join->cond_equal= NULL; if (conds) { @@ -3942,12 +3944,18 @@ make_join_statistics(JOIN *join, List &tables_list, { select= make_select(s->table, found_const_table_map, found_const_table_map, - *s->on_expr_ref ? *s->on_expr_ref : conds, + *s->on_expr_ref ? *s->on_expr_ref : join->conds, 1, &error); if (!select) goto error; records= get_quick_record_count(join->thd, select, s->table, &s->const_keys, join->row_limit); + /* Range analyzer could modify the condition. */ + if (*s->on_expr_ref) + *s->on_expr_ref= select->cond; + else + join->conds= select->cond; + s->quick=select->quick; s->needed_reg=select->needed_reg; select->quick=0; @@ -3958,7 +3966,7 @@ make_join_statistics(JOIN *join, List &tables_list, if (join->thd->variables.optimizer_use_condition_selectivity > 1) calculate_cond_selectivity_for_table(join->thd, s->table, *s->on_expr_ref ? - *s->on_expr_ref : conds); + s->on_expr_ref : &join->conds); if (s->table->reginfo.impossible_range) { impossible_range= TRUE; @@ -9658,7 +9666,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) OPTION_FOUND_ROWS ? HA_POS_ERROR : join->unit->select_limit_cnt), 0, - FALSE) < 0) + FALSE, FALSE) < 0) { /* Before reporting "Impossible WHERE" for the whole query @@ -9672,7 +9680,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) OPTION_FOUND_ROWS ? HA_POS_ERROR : join->unit->select_limit_cnt),0, - FALSE) < 0) + FALSE, FALSE) < 0) DBUG_RETURN(1); // Impossible WHERE } else @@ -18496,7 +18504,7 @@ test_if_quick_select(JOIN_TAB *tab) tab->select->quick=0; return tab->select->test_quick_select(tab->join->thd, tab->keys, (table_map) 0, HA_POS_ERROR, 0, - FALSE); + FALSE, /*remove where parts*/FALSE); } @@ -20169,7 +20177,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, OPTION_FOUND_ROWS) ? HA_POS_ERROR : tab->join->unit->select_limit_cnt,0, - TRUE) <= 0; + TRUE, FALSE) <= 0; if (res) { select->cond= save_cond; @@ -20227,7 +20235,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, join->select_options & OPTION_FOUND_ROWS ? HA_POS_ERROR : join->unit->select_limit_cnt, - TRUE, FALSE); + TRUE, FALSE, FALSE); } order_direction= best_key_direction; /* From f1a1683309899e484c0c0d38933530dcd5012c75 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Wed, 27 Aug 2014 20:08:32 +0400 Subject: [PATCH 024/153] MDEV-6384: It seems like OPTIMIZER take into account the order of indexes in the table When ORDER BY ... LIMIT check whether it should switch from index IDX1 to index IDX2, it should not ignore the fact that IDX2 may have a potential range or ref(const) access. Istead, it should calculate their costs: there is now a saved range optimizer cost and code to re-calculate what best_access_path() calculated for ref(const). /* in current cost model these two can be very different numbers unfortunately */ --- mysql-test/r/innodb_ext_key.result | 2 +- sql/opt_range.cc | 1 + sql/sql_select.cc | 118 ++++++++++++++++++++++++++++- 3 files changed, 119 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/innodb_ext_key.result b/mysql-test/r/innodb_ext_key.result index 9140f306f77..cae402a9f12 100644 --- a/mysql-test/r/innodb_ext_key.result +++ b/mysql-test/r/innodb_ext_key.result @@ -1002,7 +1002,7 @@ insert into t2 (b) values (null), (null), (null); set optimizer_switch='extended_keys=on'; explain select a from t1 where b is null order by a desc limit 2; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref b b 9 const 2 Using where; Using filesort +1 SIMPLE t1 index b PRIMARY 8 NULL 3 Using where select a from t1 where b is null order by a desc limit 2; a 3 diff --git a/sql/opt_range.cc b/sql/opt_range.cc index b795411130d..99c731d1541 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -10690,6 +10690,7 @@ ha_rows check_quick_select(PARAM *param, uint idx, bool index_only, param->table->quick_condition_rows= MY_MIN(param->table->quick_condition_rows, rows); param->table->quick_rows[keynr]= rows; + param->table->quick_costs[keynr]= cost->total_cost(); } } /* Figure out if the key scan is ROR (returns rows in ROWID order) or not */ diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 52f05e46e40..79d74d02708 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -20224,7 +20224,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, !(table->file->index_flags(best_key, 0, 1) & HA_CLUSTERED_INDEX))) goto use_filesort; - if (select && + if (select && // psergey: why doesn't this use a quick? table->quick_keys.is_set(best_key) && best_key != ref_key) { key_map map; @@ -24693,6 +24693,109 @@ void JOIN::cache_const_exprs() } } + +/* + Get a cost of reading rows_limit rows through index keynr. + + @detail + - If there is a quick select, we try to use it. + - if there is a ref(const) access, we try to use it, too. + - quick and ref(const) use different cost formulas, so if both are possible + we should make a cost-based choice. + + @return + true There was a possible quick or ref access, its cost is in the OUT + parameters. + false No quick or ref(const) possible (and so, the caller will attempt + to use a full index scan on this index). +*/ + +static bool get_range_limit_read_cost(const JOIN_TAB *tab, + const TABLE *table, + uint keynr, + ha_rows rows_limit, + double *read_time) +{ + bool res= false; + /* + We need to adjust the estimates if we had a quick select (or ref(const)) on + index keynr. + */ + if (table->quick_keys.is_set(keynr)) + { + /* + Start from quick select's rows and cost. These are always cheaper than + full index scan/cost. + */ + double best_rows= table->quick_rows[keynr]; + double best_cost= table->quick_costs[keynr]; + + /* + Check if ref(const) access was possible on this index. + */ + if (tab) + { + key_part_map const_parts= 0; + key_part_map map= 1; + uint kp; + /* Find how many key parts would be used by ref(const) */ + for (kp=0; kp < MAX_REF_PARTS; map=map << 1, kp++) + { + if (!(table->const_key_parts[keynr] & map)) + break; + const_parts |= map; + } + + if (kp > 0) + { + ha_rows ref_rows; + /* + Two possible cases: + 1. ref(const) uses the same #key parts as range access. + 2. ref(const) uses fewer key parts, becasue there is a + range_cond(key_part+1). + */ + if (kp == table->quick_key_parts[keynr]) + ref_rows= table->quick_rows[keynr]; + else + ref_rows= table->key_info[keynr].actual_rec_per_key(kp-1); + + if (ref_rows > 0) + { + double tmp= ref_rows; + /* Reuse the cost formula from best_access_path: */ + set_if_smaller(tmp, (double) tab->join->thd->variables.max_seeks_for_key); + if (table->covering_keys.is_set(keynr)) + tmp= table->file->keyread_time(keynr, 1, (ha_rows) tmp); + else + tmp= table->file->read_time(keynr, 1, + (ha_rows) MY_MIN(tmp,tab->worst_seeks)); + if (tmp < best_cost) + { + best_cost= tmp; + best_rows= ref_rows; + } + } + } + } + + if (best_rows > rows_limit) + { + /* + LIMIT clause specifies that we will need to read fewer records than + quick select will return. Assume that quick select's cost is + proportional to the number of records we need to return (e.g. if we + only need 1/3rd of records, it will cost us 1/3rd of quick select's + read time) + */ + best_cost *= rows_limit / best_rows; + } + *read_time= best_cost; + res= true; + } + return res; +} + /** Find a cheaper access key than a given @a key @@ -24786,6 +24889,11 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table, } else read_time= table->file->scan_time(); + + /* + TODO: add cost of sorting here. + */ + read_time += COST_EPS; /* Calculate the selectivity of the ref_key for REF_ACCESS. For @@ -24945,6 +25053,14 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table, */ index_scan_time= select_limit/rec_per_key * MY_MIN(rec_per_key, table->file->scan_time()); + double range_scan_time; + if (get_range_limit_read_cost(tab, table, nr, select_limit, + &range_scan_time)) + { + if (range_scan_time < index_scan_time) + index_scan_time= range_scan_time; + } + if ((ref_key < 0 && (group || table->force_index || is_covering)) || index_scan_time < read_time) { From 8cd08717f6eecd1a7b5c58349d2c8da52e985156 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 27 Aug 2014 19:53:19 +0300 Subject: [PATCH 025/153] Move galera_sst_mode test to correct location. This test tests mysqldump option. --- mysql-test/{suite/galera => }/r/galera_sst_mode.result | 0 mysql-test/{suite/galera => }/t/galera_sst_mode.test | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename mysql-test/{suite/galera => }/r/galera_sst_mode.result (100%) rename mysql-test/{suite/galera => }/t/galera_sst_mode.test (100%) diff --git a/mysql-test/suite/galera/r/galera_sst_mode.result b/mysql-test/r/galera_sst_mode.result similarity index 100% rename from mysql-test/suite/galera/r/galera_sst_mode.result rename to mysql-test/r/galera_sst_mode.result diff --git a/mysql-test/suite/galera/t/galera_sst_mode.test b/mysql-test/t/galera_sst_mode.test similarity index 100% rename from mysql-test/suite/galera/t/galera_sst_mode.test rename to mysql-test/t/galera_sst_mode.test From 422b99ed87cab7b6acdb86be0a8b424db1213af2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 27 Aug 2014 20:00:13 +0300 Subject: [PATCH 026/153] Fix incorrect merge. --- storage/innobase/lock/lock0lock.cc | 1 - storage/xtradb/lock/lock0lock.cc | 1 - 2 files changed, 2 deletions(-) diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 564e43e9bfa..5265d3c8cf5 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -6072,7 +6072,6 @@ lock_rec_queue_validate( } ut_a(!lock_rec_other_has_expl_req( mode, 0, 0, block, heap_no, lock->trx)); - } #endif /* WITH_WSREP */ } else if (lock_get_wait(lock) && !lock_rec_get_gap(lock)) { diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc index ede6dd47b90..d308e04d07d 100644 --- a/storage/xtradb/lock/lock0lock.cc +++ b/storage/xtradb/lock/lock0lock.cc @@ -6122,7 +6122,6 @@ lock_rec_queue_validate( } ut_a(!lock_rec_other_has_expl_req( mode, 0, 0, block, heap_no, lock->trx->id)); - } #endif /* WITH_WSREP */ } else if (lock_get_wait(lock) && !lock_rec_get_gap(lock)) { From f883f3ef868fb7471dafdd9b21f1f50ab98bda85 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 12 Aug 2014 14:05:35 +0200 Subject: [PATCH 027/153] git: ignore errmsg.sys and typescript, better diff header for C/C++ files --- .gitattributes | 5 +++++ .gitignore | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000000..cdfedef671f --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +*.c diff=cpp +*.h diff=cpp +*.cc diff=cpp +*.ic diff=cpp +*.cpp diff=cpp diff --git a/.gitignore b/.gitignore index 3a3733470fc..24d82cb758c 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,8 @@ *.ninja .ninja_* .gdb_history +errmsg.sys +typescript CMakeCache.txt CMakeFiles/ CPackConfig.cmake @@ -132,7 +134,6 @@ sql/gen_lex_hash sql/lex_hash.h sql/mysql_tzinfo_to_sql sql/mysqld -sql/share/*/errmsg.sys sql/sql_builtin.cc sql/sql_yacc.cc sql/sql_yacc.h From f8f8a59c189254baeb7f90920b6b23da227984e8 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Wed, 27 Aug 2014 23:31:27 +0400 Subject: [PATCH 028/153] Forgot one file in previous commit --- sql/table.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/table.h b/sql/table.h index b57e9c7227d..bbe4b181339 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1113,6 +1113,7 @@ public: and max #key parts that range access would use. */ ha_rows quick_rows[MAX_KEY]; + double quick_costs[MAX_KEY]; /* Bitmaps of key parts that =const for the duration of join execution. If From eff5ef77dd1b8d2d407fe94b4d296c6c808b43b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Thu, 28 Aug 2014 06:49:58 +0300 Subject: [PATCH 029/153] Rule for configure wsrep-notify was missing. --- support-files/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/support-files/CMakeLists.txt b/support-files/CMakeLists.txt index 19f6bc14663..adfcb155d84 100644 --- a/support-files/CMakeLists.txt +++ b/support-files/CMakeLists.txt @@ -50,7 +50,7 @@ ENDFOREACH() IF(UNIX) SET(prefix ${CMAKE_INSTALL_PREFIX}) - FOREACH(script mysqld_multi.server mysql-log-rotate binary-configure) + FOREACH(script mysqld_multi.server mysql-log-rotate binary-configure wsrep-notify) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/${script}.sh ${CMAKE_CURRENT_BINARY_DIR}/${script} @ONLY ) From 5a684f829159bf4d6c2ec76479a33d1e5649b8f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Thu, 28 Aug 2014 07:01:06 +0300 Subject: [PATCH 030/153] Fix typo. --- support-files/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/support-files/CMakeLists.txt b/support-files/CMakeLists.txt index adfcb155d84..e9abb63a7dc 100644 --- a/support-files/CMakeLists.txt +++ b/support-files/CMakeLists.txt @@ -50,7 +50,7 @@ ENDFOREACH() IF(UNIX) SET(prefix ${CMAKE_INSTALL_PREFIX}) - FOREACH(script mysqld_multi.server mysql-log-rotate binary-configure wsrep-notify) + FOREACH(script mysqld_multi.server mysql-log-rotate binary-configure wsrep_notify) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/${script}.sh ${CMAKE_CURRENT_BINARY_DIR}/${script} @ONLY ) From e44751b65f4760067d15f8a526e8f97f84810c29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Fri, 29 Aug 2014 10:11:08 +0300 Subject: [PATCH 031/153] Merge revision 3882 from lp:maria/maria-10.0-galera MDEV-6656: Test wsrep.variables hangs Analysis: wsrep_applier_thread shutdown signaling does not always work correctly causing a timing problem where main thread is waiting in a condition variable a signal that all worker threads to end. --- mysql-test/suite/wsrep/r/variables.result | 3 -- mysql-test/suite/wsrep/t/variables.test | 3 +- sql/wsrep_mysqld.cc | 53 +++-------------------- 3 files changed, 6 insertions(+), 53 deletions(-) diff --git a/mysql-test/suite/wsrep/r/variables.result b/mysql-test/suite/wsrep/r/variables.result index bd762f916bc..438e4730f57 100644 --- a/mysql-test/suite/wsrep/r/variables.result +++ b/mysql-test/suite/wsrep/r/variables.result @@ -195,9 +195,6 @@ SET GLOBAL wsrep_slave_threads= 10; SHOW STATUS LIKE 'threads_connected'; Variable_name Value Threads_connected 1 -SHOW STATUS LIKE 'wsrep_thread_count'; -Variable_name Value -wsrep_thread_count 11 SET GLOBAL wsrep_slave_threads= @wsrep_slave_threads_saved; SET GLOBAL wsrep_provider= none; SET GLOBAL wsrep_cluster_address= ''; diff --git a/mysql-test/suite/wsrep/t/variables.test b/mysql-test/suite/wsrep/t/variables.test index 6cc895a75d9..22f4c6cb940 100644 --- a/mysql-test/suite/wsrep/t/variables.test +++ b/mysql-test/suite/wsrep/t/variables.test @@ -120,9 +120,8 @@ SHOW STATUS LIKE 'wsrep_thread_count'; SET @wsrep_slave_threads_saved= @@global.wsrep_slave_threads; SET GLOBAL wsrep_slave_threads= 10; --echo # Wait for applier threads to get created. -sleep 3; +sleep 5; SHOW STATUS LIKE 'threads_connected'; -SHOW STATUS LIKE 'wsrep_thread_count'; # reset (for mtr internal checks) SET GLOBAL wsrep_slave_threads= @wsrep_slave_threads_saved; diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index c1b15bd02c2..c74bb528ebd 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -1711,7 +1711,7 @@ static bool abort_replicated(THD *thd) bool ret_code= false; if (thd->wsrep_query_state== QUERY_COMMITTING) { - if (wsrep_debug) WSREP_INFO("aborting replicated trx: %lu", thd->real_id); + WSREP_DEBUG("aborting replicated trx: %lu", thd->real_id); (void)wsrep_abort_thd(thd, thd, TRUE); ret_code= true; @@ -1769,24 +1769,6 @@ static bool have_client_connections() return false; } -/* - returns the number of wsrep appliers running. - However, the caller (thd parameter) is not taken in account - */ -static int have_wsrep_appliers(THD *thd) -{ - int ret= 0; - THD *tmp; - - I_List_iterator it(threads); - while ((tmp=it++)) - { - ret+= (tmp != thd && tmp->wsrep_applier); - } - return ret; -} - - static void wsrep_close_thread(THD *thd) { thd->killed= KILL_CONNECTION; @@ -1894,7 +1876,7 @@ void wsrep_close_client_connections(my_bool wait_to_end) while ((tmp=it2++)) { #ifndef __bsdi__ // Bug in BSDI kernel - if (is_client_connection(tmp) && + if (is_client_connection(tmp) && !abort_replicated(tmp) && !is_replaying_connection(tmp)) { @@ -1905,8 +1887,7 @@ void wsrep_close_client_connections(my_bool wait_to_end) } DBUG_PRINT("quit",("Waiting for threads to die (count=%u)",thread_count)); - if (wsrep_debug) - WSREP_INFO("waiting for client connections to close: %u", thread_count); + WSREP_DEBUG("waiting for client connections to close: %u", thread_count); while (wait_to_end && have_client_connections()) { @@ -1950,35 +1931,11 @@ void wsrep_close_threads(THD *thd) mysql_mutex_unlock(&LOCK_thread_count); } - -void wsrep_close_applier_threads(int count) -{ - THD *tmp; - mysql_mutex_lock(&LOCK_thread_count); // For unlink from list - - I_List_iterator it(threads); - while ((tmp=it++) && count) - { - DBUG_PRINT("quit",("Informing thread %ld that it's time to die", - tmp->thread_id)); - /* We skip slave threads & scheduler on this first loop through. */ - if (tmp->wsrep_applier) - { - WSREP_DEBUG("closing wsrep applier thread %ld", tmp->thread_id); - tmp->wsrep_applier_closing= TRUE; - count--; - } - } - - mysql_mutex_unlock(&LOCK_thread_count); -} - - void wsrep_wait_appliers_close(THD *thd) { /* Wait for wsrep appliers to gracefully exit */ mysql_mutex_lock(&LOCK_thread_count); - while (have_wsrep_appliers(thd) > 1) + while (wsrep_running_threads > 1) // 1 is for rollbacker thread which needs to be killed explicitly. // This gotta be fixed in a more elegant manner if we gonna have arbitrary // number of non-applier wsrep threads. @@ -1998,7 +1955,7 @@ void wsrep_wait_appliers_close(THD *thd) wsrep_close_threads (thd); /* and wait for them to die */ mysql_mutex_lock(&LOCK_thread_count); - while (have_wsrep_appliers(thd) > 0) + while (wsrep_running_threads > 0) { if (thread_handling > SCHEDULER_ONE_THREAD_PER_CONNECTION) { From c945233a192d559695b83a252b61168e7611ea03 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Tue, 2 Sep 2014 18:54:29 +0400 Subject: [PATCH 032/153] MDEV-6657: Poor plan choice for ORDER BY key DESC optimization... The problem was caused by the following scenario: - range optimizer picks an index IDX1 which doesn't match the ORDER BY ... LIMIT clause. - test_if_skip_sort_order() decides to switch to index IDX2 which matches the ORDER BY ... LIMIT. - it runs SQL_SELECT::test_quick_select() for the second time to produce an quick select for IDX2. - However, test_quick_select() would figure that full index scan on IDX1 is still cheaper (its calculations ignore the LIMIT n). Fixed this by - passing force_quick_range=true to test_quick_select() - in test_quick_select, don't consider full index scans if the mentioned parameter is true. Numerous changes in .result files are caused by test_quick_select() being run after "early/late NULLs filtering" feature has injected NOT NULL condition. --- .../r/myisam_explain_non_select_all.result | 4 +- mysql-test/r/order_by.result | 6 +-- mysql-test/r/show_explain.result | 4 +- mysql-test/r/subselect.result | 4 +- mysql-test/r/subselect_mat.result | 2 +- mysql-test/r/subselect_no_exists_to_in.result | 4 +- mysql-test/r/subselect_no_mat.result | 4 +- mysql-test/r/subselect_no_opts.result | 4 +- mysql-test/r/subselect_no_scache.result | 4 +- mysql-test/r/subselect_no_semijoin.result | 4 +- mysql-test/r/subselect_sj_mat.result | 2 +- sql/opt_range.cc | 2 +- sql/sql_select.cc | 8 ++- .../tokudb_mariadb/r/mdev6657.result | 47 ++++++++++++++++ .../mysql-test/tokudb_mariadb/t/mdev6657.test | 53 +++++++++++++++++++ 15 files changed, 129 insertions(+), 23 deletions(-) create mode 100644 storage/tokudb/mysql-test/tokudb_mariadb/r/mdev6657.result create mode 100644 storage/tokudb/mysql-test/tokudb_mariadb/t/mdev6657.test diff --git a/mysql-test/r/myisam_explain_non_select_all.result b/mysql-test/r/myisam_explain_non_select_all.result index 285a1ca6786..a9eeee8548c 100644 --- a/mysql-test/r/myisam_explain_non_select_all.result +++ b/mysql-test/r/myisam_explain_non_select_all.result @@ -674,14 +674,14 @@ FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 WHERE t1.a > 0 ORDER BY t1.a; id select_type table type possible_keys key key_len ref rows filtered Extra -1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 3 100.00 Using where; Using index +1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 3 100.00 Using where; Using index Warnings: Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` > 0) order by `test`.`t1`.`a` # Status of EXPLAIN EXTENDED "equivalent" SELECT query execution Variable_name Value # Status of "equivalent" SELECT query execution: Variable_name Value -Handler_read_first 1 +Handler_read_key 1 Handler_read_next 3 # Status of testing query execution: Variable_name Value diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index 294142737d9..aba8d6c201c 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -297,7 +297,7 @@ create table t1 (a int not null, b int, c varchar(10), key (a, b, c)); insert into t1 values (1, NULL, NULL), (1, NULL, 'b'), (1, 1, NULL), (1, 1, 'b'), (1, 1, 'b'), (2, 1, 'a'), (2, 1, 'b'), (2, 2, 'a'), (2, 2, 'b'), (2, 3, 'c'),(1,3,'b'); explain select * from t1 where (a = 1 and b is null and c = 'b') or (a > 2) order by a desc; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index a a 22 NULL 11 Using where; Using index +1 SIMPLE t1 range a a 22 NULL 2 Using where; Using index select * from t1 where (a = 1 and b is null and c = 'b') or (a > 2) order by a desc; a b c 1 NULL b @@ -2569,7 +2569,7 @@ SELECT * FROM t1 r JOIN t1 s ON r.a = s.a WHERE s.a IN (2,9) OR s.a < 100 AND s.a != 0 ORDER BY 1 LIMIT 10; id select_type table type possible_keys key key_len ref rows filtered Extra -1 SIMPLE r index PRIMARY PRIMARY 4 NULL 10 100.00 Using where; Using index +1 SIMPLE r range PRIMARY PRIMARY 4 NULL 12 100.00 Using where; Using index 1 SIMPLE s eq_ref PRIMARY PRIMARY 4 test.r.a 1 100.00 Using index Warnings: Note 1003 select `test`.`r`.`a` AS `a`,`test`.`s`.`a` AS `a` from `test`.`t1` `r` join `test`.`t1` `s` where ((`test`.`s`.`a` = `test`.`r`.`a`) and ((`test`.`r`.`a` in (2,9)) or ((`test`.`r`.`a` < 100) and (`test`.`r`.`a` <> 0)))) order by 1 limit 10 @@ -2600,7 +2600,7 @@ CREATE TABLE t1 (a INT,KEY (a)); INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); EXPLAIN SELECT DISTINCT a,1 FROM t1 WHERE a <> 1 ORDER BY a DESC; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index a a 5 NULL 10 Using where; Using index; Using filesort +1 SIMPLE t1 range a a 5 NULL 10 Using where; Using index SELECT DISTINCT a,1 FROM t1 WHERE a <> 1 ORDER BY a DESC; a 1 10 1 diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index 3695384bac4..8aefb552d57 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -1036,7 +1036,7 @@ explain SELECT b AS field1, b AS field2 FROM t1, t2, t3 WHERE d = b ORDER BY field1, field2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 system NULL NULL NULL NULL 1 -1 SIMPLE t1 index b b 6 NULL 107 Using where; Using index +1 SIMPLE t1 range b b 6 NULL 107 Using where; Using index 1 SIMPLE t3 ref PRIMARY PRIMARY 5 test.t1.b 1 Using index set @show_explain_probe_select_id=1; set debug_dbug='+d,show_explain_probe_do_select'; @@ -1044,7 +1044,7 @@ SELECT b AS field1, b AS field2 FROM t1, t2, t3 WHERE d = b ORDER BY field1, fie show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 system NULL NULL NULL NULL 1 Using filesort -1 SIMPLE t1 index b b 6 NULL 107 Using where; Using index +1 SIMPLE t1 range b b 6 NULL 107 Using where; Using index 1 SIMPLE t3 ref PRIMARY PRIMARY 5 test.t1.b 1 Using index Warnings: Note 1003 SELECT b AS field1, b AS field2 FROM t1, t2, t3 WHERE d = b ORDER BY field1, field2 diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 5678a455234..55184f42c97 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -6974,7 +6974,7 @@ INSERT INTO t2 VALUES (45),(17),(20); EXPLAIN SELECT * FROM t1 WHERE EXISTS ( SELECT a FROM t1, t2 WHERE b = a GROUP BY a HAVING a <> 1 ) ; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE -2 SUBQUERY t1 index a a 5 NULL 2 Using where; Using index +2 SUBQUERY t1 range a a 5 NULL 2 Using where; Using index 2 SUBQUERY t2 ref b b 5 test.t1.a 2 Using index DROP TABLE t1,t2; # @@ -7008,7 +7008,7 @@ INSERT INTO t2 VALUES (45),(17),(20); EXPLAIN SELECT * FROM t1 WHERE EXISTS ( SELECT a FROM t1, t2 WHERE b = a GROUP BY a HAVING a <> 1 ) ; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE -2 SUBQUERY t1 index a a 5 NULL 2 Using where; Using index +2 SUBQUERY t1 range a a 5 NULL 2 Using where; Using index 2 SUBQUERY t2 ref b b 5 test.t1.a 2 Using index DROP TABLE t1,t2; # diff --git a/mysql-test/r/subselect_mat.result b/mysql-test/r/subselect_mat.result index 6cc627ad16c..30b020cbcf6 100644 --- a/mysql-test/r/subselect_mat.result +++ b/mysql-test/r/subselect_mat.result @@ -103,7 +103,7 @@ explain extended select * from t1i where a1 in (select max(b1) from t2i where b1 > '0' group by b1); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1i index NULL # 18 # 3 100.00 # -2 MATERIALIZED t2i index it2i1,it2i3 # 9 # 5 100.00 # +2 MATERIALIZED t2i range it2i1,it2i3 # 9 # 5 100.00 # Warnings: Note 1003 select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where <`test`.`t1i`.`a1`>((`test`.`t1i`.`a1`,`test`.`t1i`.`a1` in ( (select max(`test`.`t2i`.`b1`) from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') group by `test`.`t2i`.`b1` ), (`test`.`t1i`.`a1` in on distinct_key where ((`test`.`t1i`.`a1` = ``.`max(b1)`)))))) select * from t1i where a1 in (select max(b1) from t2i where b1 > '0' group by b1); diff --git a/mysql-test/r/subselect_no_exists_to_in.result b/mysql-test/r/subselect_no_exists_to_in.result index 5434bb920e3..58ee06d754d 100644 --- a/mysql-test/r/subselect_no_exists_to_in.result +++ b/mysql-test/r/subselect_no_exists_to_in.result @@ -6974,7 +6974,7 @@ INSERT INTO t2 VALUES (45),(17),(20); EXPLAIN SELECT * FROM t1 WHERE EXISTS ( SELECT a FROM t1, t2 WHERE b = a GROUP BY a HAVING a <> 1 ) ; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE -2 SUBQUERY t1 index a a 5 NULL 2 Using where; Using index +2 SUBQUERY t1 range a a 5 NULL 2 Using where; Using index 2 SUBQUERY t2 ref b b 5 test.t1.a 2 Using index DROP TABLE t1,t2; # @@ -7008,7 +7008,7 @@ INSERT INTO t2 VALUES (45),(17),(20); EXPLAIN SELECT * FROM t1 WHERE EXISTS ( SELECT a FROM t1, t2 WHERE b = a GROUP BY a HAVING a <> 1 ) ; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE -2 SUBQUERY t1 index a a 5 NULL 2 Using where; Using index +2 SUBQUERY t1 range a a 5 NULL 2 Using where; Using index 2 SUBQUERY t2 ref b b 5 test.t1.a 2 Using index DROP TABLE t1,t2; # diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result index 3325889e1e0..53307efdb89 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -6968,7 +6968,7 @@ INSERT INTO t2 VALUES (45),(17),(20); EXPLAIN SELECT * FROM t1 WHERE EXISTS ( SELECT a FROM t1, t2 WHERE b = a GROUP BY a HAVING a <> 1 ) ; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE -2 SUBQUERY t1 index a a 5 NULL 2 Using where; Using index +2 SUBQUERY t1 range a a 5 NULL 2 Using where; Using index 2 SUBQUERY t2 ref b b 5 test.t1.a 2 Using index DROP TABLE t1,t2; # @@ -7001,7 +7001,7 @@ INSERT INTO t2 VALUES (45),(17),(20); EXPLAIN SELECT * FROM t1 WHERE EXISTS ( SELECT a FROM t1, t2 WHERE b = a GROUP BY a HAVING a <> 1 ) ; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE -2 SUBQUERY t1 index a a 5 NULL 2 Using where; Using index +2 SUBQUERY t1 range a a 5 NULL 2 Using where; Using index 2 SUBQUERY t2 ref b b 5 test.t1.a 2 Using index DROP TABLE t1,t2; # diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result index 01af3ea4b16..c228ae46347 100644 --- a/mysql-test/r/subselect_no_opts.result +++ b/mysql-test/r/subselect_no_opts.result @@ -6965,7 +6965,7 @@ INSERT INTO t2 VALUES (45),(17),(20); EXPLAIN SELECT * FROM t1 WHERE EXISTS ( SELECT a FROM t1, t2 WHERE b = a GROUP BY a HAVING a <> 1 ) ; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE -2 SUBQUERY t1 index a a 5 NULL 2 Using where; Using index +2 SUBQUERY t1 range a a 5 NULL 2 Using where; Using index 2 SUBQUERY t2 ref b b 5 test.t1.a 2 Using index DROP TABLE t1,t2; # @@ -6999,7 +6999,7 @@ INSERT INTO t2 VALUES (45),(17),(20); EXPLAIN SELECT * FROM t1 WHERE EXISTS ( SELECT a FROM t1, t2 WHERE b = a GROUP BY a HAVING a <> 1 ) ; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE -2 SUBQUERY t1 index a a 5 NULL 2 Using where; Using index +2 SUBQUERY t1 range a a 5 NULL 2 Using where; Using index 2 SUBQUERY t2 ref b b 5 test.t1.a 2 Using index DROP TABLE t1,t2; # diff --git a/mysql-test/r/subselect_no_scache.result b/mysql-test/r/subselect_no_scache.result index 16ebf7a4199..7d1dde6498e 100644 --- a/mysql-test/r/subselect_no_scache.result +++ b/mysql-test/r/subselect_no_scache.result @@ -6980,7 +6980,7 @@ INSERT INTO t2 VALUES (45),(17),(20); EXPLAIN SELECT * FROM t1 WHERE EXISTS ( SELECT a FROM t1, t2 WHERE b = a GROUP BY a HAVING a <> 1 ) ; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE -2 SUBQUERY t1 index a a 5 NULL 2 Using where; Using index +2 SUBQUERY t1 range a a 5 NULL 2 Using where; Using index 2 SUBQUERY t2 ref b b 5 test.t1.a 2 Using index DROP TABLE t1,t2; # @@ -7014,7 +7014,7 @@ INSERT INTO t2 VALUES (45),(17),(20); EXPLAIN SELECT * FROM t1 WHERE EXISTS ( SELECT a FROM t1, t2 WHERE b = a GROUP BY a HAVING a <> 1 ) ; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE -2 SUBQUERY t1 index a a 5 NULL 2 Using where; Using index +2 SUBQUERY t1 range a a 5 NULL 2 Using where; Using index 2 SUBQUERY t2 ref b b 5 test.t1.a 2 Using index DROP TABLE t1,t2; # diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result index d98f7ad67de..c850644fbaa 100644 --- a/mysql-test/r/subselect_no_semijoin.result +++ b/mysql-test/r/subselect_no_semijoin.result @@ -6965,7 +6965,7 @@ INSERT INTO t2 VALUES (45),(17),(20); EXPLAIN SELECT * FROM t1 WHERE EXISTS ( SELECT a FROM t1, t2 WHERE b = a GROUP BY a HAVING a <> 1 ) ; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE -2 SUBQUERY t1 index a a 5 NULL 2 Using where; Using index +2 SUBQUERY t1 range a a 5 NULL 2 Using where; Using index 2 SUBQUERY t2 ref b b 5 test.t1.a 2 Using index DROP TABLE t1,t2; # @@ -6999,7 +6999,7 @@ INSERT INTO t2 VALUES (45),(17),(20); EXPLAIN SELECT * FROM t1 WHERE EXISTS ( SELECT a FROM t1, t2 WHERE b = a GROUP BY a HAVING a <> 1 ) ; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE -2 SUBQUERY t1 index a a 5 NULL 2 Using where; Using index +2 SUBQUERY t1 range a a 5 NULL 2 Using where; Using index 2 SUBQUERY t2 ref b b 5 test.t1.a 2 Using index DROP TABLE t1,t2; # diff --git a/mysql-test/r/subselect_sj_mat.result b/mysql-test/r/subselect_sj_mat.result index 95dfc34777b..7417ab56ff8 100644 --- a/mysql-test/r/subselect_sj_mat.result +++ b/mysql-test/r/subselect_sj_mat.result @@ -107,7 +107,7 @@ select * from t1i where a1 in (select max(b1) from t2i where b1 > '0' group by b id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1i index it1i1,it1i3 # 18 # 3 100.00 # 1 PRIMARY eq_ref distinct_key # 8 # 1 100.00 # -2 MATERIALIZED t2i index it2i1,it2i3 # 9 # 5 100.00 # +2 MATERIALIZED t2i range it2i1,it2i3 # 9 # 5 100.00 # Warnings: Note 1003 select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from (select max(`test`.`t2i`.`b1`) from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') group by `test`.`t2i`.`b1`) join `test`.`t1i` where (``.`max(b1)` = `test`.`t1i`.`a1`) select * from t1i where a1 in (select max(b1) from t2i where b1 > '0' group by b1); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 2616e044025..7a584eed742 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -3056,7 +3056,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, param.alloced_sel_args= 0; /* Calculate cost of full index read for the shortest covering index */ - if (!head->covering_keys.is_clear_all()) + if (!force_quick_range && !head->covering_keys.is_clear_all()) { int key_for_use= find_shortest_key(head, &head->covering_keys); double key_read_time= head->file->keyread_time(key_for_use, 1, records) + diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 05c88a5f534..860f0cd346c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -20168,7 +20168,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, (tab->join->select_options & OPTION_FOUND_ROWS) ? HA_POS_ERROR : - tab->join->unit->select_limit_cnt,0, + tab->join->unit->select_limit_cnt,TRUE, TRUE) <= 0; if (res) { @@ -20286,6 +20286,12 @@ check_reverse_order: */ if (!table->covering_keys.is_set(best_key)) table->disable_keyread(); + else + { + if (!table->key_read) + table->enable_keyread(); + } + if (!quick_created) { if (select) // Throw any existing quick select diff --git a/storage/tokudb/mysql-test/tokudb_mariadb/r/mdev6657.result b/storage/tokudb/mysql-test/tokudb_mariadb/r/mdev6657.result new file mode 100644 index 00000000000..a09e2f2010e --- /dev/null +++ b/storage/tokudb/mysql-test/tokudb_mariadb/r/mdev6657.result @@ -0,0 +1,47 @@ +drop table if exists t1,t2,t3; +create table t1(a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2(a int); +insert into t2 select A.a + B.a* 10 + C.a * 100 from t1 A, t1 B, t1 C; +CREATE TABLE t3 ( +col1 int(10) unsigned NOT NULL DEFAULT '0', +col2 mediumint(8) unsigned NOT NULL DEFAULT '0', +col3 smallint(5) NOT NULL DEFAULT '1', +filler varchar(255) DEFAULT NULL, +PRIMARY KEY (col1,col2,col3), +KEY key1 (col1,col2) USING BTREE +) ENGINE=TokuDB DEFAULT CHARSET=latin1 PACK_KEYS=1 COMPRESSION=TOKUDB_LZMA; +insert into t3 select 1300000000+a, 12345, 7890, 'data' from t2; +insert into t3 select 1400000000+a, 12345, 7890, 'data' from t2; +insert into t3 select 1410799999+a, 12345, 7890, 'data' from t2; +insert into t3 select 1410899999+a, 12345, 7890, 'data' from t2; +insert into t3 select 1410999999+a, 12345, 7890, 'data' from t2; +insert into t3 select 1411099999+a, 12345, 7890, 'data' from t2; +insert into t3 select 1411199999+a, 12345, 7890, 'data' from t2; +insert into t3 select 1411299999+a, 12345, 7890, 'data' from t2; +insert into t3 select 1411399999+a, 12345, 7890, 'data' from t2; +insert into t3 select 1411499999+a, 12345, 7890, 'data' from t2; +insert into t3 select 1411599999+a, 12345, 7890, 'data' from t2; +insert into t3 select 1411699999+a, 12345, 7890, 'data' from t2; +insert into t3 select 1411899999+a, 12345, 7890, 'data' from t2; +insert into t3 select 1411999999+a, 12345, 7890, 'data' from t2; +insert into t3 select 1412099999+a, 12345, 7890, 'data' from t2; +insert into t3 select 1412199999+a, 12345, 7890, 'data' from t2; +# The following must use range(PRIMARY): +explain +select col1,col2,col3 +from t3 +where col1 <= 1410799999 +order by col1 desc,col2 desc,col3 desc limit 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 range PRIMARY,key1 PRIMARY 4 NULL 2001 Using where; Using index +# The same query but the constant is bigger. +# The query should use range(PRIMARY), not full index scan: +explain +select col1,col2,col3 +from t3 +where col1 <= 1412199999 +order by col1 desc, col2 desc, col3 desc limit 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 range PRIMARY,key1 PRIMARY 4 NULL 15001 Using where; Using index +drop table t1,t2,t3; diff --git a/storage/tokudb/mysql-test/tokudb_mariadb/t/mdev6657.test b/storage/tokudb/mysql-test/tokudb_mariadb/t/mdev6657.test new file mode 100644 index 00000000000..636dee1cde8 --- /dev/null +++ b/storage/tokudb/mysql-test/tokudb_mariadb/t/mdev6657.test @@ -0,0 +1,53 @@ +--disable_warnings +drop table if exists t1,t2,t3; +--enable_warnings + +create table t1(a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); + +create table t2(a int); +insert into t2 select A.a + B.a* 10 + C.a * 100 from t1 A, t1 B, t1 C; + +CREATE TABLE t3 ( + col1 int(10) unsigned NOT NULL DEFAULT '0', + col2 mediumint(8) unsigned NOT NULL DEFAULT '0', + col3 smallint(5) NOT NULL DEFAULT '1', + filler varchar(255) DEFAULT NULL, + PRIMARY KEY (col1,col2,col3), + KEY key1 (col1,col2) USING BTREE +) ENGINE=TokuDB DEFAULT CHARSET=latin1 PACK_KEYS=1 COMPRESSION=TOKUDB_LZMA; + +insert into t3 select 1300000000+a, 12345, 7890, 'data' from t2; +insert into t3 select 1400000000+a, 12345, 7890, 'data' from t2; +insert into t3 select 1410799999+a, 12345, 7890, 'data' from t2; +insert into t3 select 1410899999+a, 12345, 7890, 'data' from t2; +insert into t3 select 1410999999+a, 12345, 7890, 'data' from t2; +insert into t3 select 1411099999+a, 12345, 7890, 'data' from t2; +insert into t3 select 1411199999+a, 12345, 7890, 'data' from t2; +insert into t3 select 1411299999+a, 12345, 7890, 'data' from t2; +insert into t3 select 1411399999+a, 12345, 7890, 'data' from t2; +insert into t3 select 1411499999+a, 12345, 7890, 'data' from t2; +insert into t3 select 1411599999+a, 12345, 7890, 'data' from t2; +insert into t3 select 1411699999+a, 12345, 7890, 'data' from t2; +insert into t3 select 1411899999+a, 12345, 7890, 'data' from t2; +insert into t3 select 1411999999+a, 12345, 7890, 'data' from t2; +insert into t3 select 1412099999+a, 12345, 7890, 'data' from t2; +insert into t3 select 1412199999+a, 12345, 7890, 'data' from t2; + +--echo # The following must use range(PRIMARY): +explain +select col1,col2,col3 +from t3 +where col1 <= 1410799999 +order by col1 desc,col2 desc,col3 desc limit 1; + +--echo # The same query but the constant is bigger. +--echo # The query should use range(PRIMARY), not full index scan: +explain +select col1,col2,col3 +from t3 +where col1 <= 1412199999 +order by col1 desc, col2 desc, col3 desc limit 1; + +drop table t1,t2,t3; + From d161546b67142cdd5322a4ed160441045ae0cd1e Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Thu, 4 Sep 2014 01:12:49 +0400 Subject: [PATCH 033/153] MDEV-6689: valgrind errors in view.test in 10.1 SHOW COLUMNS and SHOW KEYS commands fill IS_table_read_plan in a special way - they don't set or use lookup_field_vals member. Added a "trivial_show_command" flag that signals that lookup_field_vals has no valid data, made EXPLAIN code honor it. --- sql/sql_select.cc | 14 +++++++++----- sql/sql_show.cc | 1 + sql/sql_show.h | 10 +++++++++- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 05c88a5f534..1fedf12b595 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -23490,16 +23490,19 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab const char *tmp_buff; int f_idx; StringBuffer<64> key_name_buf; - if (is_table_read_plan->has_db_lookup_value()) + if (is_table_read_plan->trivial_show_command || + is_table_read_plan->has_db_lookup_value()) { /* The "key" has the name of the column referring to the database */ f_idx= table_list->schema_table->idx_field1; tmp_buff= table_list->schema_table->fields_info[f_idx].field_name; key_name_buf.append(tmp_buff, strlen(tmp_buff), cs); } - if (is_table_read_plan->has_table_lookup_value()) + if (is_table_read_plan->trivial_show_command || + is_table_read_plan->has_table_lookup_value()) { - if (is_table_read_plan->has_db_lookup_value()) + if (is_table_read_plan->trivial_show_command || + is_table_read_plan->has_db_lookup_value()) key_name_buf.append(','); f_idx= table_list->schema_table->idx_field2; @@ -23630,8 +23633,9 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab else eta->push_extra(ET_OPEN_FULL_TABLE); /* psergey-note: the following has a bug.*/ - if (table_list->is_table_read_plan->has_db_lookup_value() && - table_list->is_table_read_plan->has_table_lookup_value()) + if (table_list->is_table_read_plan->trivial_show_command || + (table_list->is_table_read_plan->has_db_lookup_value() && + table_list->is_table_read_plan->has_table_lookup_value())) eta->push_extra(ET_SCANNED_0_DATABASES); else if (table_list->is_table_read_plan->has_db_lookup_value() || table_list->is_table_read_plan->has_table_lookup_value()) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index bb8ae16189a..ec7d4979a4e 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -8035,6 +8035,7 @@ static bool optimize_for_get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond if (lsel && lsel->table_list.first) { /* These do not need to have a query plan */ + plan->trivial_show_command= true; goto end; } diff --git a/sql/sql_show.h b/sql/sql_show.h index 2f1cb26d17a..2b58fc45d4c 100644 --- a/sql/sql_show.h +++ b/sql/sql_show.h @@ -192,9 +192,17 @@ typedef struct st_lookup_field_values class IS_table_read_plan : public Sql_alloc { public: - IS_table_read_plan() : no_rows(false) {} + IS_table_read_plan() : no_rows(false), trivial_show_command(FALSE) {} bool no_rows; + /* + For EXPLAIN only: For SHOW KEYS and SHOW COLUMNS, we know which + db_name.table_name will be read, however for some reason we don't + set the fields in this->lookup_field_vals. + In order to not have JOIN::save_explain_data() walking over uninitialized + data, we set trivial_show_command=true. + */ + bool trivial_show_command; LOOKUP_FIELD_VALUES lookup_field_vals; Item *partial_cond; From d3ceb934f1e537bedfaa96d157acdbfcf7b7ae67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Mon, 8 Sep 2014 09:34:03 +0300 Subject: [PATCH 034/153] MDEV-6701: InnoDB tests fail in 10.1 Fixed test failures seen on defragment tests, innodb.innodb-wl5522-debug-zip and innodb.innodb_bug12902967. --- .../innodb/r/innodb_defrag_binlog.result | 16 +-- .../suite/innodb/r/innodb_defrag_stats.result | 129 ++++++++++++++---- .../suite/innodb/r/innodb_defragment.result | 98 +++++++++---- .../r/innodb_defragment_fill_factor.result | 21 +-- .../suite/innodb/t/innodb_defrag_binlog.test | 5 +- .../innodb/t/innodb_defrag_concurrent.test | 3 + .../suite/innodb/t/innodb_defrag_stats.test | 64 +++++++-- .../t/innodb_defrag_stats_many_tables.test | 2 + .../suite/innodb/t/innodb_defragment.test | 82 +++++------ .../t/innodb_defragment_fill_factor.test | 42 ++++-- storage/innobase/fil/fil0fil.cc | 8 +- storage/innobase/srv/srv0start.cc | 4 - storage/xtradb/fil/fil0fil.cc | 8 +- storage/xtradb/srv/srv0start.cc | 4 - 14 files changed, 335 insertions(+), 151 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb_defrag_binlog.result b/mysql-test/suite/innodb/r/innodb_defrag_binlog.result index 2a1992e449d..7cc471f6345 100644 --- a/mysql-test/suite/innodb/r/innodb_defrag_binlog.result +++ b/mysql-test/suite/innodb/r/innodb_defrag_binlog.result @@ -11,19 +11,19 @@ drop table t1; show binlog events in 'master-bin.000001' from 313; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 313 Gtid 1 351 GTID 0-1-1 -master-bin.000001 351 Query 1 465 use `test`; DROP TABLE IF EXISTS `t1` +master-bin.000001 351 Query 1 465 use `test`; DROP TABLE IF EXISTS `t1` /* generated by server */ master-bin.000001 465 Gtid 1 503 GTID 0-1-2 master-bin.000001 503 Query 1 669 use `test`; create table t1(a int not null primary key auto_increment, b varchar(256), key second(b)) engine=innodb master-bin.000001 669 Gtid 1 707 BEGIN GTID 0-1-3 -master-bin.000001 707 Table_map 1 751 table_id: 82 (test.t1) -master-bin.000001 751 Write_rows_v1 1 1043 table_id: 82 flags: STMT_END_F -master-bin.000001 1043 Xid 1 1070 COMMIT +master-bin.000001 707 Table_map 1 751 table_id: # (test.t1) +master-bin.000001 751 Write_rows_v1 1 1043 table_id: # flags: STMT_END_F +master-bin.000001 1043 Xid 1 1070 COMMIT /* XID */ master-bin.000001 1070 Gtid 1 1108 BEGIN GTID 0-1-4 -master-bin.000001 1108 Table_map 1 1152 table_id: 82 (test.t1) -master-bin.000001 1152 Write_rows_v1 1 1444 table_id: 82 flags: STMT_END_F -master-bin.000001 1444 Xid 1 1471 COMMIT +master-bin.000001 1108 Table_map 1 1152 table_id: # (test.t1) +master-bin.000001 1152 Write_rows_v1 1 1444 table_id: # flags: STMT_END_F +master-bin.000001 1444 Xid 1 1471 COMMIT /* XID */ master-bin.000001 1471 Gtid 1 1509 GTID 0-1-5 master-bin.000001 1509 Query 1 1589 use `test`; optimize table t1 master-bin.000001 1589 Gtid 1 1627 GTID 0-1-6 -master-bin.000001 1627 Query 1 1731 use `test`; DROP TABLE `t1` +master-bin.000001 1627 Query 1 1731 use `test`; DROP TABLE `t1` /* generated by server */ include/rpl_end.inc diff --git a/mysql-test/suite/innodb/r/innodb_defrag_stats.result b/mysql-test/suite/innodb/r/innodb_defrag_stats.result index 0838a199b3b..7092688f07b 100644 --- a/mysql-test/suite/innodb/r/innodb_defrag_stats.result +++ b/mysql-test/suite/innodb/r/innodb_defrag_stats.result @@ -18,14 +18,26 @@ INSERT INTO t1 (b) SELECT b from t1; INSERT INTO t1 (b) SELECT b from t1; INSERT INTO t1 (b) SELECT b from t1; # Not enough page splits to trigger persistent stats write yet. -select count(*) from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split', 'n_leaf_pages_defrag'); -count(*) -0 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +count(stat_value) = 0 +1 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +count(stat_value) = 0 +1 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); +count(stat_value) = 0 +1 INSERT INTO t1 (b) SELECT b from t1; # Persistent stats recorded. -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split', 'n_leaf_pages_defrag'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); count(stat_value) > 0 -0 +1 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +count(stat_value) = 0 +1 +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); +count(stat_value) > 0 +1 # Delete some rows. delete from t1 where a between 100 * 20 and 100 * 20 + 30; delete from t1 where a between 100 * 19 and 100 * 19 + 30; @@ -49,46 +61,115 @@ delete from t1 where a between 100 * 2 and 100 * 2 + 30; delete from t1 where a between 100 * 1 and 100 * 1 + 30; # Server Restarted # Confirm persistent stats still there after restart. -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split', 'n_leaf_pages_defrag'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); count(stat_value) > 0 -0 +1 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +count(stat_value) = 0 +1 +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); +count(stat_value) > 0 +1 optimize table t1; Table Op Msg_type Msg_text test.t1 optimize status OK -# n_page_split should be 0 after defragmentation, n_pages_freed should be non-zero. -select stat_value = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name = 'n_page_split'; -stat_value = 0 +select sleep(2); +sleep(2) +0 +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +count(stat_value) > 0 1 +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +count(stat_value) > 0 1 -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed', 'n_leaf_pages_defrag'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); count(stat_value) > 0 1 set global innodb_defragment_stats_accuracy = 40; INSERT INTO t1 (b) SELECT b from t1; -# Not enough operation to trigger persistent stats write -select stat_value = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name = 'n_page_split'; -stat_value = 0 +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +count(stat_value) > 0 1 +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +count(stat_value) > 0 +1 +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); +count(stat_value) > 0 1 INSERT INTO t1 (b) SELECT b from t1; -# Persistent stats write triggered -select stat_value > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name = 'n_page_split'; -stat_value > 0 -0 -0 +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +count(stat_value) > 0 +1 +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +count(stat_value) > 0 +1 +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); +count(stat_value) > 0 +1 # Table rename should cause stats rename. rename table t1 to t2; -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_pages_freed', 'n_page_split', 'n_leaf_pages_defrag'); +select sleep(1); +sleep(1) +0 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +count(stat_value) = 0 +1 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +count(stat_value) = 0 +1 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); +count(stat_value) = 0 +1 +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_page_split'); +count(stat_value) > 0 +1 +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_pages_freed'); +count(stat_value) > 0 +1 +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_leaf_pages_defrag'); count(stat_value) > 0 1 # Drop index should cause stats drop. drop index SECOND on t2; -select count(*) from mysql.innodb_index_stats where table_name like '%t2%' and index_name = 'SECOND'; -count(*) -4 +select sleep(3); +sleep(3) +0 +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and index_name = 'SECOND' and stat_name in ('n_page_split'); +count(stat_value) > 0 +1 +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and index_name = 'SECOND' and stat_name in ('n_pages_freed'); +count(stat_value) > 0 +1 +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and index_name = 'SECOND' and stat_name in ('n_leaf_pages_defrag'); +count(stat_value) > 0 +1 Server Restarted -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_pages_freed', 'n_page_split', 'n_leaf_pages_defrag'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +count(stat_value) = 0 +1 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +count(stat_value) = 0 +1 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); +count(stat_value) = 0 +1 +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_page_split'); +count(stat_value) > 0 +1 +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_pages_freed'); +count(stat_value) > 0 +1 +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_leaf_pages_defrag'); count(stat_value) > 0 1 # Clean up DROP TABLE t2; +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_page_split'); +count(stat_value) = 0 +1 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_pages_freed'); +count(stat_value) = 0 +1 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_leaf_pages_defrag'); +count(stat_value) = 0 +1 diff --git a/mysql-test/suite/innodb/r/innodb_defragment.result b/mysql-test/suite/innodb/r/innodb_defragment.result index b8f61b0eba3..5f3fd523946 100644 --- a/mysql-test/suite/innodb/r/innodb_defragment.result +++ b/mysql-test/suite/innodb/r/innodb_defragment.result @@ -17,65 +17,109 @@ set @i = 0; repeat set @i = @i + 1; optimize table t1; -select sleep(5); until @i = 3 end repeat; end // -select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); -count(stat_value) = 0 -1 -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); -count(stat_value) > 0 -1 -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); -count(stat_value) > 0 -1 +select count(stat_value) from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +count(stat_value) +0 +select count(stat_value) from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +count(stat_value) +2 +select count(stat_value) from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); +count(stat_value) +2 select count(*) from t1; count(*) 10004 -select count(*) from t1 force index (second); -count(*) -10004 call defragment(); optimize table t1; Table Op Msg_type Msg_text test.t1 optimize status OK -select sleep(5); -sleep(5) -0 select count(*) from t1; count(*) 7904 -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_pages_freed', 'n_page_split', 'n_leaf_pages_defrag'); -count(stat_value) > 0 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +count(stat_value) = 0 0 +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +count(stat_value) > 0 +1 +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); +count(stat_value) > 0 +1 select count(*) from t1 force index (second); count(*) 7904 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and index_name = 'second' and stat_name in ('n_pages_freed'); +count(stat_value) = 0 +1 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and index_name = 'second' and stat_name in ('n_page_split'); +count(stat_value) = 0 +1 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and index_name = 'second' and stat_name in ('n_leaf_pages_defrag'); +count(stat_value) = 0 +1 SET @@global.innodb_defragment_n_pages = 3; optimize table t1; Table Op Msg_type Msg_text test.t1 optimize status OK -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_pages_freed', 'n_page_split', 'n_leaf_pages_defrag'); -count(stat_value) > 0 -0 +select count(stat_value) < 3 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +count(stat_value) < 3 +1 +select count(stat_value) < 3 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +count(stat_value) < 3 +1 +select count(stat_value) < 3 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); +count(stat_value) < 3 +1 select count(*) from t1; count(*) 6904 +select count(stat_value) < 3 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +count(stat_value) < 3 +1 +select count(stat_value) < 3 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +count(stat_value) < 3 +1 +select count(stat_value) < 3 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); +count(stat_value) < 3 +1 select count(*) from t1 force index (second); count(*) 6904 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and index_name = 'second' and stat_name in ('n_pages_freed'); +count(stat_value) = 0 +1 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and index_name = 'second' and stat_name in ('n_page_split'); +count(stat_value) = 0 +1 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and index_name = 'second' and stat_name in ('n_leaf_pages_defrag'); +count(stat_value) = 0 +1 SET @@global.innodb_defragment_n_pages = 10; optimize table t1; Table Op Msg_type Msg_text test.t1 optimize status OK -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_pages_freed', 'n_page_split', 'n_leaf_pages_defrag'); -count(stat_value) > 0 -0 -select count(*) from t1; -count(*) -6904 +select count(stat_value) > 1 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +count(stat_value) > 1 +1 +select count(stat_value) > 1 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +count(stat_value) > 1 +1 +select count(stat_value) > 1 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); +count(stat_value) > 1 +1 select count(*) from t1 force index (second); count(*) 6904 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and index_name = 'second' and stat_name in ('n_pages_freed'); +count(stat_value) = 0 +1 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and index_name = 'second' and stat_name in ('n_page_split'); +count(stat_value) = 0 +1 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and index_name = 'second' and stat_name in ('n_leaf_pages_defrag'); +count(stat_value) = 0 +1 DROP PROCEDURE defragment; DROP TABLE t1; diff --git a/mysql-test/suite/innodb/r/innodb_defragment_fill_factor.result b/mysql-test/suite/innodb/r/innodb_defragment_fill_factor.result index 90dcbc004f7..7c153eaaa93 100644 --- a/mysql-test/suite/innodb/r/innodb_defragment_fill_factor.result +++ b/mysql-test/suite/innodb/r/innodb_defragment_fill_factor.result @@ -14,13 +14,14 @@ count(*) # A few more insertions on the page should not cause a page split. insert into t1 values (81, REPEAT('A', 256)); insert into t1 values (83, REPEAT('A', 256)); -insert into t1 values (87, REPEAT('A', 256)); -insert into t1 values (82, REPEAT('A', 256)); -insert into t1 values (86, REPEAT('A', 256)); # More insertions will cause page splits insert into t1 values (88, REPEAT('A', 50)); -Too much space are reserved on primary index. -Too much space are reserved on second index. +insert into t1 values (85, REPEAT('A', 256)); +insert into t1 values (84, REPEAT('A', 256)); +insert into t1 values (87, REPEAT('A', 256)); +insert into t1 values (89, REPEAT('A', 256)); +insert into t1 values (82, REPEAT('A', 256)); +insert into t1 values (86, REPEAT('A', 256)); DROP TABLE t1; Testing table with small records CREATE TABLE t2 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b VARchar(16), KEY SECOND(a,b)) ENGINE=INNODB; @@ -48,12 +49,16 @@ insert into t2 values(1197, REPEAT('A', 16)); insert into t2 values(1188, REPEAT('A', 16)); insert into t2 values(1198, REPEAT('A', 16)); insert into t2 values(1189, REPEAT('A', 16)); -insert into t2 values(1199, REPEAT('A', 16)); -insert into t2 values(1190, REPEAT('A', 16)); -insert into t2 values(1180, REPEAT('A', 16)); More insertions will cause page split. insert into t2 values(1280, REPEAT('A', 16)); insert into t2 values(1290, REPEAT('A', 16)); insert into t2 values(1281, REPEAT('A', 16)); insert into t2 values(1291, REPEAT('A', 16)); +insert into t2 values(1199, REPEAT('A', 16)); +insert into t2 values(1190, REPEAT('A', 16)); +insert into t2 values(1180, REPEAT('A', 16)); +insert into t2 values(1295, REPEAT('A', 16)); +insert into t2 values(1294, REPEAT('A', 16)); +insert into t2 values(1292, REPEAT('A', 16)); +insert into t2 values(1293, REPEAT('A', 16)); DROP TABLE t2; diff --git a/mysql-test/suite/innodb/t/innodb_defrag_binlog.test b/mysql-test/suite/innodb/t/innodb_defrag_binlog.test index c0d4b377cb1..ec3203893a4 100644 --- a/mysql-test/suite/innodb/t/innodb_defrag_binlog.test +++ b/mysql-test/suite/innodb/t/innodb_defrag_binlog.test @@ -1,5 +1,8 @@ --source include/have_innodb.inc --source include/master-slave.inc +--source include/big_test.inc +--source include/not_valgrind.inc +--source include/not_embedded.inc --disable_warnings drop table if exists t1; @@ -13,7 +16,7 @@ optimize table t1; drop table t1; ---replace_regex /\/\*.*// +--replace_regex /\/\* xid=.* \*\//\/* XID *\// /Server ver: .*, Binlog ver: .*/Server ver: #, Binlog ver: #/ /table_id: [0-9]+/table_id: #/ show binlog events in 'master-bin.000001' from 313; --source include/rpl_end.inc diff --git a/mysql-test/suite/innodb/t/innodb_defrag_concurrent.test b/mysql-test/suite/innodb/t/innodb_defrag_concurrent.test index 7cf00e1da4c..2b08613535c 100644 --- a/mysql-test/suite/innodb/t/innodb_defrag_concurrent.test +++ b/mysql-test/suite/innodb/t/innodb_defrag_concurrent.test @@ -1,4 +1,7 @@ --source include/have_innodb.inc +--source include/big_test.inc +--source include/not_valgrind.inc +--source include/not_embedded.inc --disable_warnings DROP TABLE if exists t1; diff --git a/mysql-test/suite/innodb/t/innodb_defrag_stats.test b/mysql-test/suite/innodb/t/innodb_defrag_stats.test index f07544df4f6..2a5026a68e5 100644 --- a/mysql-test/suite/innodb/t/innodb_defrag_stats.test +++ b/mysql-test/suite/innodb/t/innodb_defrag_stats.test @@ -1,5 +1,7 @@ --source include/have_innodb.inc --source include/big_test.inc +--source include/not_valgrind.inc +--source include/not_embedded.inc --disable_warnings DROP TABLE if exists t1; @@ -29,12 +31,16 @@ INSERT INTO t1 (b) SELECT b from t1; INSERT INTO t1 (b) SELECT b from t1; --echo # Not enough page splits to trigger persistent stats write yet. -select count(*) from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split', 'n_leaf_pages_defrag'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); INSERT INTO t1 (b) SELECT b from t1; --echo # Persistent stats recorded. -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split', 'n_leaf_pages_defrag'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); --echo # Delete some rows. let $num_delete = 20; @@ -49,39 +55,71 @@ while ($num_delete) --echo # Server Restarted --echo # Confirm persistent stats still there after restart. -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split', 'n_leaf_pages_defrag'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); optimize table t1; ---echo # n_page_split should be 0 after defragmentation, n_pages_freed should be non-zero. -select stat_value = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name = 'n_page_split'; -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed', 'n_leaf_pages_defrag'); +select sleep(2); + +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); set global innodb_defragment_stats_accuracy = 40; INSERT INTO t1 (b) SELECT b from t1; ---echo # Not enough operation to trigger persistent stats write -select stat_value = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name = 'n_page_split'; + +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); + INSERT INTO t1 (b) SELECT b from t1; ---echo # Persistent stats write triggered -select stat_value > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name = 'n_page_split'; + +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); + --echo # Table rename should cause stats rename. rename table t1 to t2; -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_pages_freed', 'n_page_split', 'n_leaf_pages_defrag'); +select sleep(1); + +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); + +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_page_split'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_pages_freed'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_leaf_pages_defrag'); --echo # Drop index should cause stats drop. drop index SECOND on t2; -select count(*) from mysql.innodb_index_stats where table_name like '%t2%' and index_name = 'SECOND'; +select sleep(3); + +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and index_name = 'SECOND' and stat_name in ('n_page_split'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and index_name = 'SECOND' and stat_name in ('n_pages_freed'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and index_name = 'SECOND' and stat_name in ('n_leaf_pages_defrag'); --source include/restart_mysqld.inc --echo Server Restarted -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_pages_freed', 'n_page_split', 'n_leaf_pages_defrag'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); + +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_page_split'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_pages_freed'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_leaf_pages_defrag'); --echo # Clean up DROP TABLE t2; +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_page_split'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_pages_freed'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_leaf_pages_defrag'); + --disable_query_log EVAL SET GLOBAL innodb_defragment_stats_accuracy = $innodb_defragment_stats_accuracy_orig; --enable_query_log diff --git a/mysql-test/suite/innodb/t/innodb_defrag_stats_many_tables.test b/mysql-test/suite/innodb/t/innodb_defrag_stats_many_tables.test index e1a463459be..601883c35aa 100644 --- a/mysql-test/suite/innodb/t/innodb_defrag_stats_many_tables.test +++ b/mysql-test/suite/innodb/t/innodb_defrag_stats_many_tables.test @@ -1,5 +1,7 @@ --source include/have_innodb.inc --source include/big_test.inc +--source include/not_valgrind.inc +--source include/not_embedded.inc --disable_warnings DROP TABLE if exists t1; diff --git a/mysql-test/suite/innodb/t/innodb_defragment.test b/mysql-test/suite/innodb/t/innodb_defragment.test index 77fceeaa56b..22b72a4aa6b 100644 --- a/mysql-test/suite/innodb/t/innodb_defragment.test +++ b/mysql-test/suite/innodb/t/innodb_defragment.test @@ -1,4 +1,7 @@ --source include/have_innodb.inc +--source include/big_test.inc +--source include/not_valgrind.inc +--source include/not_embedded.inc --disable_warnings DROP TABLE if exists t1; @@ -36,7 +39,6 @@ begin repeat set @i = @i + 1; optimize table t1; - select sleep(5); until @i = 3 end repeat; end // delimiter ;// @@ -53,25 +55,12 @@ while ($i) } --enable_query_log -select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); +select count(stat_value) from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +select count(stat_value) from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +select count(stat_value) from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); select count(*) from t1; -if (!`select count(*) > 180 from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'PRIMARY' order by page_number;`) -{ -select count(*) from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'PRIMARY' order by page_number; -} - -select count(*) from t1 force index (second); - -if (!`select count(*) > 170 from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'second' order by page_number;`) -{ -select count(*) from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'second' order by page_number; -} - - connect (con1,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK); connection con1; @@ -98,26 +87,19 @@ connection default; disconnect con1; optimize table t1; -select sleep(5); --source include/restart_mysqld.inc select count(*) from t1; -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_pages_freed', 'n_page_split', 'n_leaf_pages_defrag'); - -# After deletion & defragmentation, there are 8000 records left -if (!`select count(*) < 180 from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'PRIMARY' order by page_number;`) -{ -select count(*) from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'PRIMARY' order by page_number; -} +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); select count(*) from t1 force index (second); -# secondary index is pretty much the same size as primary index so the number of pages should be similar. -if (!`select count(*) < 180 from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'second' order by page_number;`) -{ -select count(*) from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'second' order by page_number; -} +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and index_name = 'second' and stat_name in ('n_pages_freed'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and index_name = 'second' and stat_name in ('n_page_split'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and index_name = 'second' and stat_name in ('n_leaf_pages_defrag'); ## Test-4 defragment with larger n_pages @@ -139,23 +121,25 @@ optimize table t1; --source include/restart_mysqld.inc -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_pages_freed', 'n_page_split', 'n_leaf_pages_defrag'); +select count(stat_value) < 3 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +select count(stat_value) < 3 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +select count(stat_value) < 3 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); select count(*) from t1; # We didn't create large wholes with the previous deletion, so if innodb_defragment_n_pages = 3, we won't be able to free up many pages. -if (!`select count(*) > 130 from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'PRIMARY' order by page_number;`) -{ -select count(*) from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'PRIMARY' order by page_number; -} + +select count(stat_value) < 3 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +select count(stat_value) < 3 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +select count(stat_value) < 3 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); + select count(*) from t1 force index (second); # Same holds for secondary index, not many pages are released. -if (!`select count(*) > 100 from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'second' order by page_number;`) -{ -select count(*) from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'second' order by page_number; -} +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and index_name = 'second' and stat_name in ('n_pages_freed'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and index_name = 'second' and stat_name in ('n_page_split'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and index_name = 'second' and stat_name in ('n_leaf_pages_defrag'); SET @@global.innodb_defragment_n_pages = 10; @@ -163,25 +147,21 @@ optimize table t1; --source include/restart_mysqld.inc -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_pages_freed', 'n_page_split', 'n_leaf_pages_defrag'); +select count(stat_value) > 1 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +select count(stat_value) > 1 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +select count(stat_value) > 1 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); -select count(*) from t1; - -# This time we used innodb_defragment_n_pages = 10, so we should be able to free up some pages. -if (!`select count(*) < 165 from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'PRIMARY' order by page_number;`) -{ -select count(*) from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'PRIMARY' order by page_number; -} select count(*) from t1 force index (second); -if (!`select count(*) < 165 from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'second' order by page_number;`) -{ -select count(*) from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'second' order by page_number; -} +# Same holds for secondary index, not many pages are released. +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and index_name = 'second' and stat_name in ('n_pages_freed'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and index_name = 'second' and stat_name in ('n_page_split'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and index_name = 'second' and stat_name in ('n_leaf_pages_defrag'); DROP PROCEDURE defragment; DROP TABLE t1; + # reset system --disable_query_log EVAL SET GLOBAL innodb_defragment_n_pages = $innodb_defragment_n_pages_orig; diff --git a/mysql-test/suite/innodb/t/innodb_defragment_fill_factor.test b/mysql-test/suite/innodb/t/innodb_defragment_fill_factor.test index b2fdfa4a409..24c23448a30 100644 --- a/mysql-test/suite/innodb/t/innodb_defragment_fill_factor.test +++ b/mysql-test/suite/innodb/t/innodb_defragment_fill_factor.test @@ -1,4 +1,8 @@ --source include/have_innodb.inc +--source include/big_test.inc +--source include/not_valgrind.inc +--source include/not_embedded.inc + --disable_warnings DROP TABLE if exists t1; DROP TABLE if exists t2; @@ -34,34 +38,44 @@ select count(*) from t1; select count(*) from t1 force index (second); # secondary index is slightly bigger than primary index so the number of pages should be similar. --let $second_before = query_get_value(select count(*) as Value from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'second', Value, 1) + --echo # A few more insertions on the page should not cause a page split. insert into t1 values (81, REPEAT('A', 256)); insert into t1 values (83, REPEAT('A', 256)); -insert into t1 values (87, REPEAT('A', 256)); -insert into t1 values (82, REPEAT('A', 256)); -insert into t1 values (86, REPEAT('A', 256)); + --let $primary_after = query_get_value(select count(*) as Value from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'PRIMARY', Value, 1) --let $second_after = query_get_value(select count(*) as Value from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'second', Value, 1) + if ($primary_before != $primary_after) { --echo Insertion caused page split on primary, which should be avoided by innodb_defragment_fill_factor. } + if ($second_before != $second_after) { --echo Insertion caused page split on second, which should be avoided by innodb_defragment_fill_factor. } + --echo # More insertions will cause page splits insert into t1 values (88, REPEAT('A', 50)); -#insert into t1 values (85, REPEAT('A', 256)); -#insert into t1 values (84, REPEAT('A', 256)); -#insert into t1 values (89, REPEAT('A', 256)); +insert into t1 values (85, REPEAT('A', 256)); +insert into t1 values (84, REPEAT('A', 256)); +insert into t1 values (87, REPEAT('A', 256)); +insert into t1 values (89, REPEAT('A', 256)); +insert into t1 values (82, REPEAT('A', 256)); +insert into t1 values (86, REPEAT('A', 256)); + --let $primary_after = query_get_value(select count(*) as Value from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'PRIMARY', Value, 1) --let $second_after = query_get_value(select count(*) as Value from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'second', Value, 1) + if ($primary_before == $primary_after) { --echo Too much space are reserved on primary index. } + if ($second_before == $second_after) { --echo Too much space are reserved on second index. } + DROP TABLE t1; + --echo Testing table with small records CREATE TABLE t2 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b VARchar(16), KEY SECOND(a,b)) ENGINE=INNODB; # Populate table. @@ -111,20 +125,30 @@ insert into t2 values(1197, REPEAT('A', 16)); insert into t2 values(1188, REPEAT('A', 16)); insert into t2 values(1198, REPEAT('A', 16)); insert into t2 values(1189, REPEAT('A', 16)); -insert into t2 values(1199, REPEAT('A', 16)); -insert into t2 values(1190, REPEAT('A', 16)); -insert into t2 values(1180, REPEAT('A', 16)); + --let $second_after = query_get_value(select count(*) as Value from information_schema.innodb_buffer_page where table_name like '%t2%' and index_name = 'second', Value, 1) + if ($second_before != $second_after) { --echo Insertion caused page split on second, which should be avoided by innodb_defragment_fill_factor. } + --echo More insertions will cause page split. insert into t2 values(1280, REPEAT('A', 16)); insert into t2 values(1290, REPEAT('A', 16)); insert into t2 values(1281, REPEAT('A', 16)); insert into t2 values(1291, REPEAT('A', 16)); +insert into t2 values(1199, REPEAT('A', 16)); +insert into t2 values(1190, REPEAT('A', 16)); +insert into t2 values(1180, REPEAT('A', 16)); +insert into t2 values(1295, REPEAT('A', 16)); +insert into t2 values(1294, REPEAT('A', 16)); +insert into t2 values(1292, REPEAT('A', 16)); +insert into t2 values(1293, REPEAT('A', 16)); + --let $second_after = query_get_value(select count(*) as Value from information_schema.innodb_buffer_page where table_name like '%t2%' and index_name = 'second', Value, 1) + if ($second_before == $second_after) { --echo Too much space are reserved on second index. } + DROP TABLE t2; diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index be6a1ce30ef..e406d008705 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -3727,7 +3727,13 @@ fil_open_single_table_tablespace( #endif /* UNIV_SYNC_DEBUG */ ut_ad(!fix_dict || mutex_own(&(dict_sys->mutex))); - if (!fsp_flags_is_valid(flags)) { + /* Table flags can be ULINT_UNDEFINED if + dict_tf_to_fsp_flags_failure is set. */ + if (flags != ULINT_UNDEFINED) { + if (!fsp_flags_is_valid(flags)) { + return(DB_CORRUPTION); + } + } else { return(DB_CORRUPTION); } diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 6a02b08c3b7..bfdcbfaeee0 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -3003,10 +3003,6 @@ innobase_shutdown_for_mysql(void) buf_mtflu_io_thread_exit(); } -#ifdef UNIV_DEBUG - fprintf(stderr, "InnoDB: Note: %s:%d os_thread_count:%lu \n", __FUNCTION__, __LINE__, os_thread_count); -#endif - os_mutex_enter(os_sync_mutex); if (os_thread_count == 0) { diff --git a/storage/xtradb/fil/fil0fil.cc b/storage/xtradb/fil/fil0fil.cc index d9398e3ceb5..017e96e6111 100644 --- a/storage/xtradb/fil/fil0fil.cc +++ b/storage/xtradb/fil/fil0fil.cc @@ -3752,7 +3752,13 @@ fil_open_single_table_tablespace( #endif /* UNIV_SYNC_DEBUG */ ut_ad(!fix_dict || mutex_own(&(dict_sys->mutex))); - if (!fsp_flags_is_valid(flags)) { + /* Table flags can be ULINT_UNDEFINED if + dict_tf_to_fsp_flags_failure is set. */ + if (flags != ULINT_UNDEFINED) { + if (!fsp_flags_is_valid(flags)) { + return(DB_CORRUPTION); + } + } else { return(DB_CORRUPTION); } diff --git a/storage/xtradb/srv/srv0start.cc b/storage/xtradb/srv/srv0start.cc index cb7aa9bc3c7..86b0764d948 100644 --- a/storage/xtradb/srv/srv0start.cc +++ b/storage/xtradb/srv/srv0start.cc @@ -3085,12 +3085,8 @@ innobase_shutdown_for_mysql(void) buf_mtflu_io_thread_exit(); } -#ifdef UNIV_DEBUG - fprintf(stderr, "InnoDB: Note: %s:%d os_thread_count:%lu \n", __FUNCTION__, __LINE__, os_thread_count); -#endif os_mutex_enter(os_sync_mutex); - if (os_thread_count == 0) { /* All the threads have exited or are just exiting; NOTE that the threads may not have completed their From 7c58dd80e599862f42c60186c0c913cb9f64b6b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Mon, 8 Sep 2014 15:12:18 +0300 Subject: [PATCH 035/153] Fix another set of test failures caused by galera merge. --- .../suite/perfschema/r/stage_mdl_function.result | 2 +- .../suite/perfschema/r/stage_mdl_procedure.result | 2 +- mysql-test/suite/perfschema/r/stage_mdl_table.result | 2 +- mysql-test/suite/roles/set_default_role_for.result | 12 ++++++------ mysql-test/suite/roles/set_default_role_for.test | 12 ++++++------ 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/mysql-test/suite/perfschema/r/stage_mdl_function.result b/mysql-test/suite/perfschema/r/stage_mdl_function.result index d949b19586a..098ff4f2132 100644 --- a/mysql-test/suite/perfschema/r/stage_mdl_function.result +++ b/mysql-test/suite/perfschema/r/stage_mdl_function.result @@ -11,7 +11,6 @@ username event_name sql_text user1 statement/sql/select select test.f1() username event_name nesting_event_type username event_name nesting_event_type -user1 stage/sql/optimizing STATEMENT user1 stage/sql/executing STATEMENT user1 stage/sql/Opening tables STATEMENT user1 stage/sql/After opening tables STATEMENT @@ -19,6 +18,7 @@ user1 stage/sql/closing tables STATEMENT user1 stage/sql/end STATEMENT user1 stage/sql/query end STATEMENT user1 stage/sql/closing tables STATEMENT +user1 stage/sql/Unlocking tables STATEMENT user1 stage/sql/freeing items STATEMENT user1 stage/sql/cleaning up STATEMENT call dump_one_thread('user2'); diff --git a/mysql-test/suite/perfschema/r/stage_mdl_procedure.result b/mysql-test/suite/perfschema/r/stage_mdl_procedure.result index 263c00c98e6..1eeae4fc4fa 100644 --- a/mysql-test/suite/perfschema/r/stage_mdl_procedure.result +++ b/mysql-test/suite/perfschema/r/stage_mdl_procedure.result @@ -18,7 +18,6 @@ username event_name sql_text user1 statement/sql/select select test.f1() username event_name nesting_event_type username event_name nesting_event_type -user1 stage/sql/query end STATEMENT user1 stage/sql/closing tables STATEMENT user1 stage/sql/Opening tables STATEMENT user1 stage/sql/After opening tables STATEMENT @@ -26,6 +25,7 @@ user1 stage/sql/closing tables STATEMENT user1 stage/sql/end STATEMENT user1 stage/sql/query end STATEMENT user1 stage/sql/closing tables STATEMENT +user1 stage/sql/Unlocking tables STATEMENT user1 stage/sql/freeing items STATEMENT user1 stage/sql/cleaning up STATEMENT call dump_one_thread('user2'); diff --git a/mysql-test/suite/perfschema/r/stage_mdl_table.result b/mysql-test/suite/perfschema/r/stage_mdl_table.result index 60e83e8a179..0699c28ac47 100644 --- a/mysql-test/suite/perfschema/r/stage_mdl_table.result +++ b/mysql-test/suite/perfschema/r/stage_mdl_table.result @@ -13,7 +13,6 @@ username event_name sql_text user1 statement/sql/select select * from test.t1 for update username event_name nesting_event_type username event_name nesting_event_type -user1 stage/sql/optimizing STATEMENT user1 stage/sql/statistics STATEMENT user1 stage/sql/preparing STATEMENT user1 stage/sql/executing STATEMENT @@ -21,6 +20,7 @@ user1 stage/sql/Sending data STATEMENT user1 stage/sql/end STATEMENT user1 stage/sql/query end STATEMENT user1 stage/sql/closing tables STATEMENT +user1 stage/sql/Unlocking tables STATEMENT user1 stage/sql/freeing items STATEMENT user1 stage/sql/cleaning up STATEMENT call dump_one_thread('user2'); diff --git a/mysql-test/suite/roles/set_default_role_for.result b/mysql-test/suite/roles/set_default_role_for.result index 7289319a428..3e444a5f537 100644 --- a/mysql-test/suite/roles/set_default_role_for.result +++ b/mysql-test/suite/roles/set_default_role_for.result @@ -21,17 +21,17 @@ Grants for user_a@localhost GRANT role_a TO 'user_a'@'localhost' GRANT USAGE ON *.* TO 'user_a'@'localhost' GRANT SELECT ON *.* TO 'role_a' -select user, host, default_role from mysql.user where user like 'user_%'; +select user, host, default_role from mysql.user where user like 'user_%' order by user; user host default_role user_a localhost role_a user_b localhost role_b set default role NONE for current_user; -select user, host, default_role from mysql.user where user like 'user_%'; +select user, host, default_role from mysql.user where user like 'user_%' order by user; user host default_role user_a localhost user_b localhost role_b set default role current_role for current_user; -select user, host, default_role from mysql.user where user like 'user_%'; +select user, host, default_role from mysql.user where user like 'user_%' order by user; user host default_role user_a localhost role_a user_b localhost role_b @@ -42,7 +42,7 @@ Grants for user_b@localhost GRANT role_b TO 'user_b'@'localhost' GRANT USAGE ON *.* TO 'user_b'@'localhost' GRANT INSERT, UPDATE ON *.* TO 'role_b' -select user, host, default_role from mysql.user where user like 'user_%'; +select user, host, default_role from mysql.user where user like 'user_%' order by user; ERROR 42000: SELECT command denied to user 'user_b'@'localhost' for table 'user' insert into mysql.user (user, host) values ('someuser', 'somehost'); Warnings: @@ -56,10 +56,10 @@ Grants for user_a@localhost GRANT role_a TO 'user_a'@'localhost' GRANT USAGE ON *.* TO 'user_a'@'localhost' GRANT INSERT, UPDATE ON *.* TO 'role_b' -select user, host, default_role from mysql.user where user like 'user_%'; +select user, host, default_role from mysql.user where user like 'user_%' order by user; ERROR 42000: SELECT command denied to user 'user_a'@'localhost' for table 'user' drop role role_a; drop role role_b; -delete from mysql.user where user = 'someuser' && host = 'somehost'; +delete from mysql.user where user = 'someuser' && host = 'somehost' order by user; drop user user_a@localhost; drop user user_b@localhost; diff --git a/mysql-test/suite/roles/set_default_role_for.test b/mysql-test/suite/roles/set_default_role_for.test index d7a3372ae23..2e798b49733 100644 --- a/mysql-test/suite/roles/set_default_role_for.test +++ b/mysql-test/suite/roles/set_default_role_for.test @@ -44,13 +44,13 @@ set default role role_b for user_b@localhost; change_user 'user_a'; show grants; -select user, host, default_role from mysql.user where user like 'user_%'; +select user, host, default_role from mysql.user where user like 'user_%' order by user; set default role NONE for current_user; -select user, host, default_role from mysql.user where user like 'user_%'; +select user, host, default_role from mysql.user where user like 'user_%' order by user; set default role current_role for current_user; -select user, host, default_role from mysql.user where user like 'user_%'; +select user, host, default_role from mysql.user where user like 'user_%' order by user; # Make sure we can't set a default role not granted to us, using current_user --error ER_INVALID_ROLE @@ -60,7 +60,7 @@ change_user 'user_b'; show grants; --error ER_TABLEACCESS_DENIED_ERROR -select user, host, default_role from mysql.user where user like 'user_%'; +select user, host, default_role from mysql.user where user like 'user_%' order by user; # Make sure the default role setting worked from root. insert into mysql.user (user, host) values ('someuser', 'somehost'); @@ -73,12 +73,12 @@ change_user 'user_a'; # There is no default role set any more. show grants; --error ER_TABLEACCESS_DENIED_ERROR -select user, host, default_role from mysql.user where user like 'user_%'; +select user, host, default_role from mysql.user where user like 'user_%' order by user; change_user 'root'; drop role role_a; drop role role_b; -delete from mysql.user where user = 'someuser' && host = 'somehost'; +delete from mysql.user where user = 'someuser' && host = 'somehost' order by user; drop user user_a@localhost; drop user user_b@localhost; From 26e048ffd30e05a60a330a708341e1fff0df0a9e Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Mon, 8 Sep 2014 13:19:20 -0400 Subject: [PATCH 036/153] Merged sys_vars.wsrep_* tests from maria-10.0-galera tree. --- .../wsrep_auto_increment_control_basic.result | 53 ++++++++-- .../r/wsrep_causal_reads_basic.result | 58 +++++++++-- .../r/wsrep_certify_nonpk_basic.result | 53 ++++++++-- .../r/wsrep_cluster_address_basic.result | 97 +++++++++--------- .../r/wsrep_cluster_name_basic.result | 48 +++++++-- .../r/wsrep_convert_lock_to_trx_basic.result | 53 ++++++++-- .../r/wsrep_data_home_dir_basic.result | 94 +++++++++--------- .../sys_vars/r/wsrep_dbug_option_basic.result | 51 +++++++++- .../suite/sys_vars/r/wsrep_debug_basic.result | 53 ++++++++-- .../sys_vars/r/wsrep_desync_basic.result | 51 +++++++++- ...srep_drupal_282555_workaround_basic.result | 53 ++++++++-- .../r/wsrep_forced_binlog_format_basic.result | 59 +++++++++-- .../r/wsrep_load_data_splitting_basic.result | 53 ++++++++-- .../r/wsrep_log_conflicts_basic.result | 53 ++++++++-- .../sys_vars/r/wsrep_max_ws_rows_basic.result | 64 +++++++++--- .../sys_vars/r/wsrep_max_ws_size_basic.result | 69 ++++++++++--- ...srep_mysql_replication_bundle_basic.result | 68 +++++++++---- .../r/wsrep_node_address_basic.result | 92 ++++++++--------- .../wsrep_node_incoming_address_basic.result | 99 ++++++++++--------- .../sys_vars/r/wsrep_node_name_basic.result | 52 +++++++++- .../sys_vars/r/wsrep_notify_cmd_basic.result | 51 +++++++++- .../suite/sys_vars/r/wsrep_on_basic.result | 58 +++++++++-- .../sys_vars/r/wsrep_osu_method_basic.result | 72 +++++++++++--- .../sys_vars/r/wsrep_provider_basic.result | 44 ++++++++- .../r/wsrep_provider_options_basic.result | 52 +++++++++- .../sys_vars/r/wsrep_recover_basic.result | 69 ++++--------- .../r/wsrep_replicate_myisam_basic.result | 39 ++++++-- .../r/wsrep_restart_slave_basic.result | 39 ++++++-- .../r/wsrep_retry_autocommit_basic.result | 71 +++++++++++-- .../r/wsrep_slave_threads_basic.result | 63 ++++++++---- .../sys_vars/r/wsrep_sst_auth_basic.result | 55 ++++++++++- .../sys_vars/r/wsrep_sst_donor_basic.result | 58 +++++++++-- ...rep_sst_donor_rejects_queries_basic.result | 53 ++++++++-- .../sys_vars/r/wsrep_sst_method_basic.result | 64 +++++++++--- .../r/wsrep_sst_receive_address_basic.result | 72 ++++++++++++-- .../r/wsrep_start_position_basic.result | 63 ++++++++++-- .../t/wsrep_auto_increment_control_basic.test | 49 +++++++-- .../sys_vars/t/wsrep_causal_reads_basic.test | 52 ++++++++-- .../suite/sys_vars/t/wsrep_certify_nonpk | 13 --- .../sys_vars/t/wsrep_certify_nonpk_basic.test | 49 +++++++-- .../t/wsrep_cluster_address_basic.test | 74 +++++++------- .../sys_vars/t/wsrep_cluster_name_basic.test | 46 +++++++-- .../t/wsrep_convert_lock_to_trx_basic.test | 49 +++++++-- .../sys_vars/t/wsrep_data_home_dir_basic.test | 77 +++++++-------- .../sys_vars/t/wsrep_dbug_option_basic.test | 47 +++++++-- .../suite/sys_vars/t/wsrep_debug_basic.test | 49 +++++++-- .../sys_vars/t/wsrep_debug_option_basic.test | 13 --- .../suite/sys_vars/t/wsrep_desync_basic.test | 51 +++++++++- .../wsrep_drupal_282555_workaround_basic.test | 49 +++++++-- .../t/wsrep_forced_binlog_format_basic.test | 52 ++++++++-- .../t/wsrep_load_data_splitting_basic.test | 49 +++++++-- .../sys_vars/t/wsrep_log_conflicts_basic.test | 49 +++++++-- .../sys_vars/t/wsrep_max_ws_rows_basic.test | 53 +++++++--- .../sys_vars/t/wsrep_max_ws_size_basic.test | 53 +++++++--- .../wsrep_mysql_replication_bundle_basic.test | 53 +++++++--- .../sys_vars/t/wsrep_node_address_basic.test | 71 ++++++------- .../t/wsrep_node_incoming_address_basic.test | 73 +++++++------- .../sys_vars/t/wsrep_node_name_basic.test | 49 +++++++-- .../sys_vars/t/wsrep_notify_cmd_basic.test | 48 +++++++-- .../suite/sys_vars/t/wsrep_on_basic.test | 52 ++++++++-- .../sys_vars/t/wsrep_osu_method_basic.test | 60 ++++++++--- .../sys_vars/t/wsrep_provider_basic.test | 42 +++++++- .../t/wsrep_provider_options_basic.test | 47 ++++++++- .../suite/sys_vars/t/wsrep_recover_basic.test | 63 ++++-------- .../t/wsrep_replicate_myisam_basic.test | 43 ++++++-- .../sys_vars/t/wsrep_restart_slave_basic.test | 43 ++++++-- .../t/wsrep_retry_autocommit_basic.test | 59 +++++++++-- .../sys_vars/t/wsrep_slave_threads_basic.test | 53 +++++++--- .../sys_vars/t/wsrep_sst_auth_basic.test | 53 ++++++++-- .../sys_vars/t/wsrep_sst_donor_basic.test | 51 ++++++++-- ...wsrep_sst_donor_rejects_queries_basic.test | 49 +++++++-- .../sys_vars/t/wsrep_sst_method_basic.test | 58 ++++++++--- .../t/wsrep_sst_receive_address_basic.test | 60 +++++++++-- .../t/wsrep_start_position_basic.test | 62 ++++++++++-- .../t/wsrep_wsrep_provider_basic.test | 11 --- 75 files changed, 3166 insertions(+), 1004 deletions(-) delete mode 100644 mysql-test/suite/sys_vars/t/wsrep_certify_nonpk delete mode 100644 mysql-test/suite/sys_vars/t/wsrep_debug_option_basic.test delete mode 100644 mysql-test/suite/sys_vars/t/wsrep_wsrep_provider_basic.test diff --git a/mysql-test/suite/sys_vars/r/wsrep_auto_increment_control_basic.result b/mysql-test/suite/sys_vars/r/wsrep_auto_increment_control_basic.result index d5affeaf5e4..2608e58b986 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_auto_increment_control_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_auto_increment_control_basic.result @@ -1,8 +1,45 @@ -set @start_value = @@wsrep_auto_increment_control; -set @@global.wsrep_auto_increment_control=ON; -set @@global.wsrep_auto_increment_control=OFF; -set @@global.wsrep_auto_increment_control=1; -set @@global.wsrep_auto_increment_control=0; -SET @@global.wsrep_auto_increment_control = -1; -ERROR 42000: Variable 'wsrep_auto_increment_control' can't be set to the value of '-1' -set @@global.wsrep_auto_increment_control = @start_value; +# +# wsrep_auto_increment_control +# +# save the initial value +SET @wsrep_auto_increment_control_global_saved = @@global.wsrep_auto_increment_control; +# default +SELECT @@global.wsrep_auto_increment_control; +@@global.wsrep_auto_increment_control +1 + +# scope +SELECT @@session.wsrep_auto_increment_control; +ERROR HY000: Variable 'wsrep_auto_increment_control' is a GLOBAL variable +SET @@global.wsrep_auto_increment_control=OFF; +SELECT @@global.wsrep_auto_increment_control; +@@global.wsrep_auto_increment_control +0 +SET @@global.wsrep_auto_increment_control=ON; +SELECT @@global.wsrep_auto_increment_control; +@@global.wsrep_auto_increment_control +1 + +# valid values +SET @@global.wsrep_auto_increment_control='OFF'; +SELECT @@global.wsrep_auto_increment_control; +@@global.wsrep_auto_increment_control +0 +SET @@global.wsrep_auto_increment_control=ON; +SELECT @@global.wsrep_auto_increment_control; +@@global.wsrep_auto_increment_control +1 +SET @@global.wsrep_auto_increment_control=default; +SELECT @@global.wsrep_auto_increment_control; +@@global.wsrep_auto_increment_control +1 + +# invalid values +SET @@global.wsrep_auto_increment_control=NULL; +ERROR 42000: Variable 'wsrep_auto_increment_control' can't be set to the value of 'NULL' +SET @@global.wsrep_auto_increment_control='junk'; +ERROR 42000: Variable 'wsrep_auto_increment_control' can't be set to the value of 'junk' + +# restore the initial value +SET @@global.wsrep_auto_increment_control = @wsrep_auto_increment_control_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_causal_reads_basic.result b/mysql-test/suite/sys_vars/r/wsrep_causal_reads_basic.result index 3b96654f8c7..501117dda9f 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_causal_reads_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_causal_reads_basic.result @@ -1,8 +1,50 @@ -set @start_value = @@wsrep_causal_reads; -set @@global.wsrep_causal_reads=ON; -set @@global.wsrep_causal_reads=OFF; -set @@global.wsrep_causal_reads=1; -set @@global.wsrep_causal_reads=0; -SET @@global.wsrep_causal_reads = -1; -ERROR 42000: Variable 'wsrep_causal_reads' can't be set to the value of '-1' -set @@global.wsrep_causal_reads = @start_value; +# +# wsrep_causal_reads +# +# save the initial values +SET @wsrep_causal_reads_global_saved = @@global.wsrep_causal_reads; +SET @wsrep_causal_reads_session_saved = @@session.wsrep_causal_reads; +# default +SELECT @@global.wsrep_causal_reads; +@@global.wsrep_causal_reads +0 +SELECT @@session.wsrep_causal_reads; +@@session.wsrep_causal_reads +0 + +# scope and valid values +SET @@global.wsrep_causal_reads=OFF; +SELECT @@global.wsrep_causal_reads; +@@global.wsrep_causal_reads +0 +SET @@global.wsrep_causal_reads=ON; +SELECT @@global.wsrep_causal_reads; +@@global.wsrep_causal_reads +1 +SET @@session.wsrep_causal_reads=OFF; +SELECT @@session.wsrep_causal_reads; +@@session.wsrep_causal_reads +0 +SET @@session.wsrep_causal_reads=ON; +SELECT @@session.wsrep_causal_reads; +@@session.wsrep_causal_reads +1 +SET @@session.wsrep_causal_reads=default; +SELECT @@session.wsrep_causal_reads; +@@session.wsrep_causal_reads +1 + +# invalid values +SET @@global.wsrep_causal_reads=NULL; +ERROR 42000: Variable 'wsrep_causal_reads' can't be set to the value of 'NULL' +SET @@global.wsrep_causal_reads='junk'; +ERROR 42000: Variable 'wsrep_causal_reads' can't be set to the value of 'junk' +SET @@session.wsrep_causal_reads=NULL; +ERROR 42000: Variable 'wsrep_causal_reads' can't be set to the value of 'NULL' +SET @@session.wsrep_causal_reads='junk'; +ERROR 42000: Variable 'wsrep_causal_reads' can't be set to the value of 'junk' + +# restore the initial values +SET @@global.wsrep_causal_reads = @wsrep_causal_reads_global_saved; +SET @@session.wsrep_causal_reads = @wsrep_causal_reads_session_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_certify_nonpk_basic.result b/mysql-test/suite/sys_vars/r/wsrep_certify_nonpk_basic.result index 4b02f9fb61e..7200d14f75f 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_certify_nonpk_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_certify_nonpk_basic.result @@ -1,8 +1,45 @@ -set @start_value = @@wsrep_certify_nonpk; -set @@global.wsrep_certify_nonpk=ON; -set @@global.wsrep_certify_nonpk=OFF; -set @@global.wsrep_certify_nonpk=1; -set @@global.wsrep_certify_nonpk=0; -SET @@global.wsrep_certify_nonpk = -1; -ERROR 42000: Variable 'wsrep_certify_nonPK' can't be set to the value of '-1' -set @@global.wsrep_certify_nonpk = @start_value; +# +# wsrep_certify_nonpk +# +# save the initial value +SET @wsrep_certify_nonpk_global_saved = @@global.wsrep_certify_nonpk; +# default +SELECT @@global.wsrep_certify_nonpk; +@@global.wsrep_certify_nonpk +1 + +# scope +SELECT @@session.wsrep_certify_nonpk; +ERROR HY000: Variable 'wsrep_certify_nonPK' is a GLOBAL variable +SET @@global.wsrep_certify_nonpk=OFF; +SELECT @@global.wsrep_certify_nonpk; +@@global.wsrep_certify_nonpk +0 +SET @@global.wsrep_certify_nonpk=ON; +SELECT @@global.wsrep_certify_nonpk; +@@global.wsrep_certify_nonpk +1 + +# valid values +SET @@global.wsrep_certify_nonpk='OFF'; +SELECT @@global.wsrep_certify_nonpk; +@@global.wsrep_certify_nonpk +0 +SET @@global.wsrep_certify_nonpk=ON; +SELECT @@global.wsrep_certify_nonpk; +@@global.wsrep_certify_nonpk +1 +SET @@global.wsrep_certify_nonpk=default; +SELECT @@global.wsrep_certify_nonpk; +@@global.wsrep_certify_nonpk +1 + +# invalid values +SET @@global.wsrep_certify_nonpk=NULL; +ERROR 42000: Variable 'wsrep_certify_nonPK' can't be set to the value of 'NULL' +SET @@global.wsrep_certify_nonpk='junk'; +ERROR 42000: Variable 'wsrep_certify_nonPK' can't be set to the value of 'junk' + +# restore the initial value +SET @@global.wsrep_certify_nonpk = @wsrep_certify_nonpk_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_cluster_address_basic.result b/mysql-test/suite/sys_vars/r/wsrep_cluster_address_basic.result index 734908d42e5..8497e220523 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_cluster_address_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_cluster_address_basic.result @@ -1,45 +1,54 @@ -SELECT COUNT(@@GLOBAL.wsrep_cluster_address); -COUNT(@@GLOBAL.wsrep_cluster_address) -1 -1 Expected -SELECT COUNT(@@GLOBAL.wsrep_cluster_address); -COUNT(@@GLOBAL.wsrep_cluster_address) -1 -1 Expected -SELECT @@GLOBAL.wsrep_cluster_address = VARIABLE_VALUE -FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES -WHERE VARIABLE_NAME='wsrep_cluster_address'; -@@GLOBAL.wsrep_cluster_address = VARIABLE_VALUE -1 -1 Expected -SELECT COUNT(@@GLOBAL.wsrep_cluster_address); -COUNT(@@GLOBAL.wsrep_cluster_address) -1 -1 Expected -SELECT COUNT(VARIABLE_VALUE) -FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES -WHERE VARIABLE_NAME='wsrep_cluster_address'; -COUNT(VARIABLE_VALUE) -1 -1 Expected -SELECT @@wsrep_cluster_address = @@GLOBAL.wsrep_cluster_address; -@@wsrep_cluster_address = @@GLOBAL.wsrep_cluster_address -1 -1 Expected -SELECT COUNT(@@wsrep_cluster_address); -COUNT(@@wsrep_cluster_address) -1 -1 Expected -SELECT COUNT(@@local.wsrep_cluster_address); +# +# wsrep_cluster_address +# +call mtr.add_suppression("safe_mutex: Found wrong usage of mutex.*"); +# save the initial value +SET @wsrep_cluster_address_global_saved = @@global.wsrep_cluster_address; +# default +SELECT @@global.wsrep_cluster_address; +@@global.wsrep_cluster_address + + +# scope +SELECT @@session.wsrep_cluster_address; ERROR HY000: Variable 'wsrep_cluster_address' is a GLOBAL variable -Expected error 'Variable is a GLOBAL variable' -SELECT COUNT(@@SESSION.wsrep_cluster_address); -ERROR HY000: Variable 'wsrep_cluster_address' is a GLOBAL variable -Expected error 'Variable is a GLOBAL variable' -SELECT COUNT(@@GLOBAL.wsrep_cluster_address); -COUNT(@@GLOBAL.wsrep_cluster_address) -1 -1 Expected -SELECT wsrep_cluster_address = @@SESSION.wsrep_cluster_address; -ERROR 42S22: Unknown column 'wsrep_cluster_address' in 'field list' -Expected error 'Readonly variable' +SELECT @@global.wsrep_cluster_address; +@@global.wsrep_cluster_address + + +# valid values +SET @@global.wsrep_cluster_address='127.0.0.1'; +SELECT @@global.wsrep_cluster_address; +@@global.wsrep_cluster_address +127.0.0.1 +SET @@global.wsrep_cluster_address=AUTO; +SELECT @@global.wsrep_cluster_address; +@@global.wsrep_cluster_address +AUTO +SET @@global.wsrep_cluster_address=default; +SELECT @@global.wsrep_cluster_address; +@@global.wsrep_cluster_address + + +# invalid values +SET @@global.wsrep_node_address=NULL; +ERROR 42000: Variable 'wsrep_node_address' can't be set to the value of 'NULL' +SELECT @@global.wsrep_node_address; +@@global.wsrep_node_address + +SET @@global.wsrep_cluster_address=ON; +SELECT @@global.wsrep_cluster_address; +@@global.wsrep_cluster_address +ON +SET @@global.wsrep_cluster_address='OFF'; +SELECT @@global.wsrep_cluster_address; +@@global.wsrep_cluster_address +OFF +SET @@global.wsrep_cluster_address='junk'; +SELECT @@global.wsrep_cluster_address; +@@global.wsrep_cluster_address +junk + +# restore the initial value +SET @@global.wsrep_cluster_address = @wsrep_cluster_address_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_cluster_name_basic.result b/mysql-test/suite/sys_vars/r/wsrep_cluster_name_basic.result index 59c3b9381d1..29a2d966489 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_cluster_name_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_cluster_name_basic.result @@ -1,7 +1,43 @@ -set @start_value = @@wsrep_cluster_name; -set @@global.wsrep_cluster_name='test'; -set @@global.wsrep_cluster_name=NULL; +# +# wsrep_cluster_name +# +# save the initial value +SET @wsrep_cluster_name_global_saved = @@global.wsrep_cluster_name; +# default +SELECT @@global.wsrep_cluster_name; +@@global.wsrep_cluster_name +my_wsrep_cluster + +# scope +SELECT @@session.wsrep_cluster_name; +ERROR HY000: Variable 'wsrep_cluster_name' is a GLOBAL variable +SET @@global.wsrep_cluster_name='my_galera_cluster'; +SELECT @@global.wsrep_cluster_name; +@@global.wsrep_cluster_name +my_galera_cluster + +# valid values +SET @@global.wsrep_cluster_name='my_quoted_galera_cluster'; +SELECT @@global.wsrep_cluster_name; +@@global.wsrep_cluster_name +my_quoted_galera_cluster +SET @@global.wsrep_cluster_name=my_unquoted_cluster; +SELECT @@global.wsrep_cluster_name; +@@global.wsrep_cluster_name +my_unquoted_cluster +SET @@global.wsrep_cluster_name=OFF; +SELECT @@global.wsrep_cluster_name; +@@global.wsrep_cluster_name +OFF +SET @@global.wsrep_cluster_name=default; +SELECT @@global.wsrep_cluster_name; +@@global.wsrep_cluster_name +my_wsrep_cluster + +# invalid values +SET @@global.wsrep_cluster_name=NULL; ERROR 42000: Variable 'wsrep_cluster_name' can't be set to the value of 'NULL' -SET @@global.wsrep_cluster_name = 1; -ERROR 42000: Incorrect argument type to variable 'wsrep_cluster_name' -set @@global.wsrep_cluster_name = @start_value; + +# restore the initial value +SET @@global.wsrep_cluster_name = @wsrep_cluster_name_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_convert_lock_to_trx_basic.result b/mysql-test/suite/sys_vars/r/wsrep_convert_lock_to_trx_basic.result index 10043812289..80210c4c4b6 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_convert_lock_to_trx_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_convert_lock_to_trx_basic.result @@ -1,8 +1,45 @@ -set @start_value = @@wsrep_convert_lock_to_trx; -set @@global.wsrep_convert_lock_to_trx=ON; -set @@global.wsrep_convert_lock_to_trx=OFF; -set @@global.wsrep_convert_lock_to_trx=1; -set @@global.wsrep_convert_lock_to_trx=0; -SET @@global.wsrep_convert_lock_to_trx = -1; -ERROR 42000: Variable 'wsrep_convert_LOCK_to_trx' can't be set to the value of '-1' -set @@global.wsrep_convert_lock_to_trx = @start_value; +# +# wsrep_convert_lock_to_trx +# +# save the initial value +SET @wsrep_convert_lock_to_trx_global_saved = @@global.wsrep_convert_lock_to_trx; +# default +SELECT @@global.wsrep_convert_lock_to_trx; +@@global.wsrep_convert_lock_to_trx +0 + +# scope +SELECT @@session.wsrep_convert_lock_to_trx; +ERROR HY000: Variable 'wsrep_convert_LOCK_to_trx' is a GLOBAL variable +SET @@global.wsrep_convert_lock_to_trx=OFF; +SELECT @@global.wsrep_convert_lock_to_trx; +@@global.wsrep_convert_lock_to_trx +0 +SET @@global.wsrep_convert_lock_to_trx=ON; +SELECT @@global.wsrep_convert_lock_to_trx; +@@global.wsrep_convert_lock_to_trx +1 + +# valid values +SET @@global.wsrep_convert_lock_to_trx='OFF'; +SELECT @@global.wsrep_convert_lock_to_trx; +@@global.wsrep_convert_lock_to_trx +0 +SET @@global.wsrep_convert_lock_to_trx=ON; +SELECT @@global.wsrep_convert_lock_to_trx; +@@global.wsrep_convert_lock_to_trx +1 +SET @@global.wsrep_convert_lock_to_trx=default; +SELECT @@global.wsrep_convert_lock_to_trx; +@@global.wsrep_convert_lock_to_trx +0 + +# invalid values +SET @@global.wsrep_convert_lock_to_trx=NULL; +ERROR 42000: Variable 'wsrep_convert_LOCK_to_trx' can't be set to the value of 'NULL' +SET @@global.wsrep_convert_lock_to_trx='junk'; +ERROR 42000: Variable 'wsrep_convert_LOCK_to_trx' can't be set to the value of 'junk' + +# restore the initial value +SET @@global.wsrep_convert_lock_to_trx = @wsrep_convert_lock_to_trx_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_data_home_dir_basic.result b/mysql-test/suite/sys_vars/r/wsrep_data_home_dir_basic.result index 668aebe30f1..044ef8bf3bc 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_data_home_dir_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_data_home_dir_basic.result @@ -1,48 +1,48 @@ -SELECT COUNT(@@GLOBAL.wsrep_data_home_dir); -COUNT(@@GLOBAL.wsrep_data_home_dir) -1 -1 Expected -SET @@GLOBAL.wsrep_data_home_dir=1; +# +# wsrep_data_home_dir (readonly) +# +# default +SELECT @@global.wsrep_data_home_dir; +@@global.wsrep_data_home_dir + + +# scope +SELECT @@session.wsrep_data_home_dir; +ERROR HY000: Variable 'wsrep_data_home_dir' is a GLOBAL variable +SET @@global.wsrep_data_home_dir='/tmp/data'; ERROR HY000: Variable 'wsrep_data_home_dir' is a read only variable -Expected error 'Read only variable' -SELECT COUNT(@@GLOBAL.wsrep_data_home_dir); -COUNT(@@GLOBAL.wsrep_data_home_dir) -1 -1 Expected -SELECT @@GLOBAL.wsrep_data_home_dir = VARIABLE_VALUE -FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES -WHERE VARIABLE_NAME='wsrep_data_home_dir'; -@@GLOBAL.wsrep_data_home_dir = VARIABLE_VALUE -1 -1 Expected -SELECT COUNT(@@GLOBAL.wsrep_data_home_dir); -COUNT(@@GLOBAL.wsrep_data_home_dir) -1 -1 Expected -SELECT COUNT(VARIABLE_VALUE) -FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES -WHERE VARIABLE_NAME='wsrep_data_home_dir'; -COUNT(VARIABLE_VALUE) -1 -1 Expected -SELECT @@wsrep_data_home_dir = @@GLOBAL.wsrep_data_home_dir; -@@wsrep_data_home_dir = @@GLOBAL.wsrep_data_home_dir -1 -1 Expected -SELECT COUNT(@@wsrep_data_home_dir); -COUNT(@@wsrep_data_home_dir) -1 -1 Expected -SELECT COUNT(@@local.wsrep_data_home_dir); -ERROR HY000: Variable 'wsrep_data_home_dir' is a GLOBAL variable -Expected error 'Variable is a GLOBAL variable' -SELECT COUNT(@@SESSION.wsrep_data_home_dir); -ERROR HY000: Variable 'wsrep_data_home_dir' is a GLOBAL variable -Expected error 'Variable is a GLOBAL variable' -SELECT COUNT(@@GLOBAL.wsrep_data_home_dir); -COUNT(@@GLOBAL.wsrep_data_home_dir) -1 -1 Expected -SELECT wsrep_data_home_dir = @@SESSION.wsrep_data_home_dir; -ERROR 42S22: Unknown column 'wsrep_data_home_dir' in 'field list' -Expected error 'Readonly variable' +SELECT @@global.wsrep_data_home_dir; +@@global.wsrep_data_home_dir + + +# valid values +SET @@global.wsrep_data_home_dir='/tmp/data'; +ERROR HY000: Variable 'wsrep_data_home_dir' is a read only variable +SELECT @@global.wsrep_data_home_dir; +@@global.wsrep_data_home_dir + +SET @@global.wsrep_data_home_dir=junk-dir; +ERROR HY000: Variable 'wsrep_data_home_dir' is a read only variable +SELECT @@global.wsrep_data_home_dir; +@@global.wsrep_data_home_dir + +SET @@global.wsrep_data_home_dir=junk/dir; +ERROR HY000: Variable 'wsrep_data_home_dir' is a read only variable +SELECT @@global.wsrep_data_home_dir; +@@global.wsrep_data_home_dir + +SET @@global.wsrep_data_home_dir=OFF; +ERROR HY000: Variable 'wsrep_data_home_dir' is a read only variable +SELECT @@global.wsrep_data_home_dir; +@@global.wsrep_data_home_dir + +SET @@global.wsrep_data_home_dir=default; +ERROR HY000: Variable 'wsrep_data_home_dir' is a read only variable +SELECT @@global.wsrep_data_home_dir; +@@global.wsrep_data_home_dir + + +# invalid values +SET @@global.wsrep_data_home_dir=NULL; +ERROR HY000: Variable 'wsrep_data_home_dir' is a read only variable +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_dbug_option_basic.result b/mysql-test/suite/sys_vars/r/wsrep_dbug_option_basic.result index 36ebcb17002..2092d54681e 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_dbug_option_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_dbug_option_basic.result @@ -1,6 +1,47 @@ -set @start_value = @@wsrep_dbug_option; -set @@global.wsrep_dbug_option='foo:bar'; -set @@global.wsrep_dbug_option=NULL; -SET @@global.wsrep_dbug_option = -1; +# +# wsrep_dbug_option +# +# save the initial value +SET @wsrep_dbug_option_global_saved = @@global.wsrep_dbug_option; +# default +SELECT @@global.wsrep_dbug_option; +@@global.wsrep_dbug_option + + +# scope +SELECT @@session.wsrep_dbug_option; +ERROR HY000: Variable 'wsrep_dbug_option' is a GLOBAL variable +SET @@global.wsrep_dbug_option='test-dbug-string'; +SELECT @@global.wsrep_dbug_option; +@@global.wsrep_dbug_option +test-dbug-string + +# valid values +SET @@global.wsrep_dbug_option='quoted-dbug-string'; +SELECT @@global.wsrep_dbug_option; +@@global.wsrep_dbug_option +quoted-dbug-string +SET @@global.wsrep_dbug_option=unquoted_dbug_string; +SELECT @@global.wsrep_dbug_option; +@@global.wsrep_dbug_option +unquoted_dbug_string +SET @@global.wsrep_dbug_option=OFF; +SELECT @@global.wsrep_dbug_option; +@@global.wsrep_dbug_option +OFF +SET @@global.wsrep_dbug_option=NULL; +SELECT @@global.wsrep_dbug_option; +@@global.wsrep_dbug_option +NULL +SET @@global.wsrep_dbug_option=default; +SELECT @@global.wsrep_dbug_option; +@@global.wsrep_dbug_option + + +# invalid values +SET @@global.wsrep_dbug_option=1; ERROR 42000: Incorrect argument type to variable 'wsrep_dbug_option' -set @@global.wsrep_dbug_option = @start_value; + +# restore the initial value +SET @@global.wsrep_dbug_option = @wsrep_dbug_option_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_debug_basic.result b/mysql-test/suite/sys_vars/r/wsrep_debug_basic.result index 6bbe780316b..96c262c110c 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_debug_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_debug_basic.result @@ -1,8 +1,45 @@ -set @start_value = @@wsrep_debug; -set @@global.wsrep_debug=ON; -set @@global.wsrep_debug=OFF; -set @@global.wsrep_debug=1; -set @@global.wsrep_debug=0; -SET @@global.wsrep_debug = -1; -ERROR 42000: Variable 'wsrep_debug' can't be set to the value of '-1' -set @@global.wsrep_debug = @start_value; +# +# wsrep_debug +# +# save the initial value +SET @wsrep_debug_global_saved = @@global.wsrep_debug; +# default +SELECT @@global.wsrep_debug; +@@global.wsrep_debug +0 + +# scope +SELECT @@session.wsrep_debug; +ERROR HY000: Variable 'wsrep_debug' is a GLOBAL variable +SET @@global.wsrep_debug=OFF; +SELECT @@global.wsrep_debug; +@@global.wsrep_debug +0 +SET @@global.wsrep_debug=ON; +SELECT @@global.wsrep_debug; +@@global.wsrep_debug +1 + +# valid values +SET @@global.wsrep_debug='OFF'; +SELECT @@global.wsrep_debug; +@@global.wsrep_debug +0 +SET @@global.wsrep_debug=ON; +SELECT @@global.wsrep_debug; +@@global.wsrep_debug +1 +SET @@global.wsrep_debug=default; +SELECT @@global.wsrep_debug; +@@global.wsrep_debug +0 + +# invalid values +SET @@global.wsrep_debug=NULL; +ERROR 42000: Variable 'wsrep_debug' can't be set to the value of 'NULL' +SET @@global.wsrep_debug='junk'; +ERROR 42000: Variable 'wsrep_debug' can't be set to the value of 'junk' + +# restore the initial value +SET @@global.wsrep_debug = @wsrep_debug_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_desync_basic.result b/mysql-test/suite/sys_vars/r/wsrep_desync_basic.result index a61367ca200..69599c4b47a 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_desync_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_desync_basic.result @@ -1,3 +1,52 @@ -select @@global.wsrep_desync; +# +# wsrep_desync +# +call mtr.add_suppression("WSREP: SET desync failed 9 for SET @@global.wsrep_desync=ON"); +# save the initial value +SET @wsrep_desync_global_saved = @@global.wsrep_desync; +# default +SELECT @@global.wsrep_desync; @@global.wsrep_desync 0 + +# scope +SELECT @@session.wsrep_desync; +ERROR HY000: Variable 'wsrep_desync' is a GLOBAL variable +SET @@global.wsrep_desync=OFF; +Warnings: +Warning 1231 'wsrep_desync' is already OFF. +SELECT @@global.wsrep_desync; +@@global.wsrep_desync +0 +SET @@global.wsrep_desync=ON; +ERROR HY000: Operation 'desync' failed for SET @@global.wsrep_desync=ON +SELECT @@global.wsrep_desync; +@@global.wsrep_desync +1 + +# valid values +SET @@global.wsrep_desync='OFF'; +SELECT @@global.wsrep_desync; +@@global.wsrep_desync +0 +SET @@global.wsrep_desync=ON; +ERROR HY000: Operation 'desync' failed for SET @@global.wsrep_desync=ON +SELECT @@global.wsrep_desync; +@@global.wsrep_desync +1 +SET @@global.wsrep_desync=default; +SELECT @@global.wsrep_desync; +@@global.wsrep_desync +0 + +# invalid values +SET @@global.wsrep_desync=NULL; +ERROR 42000: Variable 'wsrep_desync' can't be set to the value of 'NULL' +SET @@global.wsrep_desync='junk'; +ERROR 42000: Variable 'wsrep_desync' can't be set to the value of 'junk' + +# restore the initial value +SET @@global.wsrep_desync = @wsrep_desync_global_saved; +Warnings: +Warning 1231 'wsrep_desync' is already OFF. +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_drupal_282555_workaround_basic.result b/mysql-test/suite/sys_vars/r/wsrep_drupal_282555_workaround_basic.result index 5a8d5a8abee..52bfc01e810 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_drupal_282555_workaround_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_drupal_282555_workaround_basic.result @@ -1,8 +1,45 @@ -set @start_value = @@wsrep_drupal_282555_workaround; -set @@global.wsrep_drupal_282555_workaround=ON; -set @@global.wsrep_drupal_282555_workaround=OFF; -set @@global.wsrep_drupal_282555_workaround=1; -set @@global.wsrep_drupal_282555_workaround=0; -SET @@global.wsrep_drupal_282555_workaround = -1; -ERROR 42000: Variable 'wsrep_drupal_282555_workaround' can't be set to the value of '-1' -set @@global.wsrep_drupal_282555_workaround = @start_value; +# +# wsrep_drupal_282555_workaround +# +# save the initial value +SET @wsrep_drupal_282555_workaround_global_saved = @@global.wsrep_drupal_282555_workaround; +# default +SELECT @@global.wsrep_drupal_282555_workaround; +@@global.wsrep_drupal_282555_workaround +0 + +# scope +SELECT @@session.wsrep_drupal_282555_workaround; +ERROR HY000: Variable 'wsrep_drupal_282555_workaround' is a GLOBAL variable +SET @@global.wsrep_drupal_282555_workaround=OFF; +SELECT @@global.wsrep_drupal_282555_workaround; +@@global.wsrep_drupal_282555_workaround +0 +SET @@global.wsrep_drupal_282555_workaround=ON; +SELECT @@global.wsrep_drupal_282555_workaround; +@@global.wsrep_drupal_282555_workaround +1 + +# valid values +SET @@global.wsrep_drupal_282555_workaround='OFF'; +SELECT @@global.wsrep_drupal_282555_workaround; +@@global.wsrep_drupal_282555_workaround +0 +SET @@global.wsrep_drupal_282555_workaround=ON; +SELECT @@global.wsrep_drupal_282555_workaround; +@@global.wsrep_drupal_282555_workaround +1 +SET @@global.wsrep_drupal_282555_workaround=default; +SELECT @@global.wsrep_drupal_282555_workaround; +@@global.wsrep_drupal_282555_workaround +0 + +# invalid values +SET @@global.wsrep_drupal_282555_workaround=NULL; +ERROR 42000: Variable 'wsrep_drupal_282555_workaround' can't be set to the value of 'NULL' +SET @@global.wsrep_drupal_282555_workaround='junk'; +ERROR 42000: Variable 'wsrep_drupal_282555_workaround' can't be set to the value of 'junk' + +# restore the initial value +SET @@global.wsrep_drupal_282555_workaround = @wsrep_drupal_282555_workaround_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_forced_binlog_format_basic.result b/mysql-test/suite/sys_vars/r/wsrep_forced_binlog_format_basic.result index 58bdb45c8de..3cf5ffcaf4e 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_forced_binlog_format_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_forced_binlog_format_basic.result @@ -1,8 +1,51 @@ -set @start_value = @@wsrep_forced_binlog_format; -set @@global.wsrep_forced_binlog_format = ROW; -set @@global.wsrep_forced_binlog_format = MIXED; -set @@global.wsrep_forced_binlog_format = STATEMENT; -set @@global.wsrep_forced_binlog_format = NONE; -set @@global.wsrep_forced_binlog_format = FOO; -ERROR 42000: Variable 'wsrep_forced_binlog_format' can't be set to the value of 'FOO' -set @@global.wsrep_forced_binlog_format = @start_value; +# +# wsrep_forced_binlog_format +# +# save the initial value +SET @wsrep_forced_binlog_format_global_saved = @@global.wsrep_forced_binlog_format; +# default +SELECT @@global.wsrep_forced_binlog_format; +@@global.wsrep_forced_binlog_format +NONE + +# scope +SELECT @@session.wsrep_forced_binlog_format; +ERROR HY000: Variable 'wsrep_forced_binlog_format' is a GLOBAL variable +SET @@global.wsrep_forced_binlog_format=STATEMENT; +SELECT @@global.wsrep_forced_binlog_format; +@@global.wsrep_forced_binlog_format +STATEMENT + +# valid values +SET @@global.wsrep_forced_binlog_format=STATEMENT; +SELECT @@global.wsrep_forced_binlog_format; +@@global.wsrep_forced_binlog_format +STATEMENT +SET @@global.wsrep_forced_binlog_format=ROW; +SELECT @@global.wsrep_forced_binlog_format; +@@global.wsrep_forced_binlog_format +ROW +SET @@global.wsrep_forced_binlog_format=MIXED; +SELECT @@global.wsrep_forced_binlog_format; +@@global.wsrep_forced_binlog_format +MIXED +SET @@global.wsrep_forced_binlog_format=NONE; +SELECT @@global.wsrep_forced_binlog_format; +@@global.wsrep_forced_binlog_format +NONE +SET @@global.wsrep_forced_binlog_format=default; +SELECT @@global.wsrep_forced_binlog_format; +@@global.wsrep_forced_binlog_format +NONE + +# invalid values +SET @@global.wsrep_forced_binlog_format=NULL; +ERROR 42000: Variable 'wsrep_forced_binlog_format' can't be set to the value of 'NULL' +SET @@global.wsrep_forced_binlog_format='junk'; +ERROR 42000: Variable 'wsrep_forced_binlog_format' can't be set to the value of 'junk' +SET @@global.wsrep_forced_binlog_format=ON; +ERROR 42000: Variable 'wsrep_forced_binlog_format' can't be set to the value of 'ON' + +# restore the initial value +SET @@global.wsrep_forced_binlog_format = @wsrep_forced_binlog_format_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_load_data_splitting_basic.result b/mysql-test/suite/sys_vars/r/wsrep_load_data_splitting_basic.result index be73397f35e..687934a7705 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_load_data_splitting_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_load_data_splitting_basic.result @@ -1,8 +1,45 @@ -set @start_value = @@wsrep_load_data_splitting; -set @@global.wsrep_load_data_splitting=ON; -set @@global.wsrep_load_data_splitting=OFF; -set @@global.wsrep_load_data_splitting=1; -set @@global.wsrep_load_data_splitting=0; -SET @@global.wsrep_load_data_splitting = -1; -ERROR 42000: Variable 'wsrep_load_data_splitting' can't be set to the value of '-1' -set @@global.wsrep_load_data_splitting = @start_value; +# +# wsrep_load_data_splitting +# +# save the initial value +SET @wsrep_load_data_splitting_global_saved = @@global.wsrep_load_data_splitting; +# default +SELECT @@global.wsrep_load_data_splitting; +@@global.wsrep_load_data_splitting +1 + +# scope +SELECT @@session.wsrep_load_data_splitting; +ERROR HY000: Variable 'wsrep_load_data_splitting' is a GLOBAL variable +SET @@global.wsrep_load_data_splitting=OFF; +SELECT @@global.wsrep_load_data_splitting; +@@global.wsrep_load_data_splitting +0 +SET @@global.wsrep_load_data_splitting=ON; +SELECT @@global.wsrep_load_data_splitting; +@@global.wsrep_load_data_splitting +1 + +# valid values +SET @@global.wsrep_load_data_splitting='OFF'; +SELECT @@global.wsrep_load_data_splitting; +@@global.wsrep_load_data_splitting +0 +SET @@global.wsrep_load_data_splitting=ON; +SELECT @@global.wsrep_load_data_splitting; +@@global.wsrep_load_data_splitting +1 +SET @@global.wsrep_load_data_splitting=default; +SELECT @@global.wsrep_load_data_splitting; +@@global.wsrep_load_data_splitting +1 + +# invalid values +SET @@global.wsrep_load_data_splitting=NULL; +ERROR 42000: Variable 'wsrep_load_data_splitting' can't be set to the value of 'NULL' +SET @@global.wsrep_load_data_splitting='junk'; +ERROR 42000: Variable 'wsrep_load_data_splitting' can't be set to the value of 'junk' + +# restore the initial value +SET @@global.wsrep_load_data_splitting = @wsrep_load_data_splitting_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_log_conflicts_basic.result b/mysql-test/suite/sys_vars/r/wsrep_log_conflicts_basic.result index 22d8cbb568a..4d577daa904 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_log_conflicts_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_log_conflicts_basic.result @@ -1,8 +1,45 @@ -set @start_value = @@wsrep_log_conflicts; -set @@global.wsrep_log_conflicts=ON; -set @@global.wsrep_log_conflicts=OFF; -set @@global.wsrep_log_conflicts=1; -set @@global.wsrep_log_conflicts=0; -SET @@global.wsrep_log_conflicts = -1; -ERROR 42000: Variable 'wsrep_log_conflicts' can't be set to the value of '-1' -set @@global.wsrep_log_conflicts = @start_value; +# +# wsrep_log_conflicts +# +# save the initial value +SET @wsrep_log_conflicts_global_saved = @@global.wsrep_log_conflicts; +# default +SELECT @@global.wsrep_log_conflicts; +@@global.wsrep_log_conflicts +0 + +# scope +SELECT @@session.wsrep_log_conflicts; +ERROR HY000: Variable 'wsrep_log_conflicts' is a GLOBAL variable +SET @@global.wsrep_log_conflicts=OFF; +SELECT @@global.wsrep_log_conflicts; +@@global.wsrep_log_conflicts +0 +SET @@global.wsrep_log_conflicts=ON; +SELECT @@global.wsrep_log_conflicts; +@@global.wsrep_log_conflicts +1 + +# valid values +SET @@global.wsrep_log_conflicts='OFF'; +SELECT @@global.wsrep_log_conflicts; +@@global.wsrep_log_conflicts +0 +SET @@global.wsrep_log_conflicts=ON; +SELECT @@global.wsrep_log_conflicts; +@@global.wsrep_log_conflicts +1 +SET @@global.wsrep_log_conflicts=default; +SELECT @@global.wsrep_log_conflicts; +@@global.wsrep_log_conflicts +0 + +# invalid values +SET @@global.wsrep_log_conflicts=NULL; +ERROR 42000: Variable 'wsrep_log_conflicts' can't be set to the value of 'NULL' +SET @@global.wsrep_log_conflicts='junk'; +ERROR 42000: Variable 'wsrep_log_conflicts' can't be set to the value of 'junk' + +# restore the initial value +SET @@global.wsrep_log_conflicts = @wsrep_log_conflicts_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_max_ws_rows_basic.result b/mysql-test/suite/sys_vars/r/wsrep_max_ws_rows_basic.result index fc4dd38ade3..15438a2afd5 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_max_ws_rows_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_max_ws_rows_basic.result @@ -1,17 +1,53 @@ -set @start_value = @@wsrep_max_ws_rows; -set @@global.wsrep_max_ws_rows=256000; -set @@global.wsrep_max_ws_rows=0; +# +# wsrep_max_ws_rows +# +# save the initial value +SET @wsrep_max_ws_rows_global_saved = @@global.wsrep_max_ws_rows; +# default +SELECT @@global.wsrep_max_ws_rows; +@@global.wsrep_max_ws_rows +131072 + +# scope +SELECT @@session.wsrep_max_ws_rows; +ERROR HY000: Variable 'wsrep_max_ws_rows' is a GLOBAL variable +SET @@global.wsrep_max_ws_rows=1; +SELECT @@global.wsrep_max_ws_rows; +@@global.wsrep_max_ws_rows +1 + +# valid values +SET @@global.wsrep_max_ws_rows=131072; +SELECT @@global.wsrep_max_ws_rows; +@@global.wsrep_max_ws_rows +131072 +SET @@global.wsrep_max_ws_rows=131073; +SELECT @@global.wsrep_max_ws_rows; +@@global.wsrep_max_ws_rows +131073 +SET @@global.wsrep_max_ws_rows=0; Warnings: Warning 1292 Truncated incorrect wsrep_max_ws_rows value: '0' -show warnings; -Level Code Message -Warning 1292 Truncated incorrect wsrep_max_ws_rows value: '0' -set @@global.wsrep_max_ws_rows=-1; -Warnings: -Warning 1292 Truncated incorrect wsrep_max_ws_rows value: '-1' -show warnings; -Level Code Message -Warning 1292 Truncated incorrect wsrep_max_ws_rows value: '-1' -SET @@global.wsrep_max_ws_rows = r; +SELECT @@global.wsrep_max_ws_rows; +@@global.wsrep_max_ws_rows +1 +SET @@global.wsrep_max_ws_rows=default; +SELECT @global.wsrep_max_ws_rows; +@global.wsrep_max_ws_rows +NULL + +# invalid values +SET @@global.wsrep_max_ws_rows=NULL; ERROR 42000: Incorrect argument type to variable 'wsrep_max_ws_rows' -set @@global.wsrep_max_ws_rows = @start_value; +SET @@global.wsrep_max_ws_rows='junk'; +ERROR 42000: Incorrect argument type to variable 'wsrep_max_ws_rows' +SET @@global.wsrep_max_ws_rows=-1; +Warnings: +Warning 1292 Truncated incorrect wsrep_max_ws_rows value: '-1' +SELECT @global.wsrep_max_ws_rows; +@global.wsrep_max_ws_rows +NULL + +# restore the initial value +SET @@global.wsrep_max_ws_rows = @wsrep_max_ws_rows_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_max_ws_size_basic.result b/mysql-test/suite/sys_vars/r/wsrep_max_ws_size_basic.result index 292fd4e02d8..26d8d823a5c 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_max_ws_size_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_max_ws_size_basic.result @@ -1,17 +1,58 @@ -set @start_value = @@wsrep_max_ws_size; -set @@global.wsrep_max_ws_size=256000; -set @@global.wsrep_max_ws_size=0; +# +# wsrep_max_ws_size +# +# save the initial value +SET @wsrep_max_ws_size_global_saved = @@global.wsrep_max_ws_size; +# default +SELECT @@global.wsrep_max_ws_size; +@@global.wsrep_max_ws_size +1073741824 + +# scope +SELECT @@session.wsrep_max_ws_size; +ERROR HY000: Variable 'wsrep_max_ws_size' is a GLOBAL variable +SET @@global.wsrep_max_ws_size=1; +Warnings: +Warning 1292 Truncated incorrect wsrep_max_ws_size value: '1' +SELECT @@global.wsrep_max_ws_size; +@@global.wsrep_max_ws_size +1024 + +# valid values +SET @@global.wsrep_max_ws_size=1073741824; +SELECT @@global.wsrep_max_ws_size; +@@global.wsrep_max_ws_size +1073741824 +SET @@global.wsrep_max_ws_size=1073741825; +SELECT @@global.wsrep_max_ws_size; +@@global.wsrep_max_ws_size +1073741825 +SET @@global.wsrep_max_ws_size=0; Warnings: Warning 1292 Truncated incorrect wsrep_max_ws_size value: '0' -show warnings; -Level Code Message -Warning 1292 Truncated incorrect wsrep_max_ws_size value: '0' -set @@global.wsrep_max_ws_size=-1; -Warnings: -Warning 1292 Truncated incorrect wsrep_max_ws_size value: '-1' -show warnings; -Level Code Message -Warning 1292 Truncated incorrect wsrep_max_ws_size value: '-1' -SET @@global.wsrep_max_ws_size = r; +SELECT @@global.wsrep_max_ws_size; +@@global.wsrep_max_ws_size +1024 +SET @@global.wsrep_max_ws_size=default; +SELECT @global.wsrep_max_ws_size; +@global.wsrep_max_ws_size +NULL + +# invalid values +SET @@global.wsrep_max_ws_size=NULL; ERROR 42000: Incorrect argument type to variable 'wsrep_max_ws_size' -set @@global.wsrep_max_ws_size = @start_value; +SET @@global.wsrep_max_ws_size='junk'; +ERROR 42000: Incorrect argument type to variable 'wsrep_max_ws_size' +SELECT @global.wsrep_max_ws_size; +@global.wsrep_max_ws_size +NULL +SET @@global.wsrep_max_ws_size=-1; +Warnings: +Warning 1292 Truncated incorrect wsrep_max_ws_size value: '-1' +SELECT @global.wsrep_max_ws_size; +@global.wsrep_max_ws_size +NULL + +# restore the initial value +SET @@global.wsrep_max_ws_size = @wsrep_max_ws_size_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_mysql_replication_bundle_basic.result b/mysql-test/suite/sys_vars/r/wsrep_mysql_replication_bundle_basic.result index ad435a2c05f..1d69d800703 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_mysql_replication_bundle_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_mysql_replication_bundle_basic.result @@ -1,18 +1,52 @@ -set @start_value = @@wsrep_mysql_replication_bundle; -set @@global.wsrep_mysql_replication_bundle=0; -set @@global.wsrep_mysql_replication_bundle=1000; -set @@global.wsrep_mysql_replication_bundle=-1; -Warnings: -Warning 1292 Truncated incorrect wsrep_mysql_replication_bundle value: '-1' -show warnings; -Level Code Message -Warning 1292 Truncated incorrect wsrep_mysql_replication_bundle value: '-1' -set @@global.wsrep_mysql_replication_bundle=1001; -Warnings: -Warning 1292 Truncated incorrect wsrep_mysql_replication_bundle value: '1001' -show warnings; -Level Code Message -Warning 1292 Truncated incorrect wsrep_mysql_replication_bundle value: '1001' -SET @@global.wsrep_mysql_replication_bundle = r; +# +# wsrep_mysql_replication_bundle +# +# save the initial value +SET @wsrep_mysql_replication_bundle_global_saved = @@global.wsrep_mysql_replication_bundle; +# default +SELECT @@global.wsrep_mysql_replication_bundle; +@@global.wsrep_mysql_replication_bundle +0 + +# scope +SELECT @@session.wsrep_mysql_replication_bundle; +ERROR HY000: Variable 'wsrep_mysql_replication_bundle' is a GLOBAL variable +SELECT @@global.wsrep_mysql_replication_bundle; +@@global.wsrep_mysql_replication_bundle +0 + +# valid values +SET @@global.wsrep_mysql_replication_bundle=0; +SELECT @@global.wsrep_mysql_replication_bundle; +@@global.wsrep_mysql_replication_bundle +0 +SET @@global.wsrep_mysql_replication_bundle=1000; +SELECT @@global.wsrep_mysql_replication_bundle; +@@global.wsrep_mysql_replication_bundle +1000 +SET @@global.wsrep_mysql_replication_bundle=default; +SELECT @@global.wsrep_mysql_replication_bundle; +@@global.wsrep_mysql_replication_bundle +0 + +# invalid values +SET @@global.wsrep_mysql_replication_bundle=NULL; ERROR 42000: Incorrect argument type to variable 'wsrep_mysql_replication_bundle' -set @@global.wsrep_mysql_replication_bundle = @start_value; +SET @@global.wsrep_mysql_replication_bundle='junk'; +ERROR 42000: Incorrect argument type to variable 'wsrep_mysql_replication_bundle' +SET @@global.wsrep_mysql_replication_bundle=-1; +Warnings: +Warning 1292 Truncated incorrect wsrep_mysql_replication_bundle value: '-1' +SELECT @@global.wsrep_mysql_replication_bundle; +@@global.wsrep_mysql_replication_bundle +0 +SET @@global.wsrep_mysql_replication_bundle=1001; +Warnings: +Warning 1292 Truncated incorrect wsrep_mysql_replication_bundle value: '1001' +SELECT @@global.wsrep_mysql_replication_bundle; +@@global.wsrep_mysql_replication_bundle +1000 + +# restore the initial value +SET @@global.wsrep_mysql_replication_bundle = @wsrep_mysql_replication_bundle_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_node_address_basic.result b/mysql-test/suite/sys_vars/r/wsrep_node_address_basic.result index 96ae51cc70f..e9a93d2fcd6 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_node_address_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_node_address_basic.result @@ -1,45 +1,49 @@ -SELECT COUNT(@@GLOBAL.wsrep_node_address); -COUNT(@@GLOBAL.wsrep_node_address) -1 -1 Expected -SET @@GLOBAL.wsrep_node_address=1; -ERROR 42000: Incorrect argument type to variable 'wsrep_node_address' -Expected error 'Read only variable' -SELECT COUNT(@@GLOBAL.wsrep_node_address); -COUNT(@@GLOBAL.wsrep_node_address) -1 -1 Expected -SELECT @@GLOBAL.wsrep_node_address = VARIABLE_VALUE -FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES -WHERE VARIABLE_NAME='wsrep_node_address'; -@@GLOBAL.wsrep_node_address = VARIABLE_VALUE -1 -1 Expected -SELECT COUNT(@@GLOBAL.wsrep_node_address); -COUNT(@@GLOBAL.wsrep_node_address) -1 -1 Expected -SELECT COUNT(VARIABLE_VALUE) -FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES -WHERE VARIABLE_NAME='wsrep_node_address'; -COUNT(VARIABLE_VALUE) -1 -1 Expected -SELECT @@wsrep_node_address = @@GLOBAL.wsrep_node_address; -@@wsrep_node_address = @@GLOBAL.wsrep_node_address -1 -1 Expected -SELECT COUNT(@@wsrep_node_address); -COUNT(@@wsrep_node_address) -1 -1 Expected -SELECT COUNT(@@local.wsrep_node_address); +# +# wsrep_node_address +# +# save the initial value +SET @wsrep_node_address_global_saved = @@global.wsrep_node_address; +# default +SELECT @@global.wsrep_node_address; +@@global.wsrep_node_address + + +# scope +SELECT @@session.wsrep_node_address; ERROR HY000: Variable 'wsrep_node_address' is a GLOBAL variable -Expected error 'Variable is a GLOBAL variable' -SELECT COUNT(@@SESSION.wsrep_node_address); -ERROR HY000: Variable 'wsrep_node_address' is a GLOBAL variable -Expected error 'Variable is a GLOBAL variable' -SELECT COUNT(@@GLOBAL.wsrep_node_address); -COUNT(@@GLOBAL.wsrep_node_address) -1 -1 Expected +SELECT @@global.wsrep_node_address; +@@global.wsrep_node_address + + +# valid values +SET @@global.wsrep_node_address='127.0.0.1'; +SELECT @@global.wsrep_node_address; +@@global.wsrep_node_address +127.0.0.1 +SET @@global.wsrep_node_address=default; +SELECT @@global.wsrep_node_address; +@@global.wsrep_node_address + + +# invalid values +SET @@global.wsrep_node_address=NULL; +ERROR 42000: Variable 'wsrep_node_address' can't be set to the value of 'NULL' +SELECT @@global.wsrep_node_address; +@@global.wsrep_node_address + +SET @@global.wsrep_node_address=ON; +SELECT @@global.wsrep_node_address; +@@global.wsrep_node_address +ON +SET @@global.wsrep_node_address='OFF'; +SELECT @@global.wsrep_node_address; +@@global.wsrep_node_address +OFF +SET @@global.wsrep_node_address='junk'; +SELECT @@global.wsrep_node_address; +@@global.wsrep_node_address +junk + +# restore the initial value +SET @@global.wsrep_node_address = @wsrep_node_address_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_node_incoming_address_basic.result b/mysql-test/suite/sys_vars/r/wsrep_node_incoming_address_basic.result index 9ccf9706484..2340c61db28 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_node_incoming_address_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_node_incoming_address_basic.result @@ -1,45 +1,56 @@ -SELECT COUNT(@@GLOBAL.wsrep_node_incoming_address); -COUNT(@@GLOBAL.wsrep_node_incoming_address) -1 -1 Expected -SET @@GLOBAL.wsrep_node_incoming_address=1; -ERROR 42000: Incorrect argument type to variable 'wsrep_node_incoming_address' -Expected error 'Read only variable' -SELECT COUNT(@@GLOBAL.wsrep_node_incoming_address); -COUNT(@@GLOBAL.wsrep_node_incoming_address) -1 -1 Expected -SELECT @@GLOBAL.wsrep_node_incoming_address = VARIABLE_VALUE -FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES -WHERE VARIABLE_NAME='wsrep_node_incoming_address'; -@@GLOBAL.wsrep_node_incoming_address = VARIABLE_VALUE -1 -1 Expected -SELECT COUNT(@@GLOBAL.wsrep_node_incoming_address); -COUNT(@@GLOBAL.wsrep_node_incoming_address) -1 -1 Expected -SELECT COUNT(VARIABLE_VALUE) -FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES -WHERE VARIABLE_NAME='wsrep_node_incoming_address'; -COUNT(VARIABLE_VALUE) -1 -1 Expected -SELECT @@wsrep_node_incoming_address = @@GLOBAL.wsrep_node_incoming_address; -@@wsrep_node_incoming_address = @@GLOBAL.wsrep_node_incoming_address -1 -1 Expected -SELECT COUNT(@@wsrep_node_incoming_address); -COUNT(@@wsrep_node_incoming_address) -1 -1 Expected -SELECT COUNT(@@local.wsrep_node_incoming_address); +# +# wsrep_node_incoming_address +# +# save the initial value +SET @wsrep_node_incoming_address_global_saved = @@global.wsrep_node_incoming_address; +# default +SELECT @@global.wsrep_node_incoming_address; +@@global.wsrep_node_incoming_address +AUTO + +# scope +SELECT @@session.wsrep_node_incoming_address; ERROR HY000: Variable 'wsrep_node_incoming_address' is a GLOBAL variable -Expected error 'Variable is a GLOBAL variable' -SELECT COUNT(@@SESSION.wsrep_node_incoming_address); -ERROR HY000: Variable 'wsrep_node_incoming_address' is a GLOBAL variable -Expected error 'Variable is a GLOBAL variable' -SELECT COUNT(@@GLOBAL.wsrep_node_incoming_address); -COUNT(@@GLOBAL.wsrep_node_incoming_address) -1 -1 Expected +SELECT @@global.wsrep_node_incoming_address; +@@global.wsrep_node_incoming_address +AUTO + +# valid values +SET @@global.wsrep_node_incoming_address='127.0.0.1:4444'; +SELECT @@global.wsrep_node_incoming_address; +@@global.wsrep_node_incoming_address +127.0.0.1:4444 +SET @@global.wsrep_node_incoming_address='127.0.0.1'; +SELECT @@global.wsrep_node_incoming_address; +@@global.wsrep_node_incoming_address +127.0.0.1 +SET @@global.wsrep_node_incoming_address=AUTO; +SELECT @@global.wsrep_node_incoming_address; +@@global.wsrep_node_incoming_address +AUTO +SET @@global.wsrep_node_incoming_address=default; +SELECT @@global.wsrep_node_incoming_address; +@@global.wsrep_node_incoming_address +AUTO + +# invalid values +SET @@global.wsrep_node_incoming_address=ON; +SELECT @@global.wsrep_node_incoming_address; +@@global.wsrep_node_incoming_address +ON +SET @@global.wsrep_node_incoming_address='OFF'; +SELECT @@global.wsrep_node_incoming_address; +@@global.wsrep_node_incoming_address +OFF +SET @@global.wsrep_node_incoming_address=NULL; +SELECT @@global.wsrep_node_incoming_address; +@@global.wsrep_node_incoming_address +NULL +SET @@global.wsrep_node_incoming_address='junk'; +SELECT @@global.wsrep_node_incoming_address; +@@global.wsrep_node_incoming_address +junk + +# restore the initial value +SET @@global.wsrep_node_incoming_address = @wsrep_node_incoming_address_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_node_name_basic.result b/mysql-test/suite/sys_vars/r/wsrep_node_name_basic.result index f3c03570b7b..9657e6bf428 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_node_name_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_node_name_basic.result @@ -1,6 +1,48 @@ -set @start_value = @@wsrep_node_name; -set @@global.wsrep_node_name='test'; -set @@global.wsrep_node_name=NULL; -SET @@global.wsrep_node_name = 1; +# +# wsrep_node_name +# +call mtr.add_suppression("WSREP: Failed to get provider options"); +# save the initial value +SET @wsrep_node_name_global_saved = @@global.wsrep_node_name; +# default +SELECT @@global.wsrep_node_name; +@@global.wsrep_node_name + + +# scope +SELECT @@session.wsrep_node_name; +ERROR HY000: Variable 'wsrep_node_name' is a GLOBAL variable +SET @@global.wsrep_node_name='node_name'; +SELECT @@global.wsrep_node_name; +@@global.wsrep_node_name +node_name + +# valid values +SET @@global.wsrep_node_name='my_node'; +SELECT @@global.wsrep_node_name; +@@global.wsrep_node_name +my_node +SET @@global.wsrep_node_name='hyphenated-node-name'; +SELECT @@global.wsrep_node_name; +@@global.wsrep_node_name +hyphenated-node-name +SET @@global.wsrep_node_name=default; +SELECT @@global.wsrep_node_name; +@@global.wsrep_node_name + + +# invalid values +SET @@global.wsrep_node_name=NULL; +ERROR 42000: Variable 'wsrep_node_name' can't be set to the value of 'NULL' +SELECT @@global.wsrep_node_name; +@@global.wsrep_node_name + +SET @@global.wsrep_node_name=1; ERROR 42000: Incorrect argument type to variable 'wsrep_node_name' -set @@global.wsrep_node_name = @start_value; +SELECT @@global.wsrep_node_name; +@@global.wsrep_node_name + + +# restore the initial value +SET @@global.wsrep_node_name = @wsrep_node_name_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_notify_cmd_basic.result b/mysql-test/suite/sys_vars/r/wsrep_notify_cmd_basic.result index d1d68ea036b..056ff8c817b 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_notify_cmd_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_notify_cmd_basic.result @@ -1,6 +1,47 @@ -set @start_value = @@wsrep_notify_cmd; -set @@global.wsrep_notify_cmd='test'; -set @@global.wsrep_notify_cmd=NULL; -SET @@global.wsrep_notify_cmd = 1; +# +# wsrep_notify_cmd +# +call mtr.add_suppression("WSREP: Failed to get provider options"); +# save the initial value +SET @wsrep_notify_cmd_global_saved = @@global.wsrep_notify_cmd; +# default +SELECT @@global.wsrep_notify_cmd; +@@global.wsrep_notify_cmd + + +# scope +SELECT @@session.wsrep_notify_cmd; +ERROR HY000: Variable 'wsrep_notify_cmd' is a GLOBAL variable +SET @@global.wsrep_notify_cmd='notify_cmd'; +SELECT @@global.wsrep_notify_cmd; +@@global.wsrep_notify_cmd +notify_cmd + +# valid values +SET @@global.wsrep_notify_cmd='command'; +SELECT @@global.wsrep_notify_cmd; +@@global.wsrep_notify_cmd +command +SET @@global.wsrep_notify_cmd='hyphenated-command'; +SELECT @@global.wsrep_notify_cmd; +@@global.wsrep_notify_cmd +hyphenated-command +SET @@global.wsrep_notify_cmd=default; +SELECT @@global.wsrep_notify_cmd; +@@global.wsrep_notify_cmd + +SET @@global.wsrep_notify_cmd=NULL; +SELECT @@global.wsrep_notify_cmd; +@@global.wsrep_notify_cmd +NULL + +# invalid values +SET @@global.wsrep_notify_cmd=1; ERROR 42000: Incorrect argument type to variable 'wsrep_notify_cmd' -set @@global.wsrep_notify_cmd = @start_value; +SELECT @@global.wsrep_notify_cmd; +@@global.wsrep_notify_cmd +NULL + +# restore the initial value +SET @@global.wsrep_notify_cmd = @wsrep_notify_cmd_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_on_basic.result b/mysql-test/suite/sys_vars/r/wsrep_on_basic.result index 629c0e866cb..735e2d77180 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_on_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_on_basic.result @@ -1,8 +1,50 @@ -set @start_value = @@wsrep_on; -set @@global.wsrep_on=ON; -set @@global.wsrep_on=OFF; -set @@global.wsrep_on=1; -set @@global.wsrep_on=0; -SET @@global.wsrep_on = -1; -ERROR 42000: Variable 'wsrep_on' can't be set to the value of '-1' -set @@global.wsrep_on = @start_value; +# +# wsrep_on +# +# save the initial values +SET @wsrep_on_global_saved = @@global.wsrep_on; +SET @wsrep_on_session_saved = @@session.wsrep_on; +# default +SELECT @@global.wsrep_on; +@@global.wsrep_on +0 +SELECT @@session.wsrep_on; +@@session.wsrep_on +0 + +# scope and valid values +SET @@global.wsrep_on=OFF; +SELECT @@global.wsrep_on; +@@global.wsrep_on +0 +SET @@global.wsrep_on=ON; +SELECT @@global.wsrep_on; +@@global.wsrep_on +1 +SET @@session.wsrep_on=OFF; +SELECT @@session.wsrep_on; +@@session.wsrep_on +0 +SET @@session.wsrep_on=ON; +SELECT @@session.wsrep_on; +@@session.wsrep_on +1 +SET @@session.wsrep_on=default; +SELECT @@session.wsrep_on; +@@session.wsrep_on +1 + +# invalid values +SET @@global.wsrep_on=NULL; +ERROR 42000: Variable 'wsrep_on' can't be set to the value of 'NULL' +SET @@global.wsrep_on='junk'; +ERROR 42000: Variable 'wsrep_on' can't be set to the value of 'junk' +SET @@session.wsrep_on=NULL; +ERROR 42000: Variable 'wsrep_on' can't be set to the value of 'NULL' +SET @@session.wsrep_on='junk'; +ERROR 42000: Variable 'wsrep_on' can't be set to the value of 'junk' + +# restore the initial values +SET @@global.wsrep_on = @wsrep_on_global_saved; +SET @@session.wsrep_on = @wsrep_on_session_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_osu_method_basic.result b/mysql-test/suite/sys_vars/r/wsrep_osu_method_basic.result index 84c828e5965..95b59e62adc 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_osu_method_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_osu_method_basic.result @@ -1,12 +1,60 @@ -set @start_value = @@wsrep_osu_method; -set @@global.wsrep_osu_method='TOI'; -set @@global.wsrep_osu_method='RSU'; -set @@global.wsrep_osu_method=TOI; -set @@global.wsrep_osu_method=RSU; -set @@global.wsrep_osu_method=TSU; -ERROR 42000: Variable 'wsrep_OSU_method' can't be set to the value of 'TSU' -set @@global.wsrep_osu_method='TSU'; -ERROR 42000: Variable 'wsrep_OSU_method' can't be set to the value of 'TSU' -SET @@global.wsrep_on = -1; -ERROR 42000: Variable 'wsrep_on' can't be set to the value of '-1' -set @@global.wsrep_osu_method = @start_value; +# +# wsrep_osu_method +# +# save the initial value +SET @wsrep_osu_method_global_saved = @@global.wsrep_osu_method; +# default +SELECT @@global.wsrep_osu_method; +@@global.wsrep_osu_method +TOI + +# scope +SELECT @@session.wsrep_osu_method; +ERROR HY000: Variable 'wsrep_OSU_method' is a GLOBAL variable +SET @@global.wsrep_osu_method=TOI; +SELECT @@global.wsrep_osu_method; +@@global.wsrep_osu_method +TOI + +# valid values +SET @@global.wsrep_osu_method=TOI; +SELECT @@global.wsrep_osu_method; +@@global.wsrep_osu_method +TOI +SET @@global.wsrep_osu_method=RSU; +SELECT @@global.wsrep_osu_method; +@@global.wsrep_osu_method +RSU +SET @@global.wsrep_osu_method="RSU"; +SELECT @@global.wsrep_osu_method; +@@global.wsrep_osu_method +RSU +SET @@global.wsrep_osu_method=default; +SELECT @@global.wsrep_osu_method; +@@global.wsrep_osu_method +TOI +SET @@global.wsrep_osu_method=1; +SELECT @@global.wsrep_osu_method; +@@global.wsrep_osu_method +RSU + +# invalid values +SET @@global.wsrep_osu_method=4; +ERROR 42000: Variable 'wsrep_OSU_method' can't be set to the value of '4' +SELECT @@global.wsrep_osu_method; +@@global.wsrep_osu_method +RSU +SET @@global.wsrep_osu_method=NULL; +ERROR 42000: Variable 'wsrep_OSU_method' can't be set to the value of 'NULL' +SELECT @@global.wsrep_osu_method; +@@global.wsrep_osu_method +RSU +SET @@global.wsrep_osu_method='junk'; +ERROR 42000: Variable 'wsrep_OSU_method' can't be set to the value of 'junk' +SELECT @@global.wsrep_osu_method; +@@global.wsrep_osu_method +RSU + +# restore the initial value +SET @@global.wsrep_osu_method = @wsrep_osu_method_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_provider_basic.result b/mysql-test/suite/sys_vars/r/wsrep_provider_basic.result index 2de1e84e6c0..3e4ac8ca883 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_provider_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_provider_basic.result @@ -1,4 +1,40 @@ -SELECT COUNT(@@GLOBAL.wsrep_provider); -COUNT(@@GLOBAL.wsrep_provider) -1 -1 Expected +# +# wsrep_provider +# +# save the initial value +SET @wsrep_provider_global_saved = @@global.wsrep_provider; +# default +SELECT @@global.wsrep_provider; +@@global.wsrep_provider +none + +# scope +SELECT @@session.wsrep_provider; +ERROR HY000: Variable 'wsrep_provider' is a GLOBAL variable +SELECT @@global.wsrep_provider; +@@global.wsrep_provider +none + +# valid values +SET @@global.wsrep_provider=default; +SELECT @@global.wsrep_provider; +@@global.wsrep_provider +none + +# invalid values +SET @@global.wsrep_provider='/invalid/libgalera_smm.so'; +ERROR 42000: Variable 'wsrep_provider' can't be set to the value of '/invalid/libgalera_smm.so' +SET @@global.wsrep_provider=NULL; +ERROR 42000: Variable 'wsrep_provider' can't be set to the value of 'NULL' +SELECT @@global.wsrep_provider; +@@global.wsrep_provider +none +SET @@global.wsrep_provider=1; +ERROR 42000: Incorrect argument type to variable 'wsrep_provider' +SELECT @@global.wsrep_provider; +@@global.wsrep_provider +none + +# restore the initial value +SET @@global.wsrep_provider = @wsrep_provider_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_provider_options_basic.result b/mysql-test/suite/sys_vars/r/wsrep_provider_options_basic.result index 28b55e782bc..ed6b125e064 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_provider_options_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_provider_options_basic.result @@ -1,4 +1,48 @@ -SELECT COUNT(@@GLOBAL.wsrep_provider_options); -COUNT(@@GLOBAL.wsrep_provider_options) -1 -1 Expected +# +# wsrep_provider_options +# +call mtr.add_suppression("WSREP: Failed to get provider options"); +# save the initial value +SET @wsrep_provider_options_global_saved = @@global.wsrep_provider_options; +# default +SELECT @@global.wsrep_provider_options; +@@global.wsrep_provider_options + + +# scope +SELECT @@session.wsrep_provider_options; +ERROR HY000: Variable 'wsrep_provider_options' is a GLOBAL variable +SET @@global.wsrep_provider_options='option1'; +SELECT @@global.wsrep_provider_options; +@@global.wsrep_provider_options +option1 + +# valid values +SET @@global.wsrep_provider_options='name1=value1;name2=value2'; +SELECT @@global.wsrep_provider_options; +@@global.wsrep_provider_options +name1=value1;name2=value2 +SET @@global.wsrep_provider_options='hyphenated-name:value'; +SELECT @@global.wsrep_provider_options; +@@global.wsrep_provider_options +hyphenated-name:value +SET @@global.wsrep_provider_options=default; +SELECT @@global.wsrep_provider_options; +@@global.wsrep_provider_options + + +# invalid values +SET @@global.wsrep_provider_options=1; +ERROR 42000: Incorrect argument type to variable 'wsrep_provider_options' +SELECT @@global.wsrep_provider_options; +@@global.wsrep_provider_options + +SET @@global.wsrep_provider_options=NULL; +ERROR HY000: Incorrect arguments to SET +SELECT @@global.wsrep_provider_options; +@@global.wsrep_provider_options +NULL + +# restore the initial value +SET @@global.wsrep_provider_options = @wsrep_provider_options_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_recover_basic.result b/mysql-test/suite/sys_vars/r/wsrep_recover_basic.result index b9f7e41047e..b26c1121a4c 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_recover_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_recover_basic.result @@ -1,49 +1,22 @@ -SELECT COUNT(@@GLOBAL.wsrep_recover); -COUNT(@@GLOBAL.wsrep_recover) -1 -1 Expected -set @@global.wsrep_recover=ON; -ERROR HY000: Variable 'wsrep_recover' is a read only variable -Expected error 'Readonly variable' -set @@global.wsrep_recover=OFF; -ERROR HY000: Variable 'wsrep_recover' is a read only variable -Expected error 'Readonly variable' -SELECT @@GLOBAL.wsrep_recover = VARIABLE_VALUE -FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES -WHERE VARIABLE_NAME='wsrep_recover'; -@@GLOBAL.wsrep_recover = VARIABLE_VALUE -1 -Warnings: -Warning 1292 Truncated incorrect DOUBLE value: 'OFF' -1 Expected -SELECT COUNT(@@GLOBAL.wsrep_recover); -COUNT(@@GLOBAL.wsrep_recover) -1 -1 Expected -SELECT COUNT(VARIABLE_VALUE) -FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES -WHERE VARIABLE_NAME='wsrep_recover'; -COUNT(VARIABLE_VALUE) -1 -1 Expected -SELECT @@wsrep_recover = @@GLOBAL.wsrep_recover; -@@wsrep_recover = @@GLOBAL.wsrep_recover -1 -1 Expected -SELECT COUNT(@@wsrep_recover); -COUNT(@@wsrep_recover) -1 -1 Expected -SELECT COUNT(@@local.wsrep_recover); +# +# wsrep_recover +# +# default +SELECT @@global.wsrep_recover; +@@global.wsrep_recover +0 +SELECT @@session.wsrep_recover; ERROR HY000: Variable 'wsrep_recover' is a GLOBAL variable -Expected error 'Variable is a GLOBAL variable' -SELECT COUNT(@@SESSION.wsrep_recover); -ERROR HY000: Variable 'wsrep_recover' is a GLOBAL variable -Expected error 'Variable is a GLOBAL variable' -SELECT COUNT(@@GLOBAL.wsrep_recover); -COUNT(@@GLOBAL.wsrep_recover) -1 -1 Expected -SELECT wsrep_recover = @@SESSION.wsrep_recover; -ERROR 42S22: Unknown column 'wsrep_recover' in 'field list' -Expected error 'Readonly variable' + +# scope and valid values +SET @@global.wsrep_recover=OFF; +ERROR HY000: Variable 'wsrep_recover' is a read only variable +SET @@global.wsrep_recover=ON; +ERROR HY000: Variable 'wsrep_recover' is a read only variable + +# invalid values +SET @@global.wsrep_recover=NULL; +ERROR HY000: Variable 'wsrep_recover' is a read only variable +SET @@global.wsrep_recover='junk'; +ERROR HY000: Variable 'wsrep_recover' is a read only variable +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_replicate_myisam_basic.result b/mysql-test/suite/sys_vars/r/wsrep_replicate_myisam_basic.result index 644258206a5..3625f29aa0f 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_replicate_myisam_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_replicate_myisam_basic.result @@ -1,8 +1,31 @@ -set @start_value = @@wsrep_replicate_myisam; -set @@global.wsrep_replicate_myisam=ON; -set @@global.wsrep_replicate_myisam=OFF; -set @@global.wsrep_replicate_myisam=1; -set @@global.wsrep_replicate_myisam=0; -SET @@global.wsrep_replicate_myisam = -1; -ERROR 42000: Variable 'wsrep_replicate_myisam' can't be set to the value of '-1' -set @@global.wsrep_replicate_myisam = @start_value; +# +# wsrep_replicate_myisam +# +# save the initial value +SET @wsrep_replicate_myisam_global_saved = @@global.wsrep_replicate_myisam; +# default +SELECT @@global.wsrep_replicate_myisam; +@@global.wsrep_replicate_myisam +0 +SELECT @@session.wsrep_replicate_myisam; +ERROR HY000: Variable 'wsrep_replicate_myisam' is a GLOBAL variable + +# scope and valid values +SET @@global.wsrep_replicate_myisam=OFF; +SELECT @@global.wsrep_replicate_myisam; +@@global.wsrep_replicate_myisam +0 +SET @@global.wsrep_replicate_myisam=ON; +SELECT @@global.wsrep_replicate_myisam; +@@global.wsrep_replicate_myisam +1 + +# invalid values +SET @@global.wsrep_replicate_myisam=NULL; +ERROR 42000: Variable 'wsrep_replicate_myisam' can't be set to the value of 'NULL' +SET @@global.wsrep_replicate_myisam='junk'; +ERROR 42000: Variable 'wsrep_replicate_myisam' can't be set to the value of 'junk' + +# restore the initial value +SET @@global.wsrep_replicate_myisam = @wsrep_replicate_myisam_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_restart_slave_basic.result b/mysql-test/suite/sys_vars/r/wsrep_restart_slave_basic.result index 811981b6a37..0ecdf915992 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_restart_slave_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_restart_slave_basic.result @@ -1,8 +1,31 @@ -set @start_value = @@wsrep_restart_slave; -set @@global.wsrep_restart_slave=ON; -set @@global.wsrep_restart_slave=OFF; -set @@global.wsrep_restart_slave=1; -set @@global.wsrep_restart_slave=0; -SET @@global.wsrep_restart_slave = -1; -ERROR 42000: Variable 'wsrep_restart_slave' can't be set to the value of '-1' -set @@global.wsrep_restart_slave = @start_value; +# +# wsrep_restart_slave +# +# save the initial value +SET @wsrep_restart_slave_global_saved = @@global.wsrep_restart_slave; +# default +SELECT @@global.wsrep_restart_slave; +@@global.wsrep_restart_slave +0 +SELECT @@session.wsrep_restart_slave; +ERROR HY000: Variable 'wsrep_restart_slave' is a GLOBAL variable + +# scope and valid values +SET @@global.wsrep_restart_slave=OFF; +SELECT @@global.wsrep_restart_slave; +@@global.wsrep_restart_slave +0 +SET @@global.wsrep_restart_slave=ON; +SELECT @@global.wsrep_restart_slave; +@@global.wsrep_restart_slave +1 + +# invalid values +SET @@global.wsrep_restart_slave=NULL; +ERROR 42000: Variable 'wsrep_restart_slave' can't be set to the value of 'NULL' +SET @@global.wsrep_restart_slave='junk'; +ERROR 42000: Variable 'wsrep_restart_slave' can't be set to the value of 'junk' + +# restore the initial value +SET @@global.wsrep_restart_slave = @wsrep_restart_slave_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_retry_autocommit_basic.result b/mysql-test/suite/sys_vars/r/wsrep_retry_autocommit_basic.result index 811981b6a37..d848dadd24d 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_retry_autocommit_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_retry_autocommit_basic.result @@ -1,8 +1,63 @@ -set @start_value = @@wsrep_restart_slave; -set @@global.wsrep_restart_slave=ON; -set @@global.wsrep_restart_slave=OFF; -set @@global.wsrep_restart_slave=1; -set @@global.wsrep_restart_slave=0; -SET @@global.wsrep_restart_slave = -1; -ERROR 42000: Variable 'wsrep_restart_slave' can't be set to the value of '-1' -set @@global.wsrep_restart_slave = @start_value; +# +# wsrep_retry_autocommit +# +# save the initial values +SET @wsrep_retry_autocommit_global_saved = @@global.wsrep_retry_autocommit; +SET @wsrep_retry_autocommit_session_saved = @@session.wsrep_retry_autocommit; +# default +SELECT @@global.wsrep_retry_autocommit; +@@global.wsrep_retry_autocommit +1 + +# scope +SET @@session.wsrep_retry_autocommit=1; +SELECT @@session.wsrep_retry_autocommit; +@@session.wsrep_retry_autocommit +1 +SET @@global.wsrep_retry_autocommit=1; +SELECT @@global.wsrep_retry_autocommit; +@@global.wsrep_retry_autocommit +1 + +# valid values +SET @@global.wsrep_retry_autocommit=10; +SELECT @@global.wsrep_retry_autocommit; +@@global.wsrep_retry_autocommit +10 +SET @@global.wsrep_retry_autocommit=0; +SELECT @@global.wsrep_retry_autocommit; +@@global.wsrep_retry_autocommit +0 +SET @@global.wsrep_retry_autocommit=default; +SELECT @global.wsrep_retry_autocommit; +@global.wsrep_retry_autocommit +NULL +SET @@session.wsrep_retry_autocommit=10; +SELECT @@session.wsrep_retry_autocommit; +@@session.wsrep_retry_autocommit +10 +SET @@session.wsrep_retry_autocommit=0; +SELECT @@session.wsrep_retry_autocommit; +@@session.wsrep_retry_autocommit +0 +SET @@session.wsrep_retry_autocommit=default; +SELECT @session.wsrep_retry_autocommit; +@session.wsrep_retry_autocommit +NULL + +# invalid values +SET @@global.wsrep_retry_autocommit=NULL; +ERROR 42000: Incorrect argument type to variable 'wsrep_retry_autocommit' +SET @@global.wsrep_retry_autocommit='junk'; +ERROR 42000: Incorrect argument type to variable 'wsrep_retry_autocommit' +SET @@global.wsrep_retry_autocommit=-1; +Warnings: +Warning 1292 Truncated incorrect wsrep_retry_autocommit value: '-1' +SELECT @global.wsrep_retry_autocommit; +@global.wsrep_retry_autocommit +NULL + +# restore the initial value +SET @@global.wsrep_retry_autocommit = @wsrep_retry_autocommit_global_saved; +SET @@session.wsrep_retry_autocommit = @wsrep_retry_autocommit_session_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_slave_threads_basic.result b/mysql-test/suite/sys_vars/r/wsrep_slave_threads_basic.result index f8105660c6e..62be5a42416 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_slave_threads_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_slave_threads_basic.result @@ -1,20 +1,49 @@ -set @start_value = @@wsrep_slave_threads; -set @@global.wsrep_slave_threads=1; -set @@global.wsrep_slave_threads=4; -show warnings; -Level Code Message -set @@global.wsrep_slave_threads=0; +# +# wsrep_slave_threads +# +# save the initial value +SET @wsrep_slave_threads_global_saved = @@global.wsrep_slave_threads; +# default +SELECT @@global.wsrep_slave_threads; +@@global.wsrep_slave_threads +1 + +# scope +SELECT @@session.wsrep_slave_threads; +ERROR HY000: Variable 'wsrep_slave_threads' is a GLOBAL variable +SET @@global.wsrep_slave_threads=1; +SELECT @@global.wsrep_slave_threads; +@@global.wsrep_slave_threads +1 + +# valid values +SET @@global.wsrep_slave_threads=10; +SELECT @@global.wsrep_slave_threads; +@@global.wsrep_slave_threads +10 +SET @@global.wsrep_slave_threads=0; Warnings: Warning 1292 Truncated incorrect wsrep_slave_threads value: '0' -show warnings; -Level Code Message -Warning 1292 Truncated incorrect wsrep_slave_threads value: '0' -set @@global.wsrep_slave_threads=-1; -Warnings: -Warning 1292 Truncated incorrect wsrep_slave_threads value: '-1' -show warnings; -Level Code Message -Warning 1292 Truncated incorrect wsrep_slave_threads value: '-1' -SET @@global.wsrep_slave_threads = r; +SELECT @@global.wsrep_slave_threads; +@@global.wsrep_slave_threads +1 +SET @@global.wsrep_slave_threads=default; +SELECT @global.wsrep_slave_threads; +@global.wsrep_slave_threads +NULL + +# invalid values +SET @@global.wsrep_slave_threads=NULL; ERROR 42000: Incorrect argument type to variable 'wsrep_slave_threads' -set @@global.wsrep_slave_threads = @start_value; +SET @@global.wsrep_slave_threads='junk'; +ERROR 42000: Incorrect argument type to variable 'wsrep_slave_threads' +SET @@global.wsrep_slave_threads=-1; +Warnings: +Warning 1292 Truncated incorrect wsrep_slave_threads value: '-1' +SELECT @global.wsrep_slave_threads; +@global.wsrep_slave_threads +NULL + +# restore the initial value +SET @@global.wsrep_slave_threads = @wsrep_slave_threads_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_sst_auth_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sst_auth_basic.result index a8a31dbea61..e6b532c6bba 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_sst_auth_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_sst_auth_basic.result @@ -1,3 +1,52 @@ -SELECT COUNT(@@wsrep_sst_auth); -COUNT(@@wsrep_sst_auth) -0 +# +# wsrep_sst_auth +# +# save the initial value +SET @wsrep_sst_auth_global_saved = @@global.wsrep_sst_auth; +# default +SELECT @@global.wsrep_sst_auth; +@@global.wsrep_sst_auth +NULL + +# scope +SELECT @@session.wsrep_sst_auth; +ERROR HY000: Variable 'wsrep_sst_auth' is a GLOBAL variable +SET @@global.wsrep_sst_auth='user:pass'; +SELECT @@global.wsrep_sst_auth; +@@global.wsrep_sst_auth +******** + +# valid values +SET @@global.wsrep_sst_auth=user; +SELECT @@global.wsrep_sst_auth; +@@global.wsrep_sst_auth +******** +SET @@global.wsrep_sst_auth='user:1234'; +SELECT @@global.wsrep_sst_auth; +@@global.wsrep_sst_auth +******** +SET @@global.wsrep_sst_auth='hyphenated-user-name:'; +SELECT @@global.wsrep_sst_auth; +@@global.wsrep_sst_auth +******** +SET @@global.wsrep_sst_auth=default; +SELECT @@global.wsrep_sst_auth; +@@global.wsrep_sst_auth +NULL +SET @@global.wsrep_sst_auth=NULL; +SELECT @@global.wsrep_sst_auth; +@@global.wsrep_sst_auth +NULL + +# invalid values +SET @@global.wsrep_sst_auth=1; +ERROR 42000: Incorrect argument type to variable 'wsrep_sst_auth' +SELECT @@global.wsrep_sst_auth; +@@global.wsrep_sst_auth +NULL +SET @@global.wsrep_sst_auth=user:pass; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ':pass' at line 1 + +# restore the initial value +SET @@global.wsrep_sst_auth = @wsrep_sst_auth_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_sst_donor_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sst_donor_basic.result index fc359690275..3d4fc24df7f 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_sst_donor_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_sst_donor_basic.result @@ -1,10 +1,50 @@ -SELECT COUNT(@@wsrep_sst_donor); -COUNT(@@wsrep_sst_donor) -1 -set @start_value = @@wsrep_sst_donor; -set @@global.wsrep_sst_donor='foo'; -set @@global.wsrep_sst_donor=NULL; -set @@global.wsrep_sst_donor=r; -set @@global.wsrep_sst_donor=1; +# +# wsrep_sst_donor +# +# save the initial value +SET @wsrep_sst_donor_global_saved = @@global.wsrep_sst_donor; +# default +SELECT @@global.wsrep_sst_donor; +@@global.wsrep_sst_donor + + +# scope +SELECT @@session.wsrep_sst_donor; +ERROR HY000: Variable 'wsrep_sst_donor' is a GLOBAL variable +SET @@global.wsrep_sst_donor=rsync; +SELECT @@global.wsrep_sst_donor; +@@global.wsrep_sst_donor +rsync + +# valid values +SET @@global.wsrep_sst_donor=node1; +SELECT @@global.wsrep_sst_donor; +@@global.wsrep_sst_donor +node1 +SET @@global.wsrep_sst_donor='node1,node2'; +SELECT @@global.wsrep_sst_donor; +@@global.wsrep_sst_donor +node1,node2 +SET @@global.wsrep_sst_donor='hyphenated-donor-name'; +SELECT @@global.wsrep_sst_donor; +@@global.wsrep_sst_donor +hyphenated-donor-name +SET @@global.wsrep_sst_donor=default; +SELECT @@global.wsrep_sst_donor; +@@global.wsrep_sst_donor + +SET @@global.wsrep_sst_donor=NULL; +SELECT @@global.wsrep_sst_donor; +@@global.wsrep_sst_donor +NULL + +# invalid values +SET @@global.wsrep_sst_donor=1; ERROR 42000: Incorrect argument type to variable 'wsrep_sst_donor' -set @@global.wsrep_sst_donor = @start_value; +SELECT @@global.wsrep_sst_donor; +@@global.wsrep_sst_donor +NULL + +# restore the initial value +SET @@global.wsrep_sst_donor = @wsrep_sst_donor_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_sst_donor_rejects_queries_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sst_donor_rejects_queries_basic.result index 55aa56f27ed..c9f95beec0a 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_sst_donor_rejects_queries_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_sst_donor_rejects_queries_basic.result @@ -1,8 +1,45 @@ -set @start_value = @@wsrep_sst_donor_rejects_queries; -set @@global.wsrep_sst_donor_rejects_queries=ON; -set @@global.wsrep_sst_donor_rejects_queries=OFF; -set @@global.wsrep_sst_donor_rejects_queries=1; -set @@global.wsrep_sst_donor_rejects_queries=0; -SET @@global.wsrep_sst_donor_rejects_queries = -1; -ERROR 42000: Variable 'wsrep_sst_donor_rejects_queries' can't be set to the value of '-1' -set @@global.wsrep_sst_donor_rejects_queries = @start_value; +# +# wsrep_sst_donor_rejects_queries +# +# save the initial value +SET @wsrep_sst_donor_rejects_queries_global_saved = @@global.wsrep_sst_donor_rejects_queries; +# default +SELECT @@global.wsrep_sst_donor_rejects_queries; +@@global.wsrep_sst_donor_rejects_queries +0 + +# scope +SELECT @@session.wsrep_sst_donor_rejects_queries; +ERROR HY000: Variable 'wsrep_sst_donor_rejects_queries' is a GLOBAL variable +SET @@global.wsrep_sst_donor_rejects_queries=OFF; +SELECT @@global.wsrep_sst_donor_rejects_queries; +@@global.wsrep_sst_donor_rejects_queries +0 +SET @@global.wsrep_sst_donor_rejects_queries=ON; +SELECT @@global.wsrep_sst_donor_rejects_queries; +@@global.wsrep_sst_donor_rejects_queries +1 + +# valid values +SET @@global.wsrep_sst_donor_rejects_queries='OFF'; +SELECT @@global.wsrep_sst_donor_rejects_queries; +@@global.wsrep_sst_donor_rejects_queries +0 +SET @@global.wsrep_sst_donor_rejects_queries=ON; +SELECT @@global.wsrep_sst_donor_rejects_queries; +@@global.wsrep_sst_donor_rejects_queries +1 +SET @@global.wsrep_sst_donor_rejects_queries=default; +SELECT @@global.wsrep_sst_donor_rejects_queries; +@@global.wsrep_sst_donor_rejects_queries +0 + +# invalid values +SET @@global.wsrep_sst_donor_rejects_queries=NULL; +ERROR 42000: Variable 'wsrep_sst_donor_rejects_queries' can't be set to the value of 'NULL' +SET @@global.wsrep_sst_donor_rejects_queries='junk'; +ERROR 42000: Variable 'wsrep_sst_donor_rejects_queries' can't be set to the value of 'junk' + +# restore the initial value +SET @@global.wsrep_sst_donor_rejects_queries = @wsrep_sst_donor_rejects_queries_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_sst_method_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sst_method_basic.result index 682a5683026..cbdac640c36 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_sst_method_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_sst_method_basic.result @@ -1,12 +1,54 @@ -set @start_value = @@wsrep_sst_method; -set @@global.wsrep_sst_method='xtrabackup'; -set @@global.wsrep_sst_method='xtrabackup-v2'; -set @@global.wsrep_sst_method='rsync'; -set @@global.wsrep_sst_method='mysqldump'; -set @@global.wsrep_sst_method='myscript'; -set @@global.wsrep_sst_method='skip'; -set @@global.wsrep_sst_method=NULL; +# +# wsrep_sst_method +# +# save the initial value +SET @wsrep_sst_method_global_saved = @@global.wsrep_sst_method; +# default +SELECT @@global.wsrep_sst_method; +@@global.wsrep_sst_method +rsync + +# scope +SELECT @@session.wsrep_sst_method; +ERROR HY000: Variable 'wsrep_sst_method' is a GLOBAL variable +SET @@global.wsrep_sst_method=rsync; +SELECT @@global.wsrep_sst_method; +@@global.wsrep_sst_method +rsync + +# valid values +SET @@global.wsrep_sst_method=rsync; +SELECT @@global.wsrep_sst_method; +@@global.wsrep_sst_method +rsync +SET @@global.wsrep_sst_method=mysqldump; +SELECT @@global.wsrep_sst_method; +@@global.wsrep_sst_method +mysqldump +SET @@global.wsrep_sst_method=xtrabackup; +SELECT @@global.wsrep_sst_method; +@@global.wsrep_sst_method +xtrabackup +SET @@global.wsrep_sst_method="xtrabackup-v2"; +SELECT @@global.wsrep_sst_method; +@@global.wsrep_sst_method +xtrabackup-v2 +SET @@global.wsrep_sst_method=default; +SELECT @@global.wsrep_sst_method; +@@global.wsrep_sst_method +rsync +SET @@global.wsrep_sst_method='junk'; +SELECT @@global.wsrep_sst_method; +@@global.wsrep_sst_method +junk + +# invalid values +SET @@global.wsrep_sst_method=NULL; ERROR 42000: Variable 'wsrep_sst_method' can't be set to the value of 'NULL' -SET @@global.wsrep_sst_method = -1; -ERROR 42000: Incorrect argument type to variable 'wsrep_sst_method' -set @@global.wsrep_sst_method = @start_value; +SELECT @@global.wsrep_sst_method; +@@global.wsrep_sst_method +junk + +# restore the initial value +SET @@global.wsrep_sst_method = @wsrep_sst_method_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_sst_receive_address_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sst_receive_address_basic.result index a23b7efafa8..6db52eb8150 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_sst_receive_address_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_sst_receive_address_basic.result @@ -1,8 +1,64 @@ -set @start_value = @@wsrep_sst_receive_address; -set @@global.wsrep_sst_receive_address='128.0.2.1'; -set @@global.wsrep_sst_receive_address=AUTO; -set @@global.wsrep_sst_receive_address='AUTO'; -set @@global.wsrep_sst_receive_address=NULL; -SET @@global.wsrep_sst_receive_address = -1; -ERROR 42000: Incorrect argument type to variable 'wsrep_sst_receive_address' -set @@global.wsrep_sst_receive_address = @start_value; +# +# wsrep_sst_receive_address +# +# save the initial value +SET @wsrep_sst_receive_address_global_saved = @@global.wsrep_sst_receive_address; +# default +SELECT @@global.wsrep_sst_receive_address; +@@global.wsrep_sst_receive_address +AUTO + +# scope +SELECT @@session.wsrep_sst_receive_address; +ERROR HY000: Variable 'wsrep_sst_receive_address' is a GLOBAL variable +SELECT @@global.wsrep_sst_receive_address; +@@global.wsrep_sst_receive_address +AUTO + +# valid values +SET @@global.wsrep_sst_receive_address=AUTO; +SELECT @@global.wsrep_sst_receive_address; +@@global.wsrep_sst_receive_address +AUTO +SET @@global.wsrep_sst_receive_address=default; +SELECT @@global.wsrep_sst_receive_address; +@@global.wsrep_sst_receive_address +AUTO +SET @@global.wsrep_sst_receive_address='192.168.2.254'; +SELECT @@global.wsrep_sst_receive_address; +@@global.wsrep_sst_receive_address +192.168.2.254 + +# invalid values +SET @@global.wsrep_sst_receive_address='127.0.0.1:4444'; +ERROR 42000: Variable 'wsrep_sst_receive_address' can't be set to the value of '127.0.0.1:4444' +SET @@global.wsrep_sst_receive_address='127.0.0.1'; +ERROR 42000: Variable 'wsrep_sst_receive_address' can't be set to the value of '127.0.0.1' +SELECT @@global.wsrep_sst_receive_address; +@@global.wsrep_sst_receive_address +192.168.2.254 +SET @@global.wsrep_sst_receive_address=NULL; +ERROR 42000: Variable 'wsrep_sst_receive_address' can't be set to the value of 'NULL' +SELECT @@global.wsrep_sst_receive_address; +@@global.wsrep_sst_receive_address +192.168.2.254 +SET @@global.wsrep_sst_receive_address='OFF'; +SELECT @@global.wsrep_sst_receive_address; +@@global.wsrep_sst_receive_address +OFF +SET @@global.wsrep_sst_receive_address=ON; +SELECT @@global.wsrep_sst_receive_address; +@@global.wsrep_sst_receive_address +ON +SET @@global.wsrep_sst_receive_address=''; +SELECT @@global.wsrep_sst_receive_address; +@@global.wsrep_sst_receive_address + +SET @@global.wsrep_sst_receive_address='junk'; +SELECT @@global.wsrep_sst_receive_address; +@@global.wsrep_sst_receive_address +junk + +# restore the initial value +SET @@global.wsrep_sst_receive_address = @wsrep_sst_receive_address_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/r/wsrep_start_position_basic.result b/mysql-test/suite/sys_vars/r/wsrep_start_position_basic.result index ad3606d6d55..a49e6135d47 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_start_position_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_start_position_basic.result @@ -1,8 +1,57 @@ -set @start_value = @@wsrep_start_position; -set @@global.wsrep_start_position='foo:bar'; -ERROR 42000: Variable 'wsrep_start_position' can't be set to the value of 'foo:bar' -set @@global.wsrep_start_position=NULL; +# +# wsrep_start_position +# +# save the initial value +SET @wsrep_start_position_global_saved = @@global.wsrep_start_position; +# default +SELECT @@global.wsrep_start_position; +@@global.wsrep_start_position +00000000-0000-0000-0000-000000000000:-1 + +# scope +SELECT @@session.wsrep_start_position; +ERROR HY000: Variable 'wsrep_start_position' is a GLOBAL variable +SET @@global.wsrep_start_position='00000000-0000-0000-0000-000000000000:-1'; +SELECT @@global.wsrep_start_position; +@@global.wsrep_start_position +00000000-0000-0000-0000-000000000000:-1 + +# valid values +SET @@global.wsrep_start_position='00000000-0000-0000-0000-000000000000:-2'; +SELECT @@global.wsrep_start_position; +@@global.wsrep_start_position +00000000-0000-0000-0000-000000000000:-2 +SET @@global.wsrep_start_position='12345678-1234-1234-1234-123456789012:100'; +SELECT @@global.wsrep_start_position; +@@global.wsrep_start_position +12345678-1234-1234-1234-123456789012:100 +SET @@global.wsrep_start_position=default; +SELECT @@global.wsrep_start_position; +@@global.wsrep_start_position +00000000-0000-0000-0000-000000000000:-1 + +# invalid values +SET @@global.wsrep_start_position='000000000000000-0000-0000-0000-000000000000:-1'; +ERROR 42000: Variable 'wsrep_start_position' can't be set to the value of '000000000000000-0000-0000-0000-000000000000:-1' +SET @@global.wsrep_start_position='12345678-1234-1234-12345-123456789012:100'; +ERROR 42000: Variable 'wsrep_start_position' can't be set to the value of '12345678-1234-1234-12345-123456789012:100' +SET @@global.wsrep_start_position='12345678-1234-123-12345-123456789012:0'; +ERROR 42000: Variable 'wsrep_start_position' can't be set to the value of '12345678-1234-123-12345-123456789012:0' +SET @@global.wsrep_start_position='12345678-1234-1234-1234-123456789012:_99999'; +ERROR 42000: Variable 'wsrep_start_position' can't be set to the value of '12345678-1234-1234-1234-123456789012:_99999' +SET @@global.wsrep_start_position='12345678-1234-1234-1234-123456789012:a'; +ERROR 42000: Variable 'wsrep_start_position' can't be set to the value of '12345678-1234-1234-1234-123456789012:a' +SET @@global.wsrep_start_position='OFF'; +ERROR 42000: Variable 'wsrep_start_position' can't be set to the value of 'OFF' +SET @@global.wsrep_start_position=ON; +ERROR 42000: Variable 'wsrep_start_position' can't be set to the value of 'ON' +SET @@global.wsrep_start_position=''; +ERROR 42000: Variable 'wsrep_start_position' can't be set to the value of '' +SET @@global.wsrep_start_position=NULL; ERROR 42000: Variable 'wsrep_start_position' can't be set to the value of 'NULL' -SET @@global.wsrep_start_position = -1; -ERROR 42000: Incorrect argument type to variable 'wsrep_start_position' -set @@global.wsrep_start_position = @start_value; +SET @@global.wsrep_start_position='junk'; +ERROR 42000: Variable 'wsrep_start_position' can't be set to the value of 'junk' + +# restore the initial value +SET @@global.wsrep_start_position = @wsrep_start_position_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_auto_increment_control_basic.test b/mysql-test/suite/sys_vars/t/wsrep_auto_increment_control_basic.test index 91d3c578a2c..5dc23cf2ad6 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_auto_increment_control_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_auto_increment_control_basic.test @@ -1,13 +1,42 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -set @start_value = @@wsrep_auto_increment_control; +--echo # +--echo # wsrep_auto_increment_control +--echo # -set @@global.wsrep_auto_increment_control=ON; -set @@global.wsrep_auto_increment_control=OFF; -set @@global.wsrep_auto_increment_control=1; -set @@global.wsrep_auto_increment_control=0; ---Error 1231 -SET @@global.wsrep_auto_increment_control = -1; +--echo # save the initial value +SET @wsrep_auto_increment_control_global_saved = @@global.wsrep_auto_increment_control; -set @@global.wsrep_auto_increment_control = @start_value; +--echo # default +SELECT @@global.wsrep_auto_increment_control; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_auto_increment_control; +SET @@global.wsrep_auto_increment_control=OFF; +SELECT @@global.wsrep_auto_increment_control; +SET @@global.wsrep_auto_increment_control=ON; +SELECT @@global.wsrep_auto_increment_control; + +--echo +--echo # valid values +SET @@global.wsrep_auto_increment_control='OFF'; +SELECT @@global.wsrep_auto_increment_control; +SET @@global.wsrep_auto_increment_control=ON; +SELECT @@global.wsrep_auto_increment_control; +SET @@global.wsrep_auto_increment_control=default; +SELECT @@global.wsrep_auto_increment_control; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_auto_increment_control=NULL; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_auto_increment_control='junk'; + +--echo +--echo # restore the initial value +SET @@global.wsrep_auto_increment_control = @wsrep_auto_increment_control_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_causal_reads_basic.test b/mysql-test/suite/sys_vars/t/wsrep_causal_reads_basic.test index 2fb597e842e..6539e5cba85 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_causal_reads_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_causal_reads_basic.test @@ -1,13 +1,45 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -set @start_value = @@wsrep_causal_reads; +--echo # +--echo # wsrep_causal_reads +--echo # -set @@global.wsrep_causal_reads=ON; -set @@global.wsrep_causal_reads=OFF; -set @@global.wsrep_causal_reads=1; -set @@global.wsrep_causal_reads=0; ---Error 1231 -SET @@global.wsrep_causal_reads = -1; +--echo # save the initial values +SET @wsrep_causal_reads_global_saved = @@global.wsrep_causal_reads; +SET @wsrep_causal_reads_session_saved = @@session.wsrep_causal_reads; -set @@global.wsrep_causal_reads = @start_value; +--echo # default +SELECT @@global.wsrep_causal_reads; +SELECT @@session.wsrep_causal_reads; + +--echo +--echo # scope and valid values +SET @@global.wsrep_causal_reads=OFF; +SELECT @@global.wsrep_causal_reads; +SET @@global.wsrep_causal_reads=ON; +SELECT @@global.wsrep_causal_reads; + +SET @@session.wsrep_causal_reads=OFF; +SELECT @@session.wsrep_causal_reads; +SET @@session.wsrep_causal_reads=ON; +SELECT @@session.wsrep_causal_reads; +SET @@session.wsrep_causal_reads=default; +SELECT @@session.wsrep_causal_reads; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_causal_reads=NULL; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_causal_reads='junk'; +--error ER_WRONG_VALUE_FOR_VAR +SET @@session.wsrep_causal_reads=NULL; +--error ER_WRONG_VALUE_FOR_VAR +SET @@session.wsrep_causal_reads='junk'; + +--echo +--echo # restore the initial values +SET @@global.wsrep_causal_reads = @wsrep_causal_reads_global_saved; +SET @@session.wsrep_causal_reads = @wsrep_causal_reads_session_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_certify_nonpk b/mysql-test/suite/sys_vars/t/wsrep_certify_nonpk deleted file mode 100644 index f4512aeb5da..00000000000 --- a/mysql-test/suite/sys_vars/t/wsrep_certify_nonpk +++ /dev/null @@ -1,13 +0,0 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc - -set @start_value = @@wsrep_certify_nonpk; - -set @@global.wsrep_certify_nonpk=ON; -set @@global.wsrep_certify_nonpk=OFF; -set @@global.wsrep_certify_nonpk=1; -set @@global.wsrep_certify_nonpk=0; ---Error ER_WRONG_TYPE_FOR_VAR -SET @@global.wsrep_certify_nonpk = -1; - -set @@global.wsrep_certify_nonpk = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_certify_nonpk_basic.test b/mysql-test/suite/sys_vars/t/wsrep_certify_nonpk_basic.test index b623d8eb073..a2c690e5954 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_certify_nonpk_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_certify_nonpk_basic.test @@ -1,13 +1,42 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -set @start_value = @@wsrep_certify_nonpk; +--echo # +--echo # wsrep_certify_nonpk +--echo # -set @@global.wsrep_certify_nonpk=ON; -set @@global.wsrep_certify_nonpk=OFF; -set @@global.wsrep_certify_nonpk=1; -set @@global.wsrep_certify_nonpk=0; ---Error 1231 -SET @@global.wsrep_certify_nonpk = -1; +--echo # save the initial value +SET @wsrep_certify_nonpk_global_saved = @@global.wsrep_certify_nonpk; -set @@global.wsrep_certify_nonpk = @start_value; +--echo # default +SELECT @@global.wsrep_certify_nonpk; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_certify_nonpk; +SET @@global.wsrep_certify_nonpk=OFF; +SELECT @@global.wsrep_certify_nonpk; +SET @@global.wsrep_certify_nonpk=ON; +SELECT @@global.wsrep_certify_nonpk; + +--echo +--echo # valid values +SET @@global.wsrep_certify_nonpk='OFF'; +SELECT @@global.wsrep_certify_nonpk; +SET @@global.wsrep_certify_nonpk=ON; +SELECT @@global.wsrep_certify_nonpk; +SET @@global.wsrep_certify_nonpk=default; +SELECT @@global.wsrep_certify_nonpk; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_certify_nonpk=NULL; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_certify_nonpk='junk'; + +--echo +--echo # restore the initial value +SET @@global.wsrep_certify_nonpk = @wsrep_certify_nonpk_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_cluster_address_basic.test b/mysql-test/suite/sys_vars/t/wsrep_cluster_address_basic.test index b61d5ea60c3..b9e00901eb6 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_cluster_address_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_cluster_address_basic.test @@ -1,44 +1,48 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -SELECT COUNT(@@GLOBAL.wsrep_cluster_address); ---echo 1 Expected +--echo # +--echo # wsrep_cluster_address +--echo # -SELECT COUNT(@@GLOBAL.wsrep_cluster_address); ---echo 1 Expected +call mtr.add_suppression("safe_mutex: Found wrong usage of mutex.*"); -SELECT @@GLOBAL.wsrep_cluster_address = VARIABLE_VALUE -FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES -WHERE VARIABLE_NAME='wsrep_cluster_address'; ---echo 1 Expected +--echo # save the initial value +SET @wsrep_cluster_address_global_saved = @@global.wsrep_cluster_address; -SELECT COUNT(@@GLOBAL.wsrep_cluster_address); ---echo 1 Expected +--echo # default +SELECT @@global.wsrep_cluster_address; -SELECT COUNT(VARIABLE_VALUE) -FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES -WHERE VARIABLE_NAME='wsrep_cluster_address'; ---echo 1 Expected +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_cluster_address; +SELECT @@global.wsrep_cluster_address; -SELECT @@wsrep_cluster_address = @@GLOBAL.wsrep_cluster_address; ---echo 1 Expected +--echo +--echo # valid values +SET @@global.wsrep_cluster_address='127.0.0.1'; +SELECT @@global.wsrep_cluster_address; +SET @@global.wsrep_cluster_address=AUTO; +SELECT @@global.wsrep_cluster_address; +SET @@global.wsrep_cluster_address=default; +SELECT @@global.wsrep_cluster_address; -SELECT COUNT(@@wsrep_cluster_address); ---echo 1 Expected - ---Error ER_INCORRECT_GLOBAL_LOCAL_VAR -SELECT COUNT(@@local.wsrep_cluster_address); ---echo Expected error 'Variable is a GLOBAL variable' - ---Error ER_INCORRECT_GLOBAL_LOCAL_VAR -SELECT COUNT(@@SESSION.wsrep_cluster_address); ---echo Expected error 'Variable is a GLOBAL variable' - -SELECT COUNT(@@GLOBAL.wsrep_cluster_address); ---echo 1 Expected - ---Error ER_BAD_FIELD_ERROR -SELECT wsrep_cluster_address = @@SESSION.wsrep_cluster_address; ---echo Expected error 'Readonly variable' +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_node_address=NULL; +SELECT @@global.wsrep_node_address; +# The values being assigned to wsrep_node_address are not verified so the +# following alues are currently valid too. +SET @@global.wsrep_cluster_address=ON; +SELECT @@global.wsrep_cluster_address; +SET @@global.wsrep_cluster_address='OFF'; +SELECT @@global.wsrep_cluster_address; +SET @@global.wsrep_cluster_address='junk'; +SELECT @@global.wsrep_cluster_address; +--echo +--echo # restore the initial value +SET @@global.wsrep_cluster_address = @wsrep_cluster_address_global_saved; +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_cluster_name_basic.test b/mysql-test/suite/sys_vars/t/wsrep_cluster_name_basic.test index 104c342bfe4..a6fc3ef7b1e 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_cluster_name_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_cluster_name_basic.test @@ -1,12 +1,40 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -set @start_value = @@wsrep_cluster_name; +--echo # +--echo # wsrep_cluster_name +--echo # -set @@global.wsrep_cluster_name='test'; ---Error 1231 -set @@global.wsrep_cluster_name=NULL; ---Error 1232 -SET @@global.wsrep_cluster_name = 1; +--echo # save the initial value +SET @wsrep_cluster_name_global_saved = @@global.wsrep_cluster_name; -set @@global.wsrep_cluster_name = @start_value; \ No newline at end of file +--echo # default +SELECT @@global.wsrep_cluster_name; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_cluster_name; +SET @@global.wsrep_cluster_name='my_galera_cluster'; +SELECT @@global.wsrep_cluster_name; + +--echo +--echo # valid values +SET @@global.wsrep_cluster_name='my_quoted_galera_cluster'; +SELECT @@global.wsrep_cluster_name; +SET @@global.wsrep_cluster_name=my_unquoted_cluster; +SELECT @@global.wsrep_cluster_name; +SET @@global.wsrep_cluster_name=OFF; +SELECT @@global.wsrep_cluster_name; +SET @@global.wsrep_cluster_name=default; +SELECT @@global.wsrep_cluster_name; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_cluster_name=NULL; + +--echo +--echo # restore the initial value +SET @@global.wsrep_cluster_name = @wsrep_cluster_name_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_convert_lock_to_trx_basic.test b/mysql-test/suite/sys_vars/t/wsrep_convert_lock_to_trx_basic.test index 84b92085238..486832fb394 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_convert_lock_to_trx_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_convert_lock_to_trx_basic.test @@ -1,13 +1,42 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -set @start_value = @@wsrep_convert_lock_to_trx; +--echo # +--echo # wsrep_convert_lock_to_trx +--echo # -set @@global.wsrep_convert_lock_to_trx=ON; -set @@global.wsrep_convert_lock_to_trx=OFF; -set @@global.wsrep_convert_lock_to_trx=1; -set @@global.wsrep_convert_lock_to_trx=0; ---Error 1231 -SET @@global.wsrep_convert_lock_to_trx = -1; +--echo # save the initial value +SET @wsrep_convert_lock_to_trx_global_saved = @@global.wsrep_convert_lock_to_trx; -set @@global.wsrep_convert_lock_to_trx = @start_value; \ No newline at end of file +--echo # default +SELECT @@global.wsrep_convert_lock_to_trx; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_convert_lock_to_trx; +SET @@global.wsrep_convert_lock_to_trx=OFF; +SELECT @@global.wsrep_convert_lock_to_trx; +SET @@global.wsrep_convert_lock_to_trx=ON; +SELECT @@global.wsrep_convert_lock_to_trx; + +--echo +--echo # valid values +SET @@global.wsrep_convert_lock_to_trx='OFF'; +SELECT @@global.wsrep_convert_lock_to_trx; +SET @@global.wsrep_convert_lock_to_trx=ON; +SELECT @@global.wsrep_convert_lock_to_trx; +SET @@global.wsrep_convert_lock_to_trx=default; +SELECT @@global.wsrep_convert_lock_to_trx; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_convert_lock_to_trx=NULL; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_convert_lock_to_trx='junk'; + +--echo +--echo # restore the initial value +SET @@global.wsrep_convert_lock_to_trx = @wsrep_convert_lock_to_trx_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_data_home_dir_basic.test b/mysql-test/suite/sys_vars/t/wsrep_data_home_dir_basic.test index fccf685193e..41f97cfdaf6 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_data_home_dir_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_data_home_dir_basic.test @@ -1,48 +1,41 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -SELECT COUNT(@@GLOBAL.wsrep_data_home_dir); ---echo 1 Expected +--echo # +--echo # wsrep_data_home_dir (readonly) +--echo # +--echo # default +SELECT @@global.wsrep_data_home_dir; + +--echo +--echo # scope --error ER_INCORRECT_GLOBAL_LOCAL_VAR -SET @@GLOBAL.wsrep_data_home_dir=1; ---echo Expected error 'Read only variable' +SELECT @@session.wsrep_data_home_dir; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@global.wsrep_data_home_dir='/tmp/data'; +SELECT @@global.wsrep_data_home_dir; -SELECT COUNT(@@GLOBAL.wsrep_data_home_dir); ---echo 1 Expected - -SELECT @@GLOBAL.wsrep_data_home_dir = VARIABLE_VALUE -FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES -WHERE VARIABLE_NAME='wsrep_data_home_dir'; ---echo 1 Expected - -SELECT COUNT(@@GLOBAL.wsrep_data_home_dir); ---echo 1 Expected - -SELECT COUNT(VARIABLE_VALUE) -FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES -WHERE VARIABLE_NAME='wsrep_data_home_dir'; ---echo 1 Expected - -SELECT @@wsrep_data_home_dir = @@GLOBAL.wsrep_data_home_dir; ---echo 1 Expected - -SELECT COUNT(@@wsrep_data_home_dir); ---echo 1 Expected - ---Error ER_INCORRECT_GLOBAL_LOCAL_VAR -SELECT COUNT(@@local.wsrep_data_home_dir); ---echo Expected error 'Variable is a GLOBAL variable' - ---Error ER_INCORRECT_GLOBAL_LOCAL_VAR -SELECT COUNT(@@SESSION.wsrep_data_home_dir); ---echo Expected error 'Variable is a GLOBAL variable' - -SELECT COUNT(@@GLOBAL.wsrep_data_home_dir); ---echo 1 Expected - ---Error ER_BAD_FIELD_ERROR -SELECT wsrep_data_home_dir = @@SESSION.wsrep_data_home_dir; ---echo Expected error 'Readonly variable' +--echo +--echo # valid values +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@global.wsrep_data_home_dir='/tmp/data'; +SELECT @@global.wsrep_data_home_dir; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@global.wsrep_data_home_dir=junk-dir; +SELECT @@global.wsrep_data_home_dir; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@global.wsrep_data_home_dir=junk/dir; +SELECT @@global.wsrep_data_home_dir; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@global.wsrep_data_home_dir=OFF; +SELECT @@global.wsrep_data_home_dir; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@global.wsrep_data_home_dir=default; +SELECT @@global.wsrep_data_home_dir; +--echo +--echo # invalid values +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@global.wsrep_data_home_dir=NULL; +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_dbug_option_basic.test b/mysql-test/suite/sys_vars/t/wsrep_dbug_option_basic.test index 0a559fe8d27..80ce190a154 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_dbug_option_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_dbug_option_basic.test @@ -1,11 +1,42 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -set @start_value = @@wsrep_dbug_option; +--echo # +--echo # wsrep_dbug_option +--echo # -set @@global.wsrep_dbug_option='foo:bar'; -set @@global.wsrep_dbug_option=NULL; ---Error 1232 -SET @@global.wsrep_dbug_option = -1; +--echo # save the initial value +SET @wsrep_dbug_option_global_saved = @@global.wsrep_dbug_option; -set @@global.wsrep_dbug_option = @start_value; +--echo # default +SELECT @@global.wsrep_dbug_option; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_dbug_option; +SET @@global.wsrep_dbug_option='test-dbug-string'; +SELECT @@global.wsrep_dbug_option; + +--echo +--echo # valid values +SET @@global.wsrep_dbug_option='quoted-dbug-string'; +SELECT @@global.wsrep_dbug_option; +SET @@global.wsrep_dbug_option=unquoted_dbug_string; +SELECT @@global.wsrep_dbug_option; +SET @@global.wsrep_dbug_option=OFF; +SELECT @@global.wsrep_dbug_option; +SET @@global.wsrep_dbug_option=NULL; +SELECT @@global.wsrep_dbug_option; +SET @@global.wsrep_dbug_option=default; +SELECT @@global.wsrep_dbug_option; + +--echo +--echo # invalid values +--error ER_WRONG_TYPE_FOR_VAR +SET @@global.wsrep_dbug_option=1; + +--echo +--echo # restore the initial value +SET @@global.wsrep_dbug_option = @wsrep_dbug_option_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_debug_basic.test b/mysql-test/suite/sys_vars/t/wsrep_debug_basic.test index 194c163baa6..50576ff064e 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_debug_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_debug_basic.test @@ -1,13 +1,42 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -set @start_value = @@wsrep_debug; +--echo # +--echo # wsrep_debug +--echo # -set @@global.wsrep_debug=ON; -set @@global.wsrep_debug=OFF; -set @@global.wsrep_debug=1; -set @@global.wsrep_debug=0; ---Error 1231 -SET @@global.wsrep_debug = -1; +--echo # save the initial value +SET @wsrep_debug_global_saved = @@global.wsrep_debug; -set @@global.wsrep_debug = @start_value; \ No newline at end of file +--echo # default +SELECT @@global.wsrep_debug; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_debug; +SET @@global.wsrep_debug=OFF; +SELECT @@global.wsrep_debug; +SET @@global.wsrep_debug=ON; +SELECT @@global.wsrep_debug; + +--echo +--echo # valid values +SET @@global.wsrep_debug='OFF'; +SELECT @@global.wsrep_debug; +SET @@global.wsrep_debug=ON; +SELECT @@global.wsrep_debug; +SET @@global.wsrep_debug=default; +SELECT @@global.wsrep_debug; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_debug=NULL; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_debug='junk'; + +--echo +--echo # restore the initial value +SET @@global.wsrep_debug = @wsrep_debug_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_debug_option_basic.test b/mysql-test/suite/sys_vars/t/wsrep_debug_option_basic.test deleted file mode 100644 index 060e721b676..00000000000 --- a/mysql-test/suite/sys_vars/t/wsrep_debug_option_basic.test +++ /dev/null @@ -1,13 +0,0 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc - -set @start_value = @@wsrep_debug_option; - ---error 1231 -set @@global.wsrep_debug_option='foo:bar'; ---error 1231 -set @@global.wsrep_debug_option=NULL; ---Error 1232 -SET @@global.wsrep_debug_option = -1; - -set @@global.wsrep_debug_option = @start_value; diff --git a/mysql-test/suite/sys_vars/t/wsrep_desync_basic.test b/mysql-test/suite/sys_vars/t/wsrep_desync_basic.test index 3c64d8cb30f..15226c75d8b 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_desync_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_desync_basic.test @@ -1,4 +1,49 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -select @@global.wsrep_desync; +--echo # +--echo # wsrep_desync +--echo # + +# expected as no wsrep provider is currently loaded +call mtr.add_suppression("WSREP: SET desync failed 9 for SET @@global.wsrep_desync=ON"); + +--echo # save the initial value +SET @wsrep_desync_global_saved = @@global.wsrep_desync; + +--echo # default +SELECT @@global.wsrep_desync; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_desync; +SET @@global.wsrep_desync=OFF; +SELECT @@global.wsrep_desync; +# expected as no wsrep provider is currently loaded +--error ER_CANNOT_USER +SET @@global.wsrep_desync=ON; +SELECT @@global.wsrep_desync; + +--echo +--echo # valid values +SET @@global.wsrep_desync='OFF'; +SELECT @@global.wsrep_desync; +# expected as no wsrep provider is currently loaded +--error ER_CANNOT_USER +SET @@global.wsrep_desync=ON; +SELECT @@global.wsrep_desync; +SET @@global.wsrep_desync=default; +SELECT @@global.wsrep_desync; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_desync=NULL; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_desync='junk'; + +--echo +--echo # restore the initial value +SET @@global.wsrep_desync = @wsrep_desync_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_drupal_282555_workaround_basic.test b/mysql-test/suite/sys_vars/t/wsrep_drupal_282555_workaround_basic.test index ada08bb125d..e24f6a15265 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_drupal_282555_workaround_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_drupal_282555_workaround_basic.test @@ -1,13 +1,42 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -set @start_value = @@wsrep_drupal_282555_workaround; +--echo # +--echo # wsrep_drupal_282555_workaround +--echo # -set @@global.wsrep_drupal_282555_workaround=ON; -set @@global.wsrep_drupal_282555_workaround=OFF; -set @@global.wsrep_drupal_282555_workaround=1; -set @@global.wsrep_drupal_282555_workaround=0; ---Error 1231 -SET @@global.wsrep_drupal_282555_workaround = -1; +--echo # save the initial value +SET @wsrep_drupal_282555_workaround_global_saved = @@global.wsrep_drupal_282555_workaround; -set @@global.wsrep_drupal_282555_workaround = @start_value; \ No newline at end of file +--echo # default +SELECT @@global.wsrep_drupal_282555_workaround; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_drupal_282555_workaround; +SET @@global.wsrep_drupal_282555_workaround=OFF; +SELECT @@global.wsrep_drupal_282555_workaround; +SET @@global.wsrep_drupal_282555_workaround=ON; +SELECT @@global.wsrep_drupal_282555_workaround; + +--echo +--echo # valid values +SET @@global.wsrep_drupal_282555_workaround='OFF'; +SELECT @@global.wsrep_drupal_282555_workaround; +SET @@global.wsrep_drupal_282555_workaround=ON; +SELECT @@global.wsrep_drupal_282555_workaround; +SET @@global.wsrep_drupal_282555_workaround=default; +SELECT @@global.wsrep_drupal_282555_workaround; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_drupal_282555_workaround=NULL; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_drupal_282555_workaround='junk'; + +--echo +--echo # restore the initial value +SET @@global.wsrep_drupal_282555_workaround = @wsrep_drupal_282555_workaround_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_forced_binlog_format_basic.test b/mysql-test/suite/sys_vars/t/wsrep_forced_binlog_format_basic.test index 5e5530a8f64..455034bb623 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_forced_binlog_format_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_forced_binlog_format_basic.test @@ -1,14 +1,46 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -set @start_value = @@wsrep_forced_binlog_format; +--echo # +--echo # wsrep_forced_binlog_format +--echo # -set @@global.wsrep_forced_binlog_format = ROW; -set @@global.wsrep_forced_binlog_format = MIXED; -set @@global.wsrep_forced_binlog_format = STATEMENT; -set @@global.wsrep_forced_binlog_format = NONE; +--echo # save the initial value +SET @wsrep_forced_binlog_format_global_saved = @@global.wsrep_forced_binlog_format; ---error 1231 -set @@global.wsrep_forced_binlog_format = FOO; +--echo # default +SELECT @@global.wsrep_forced_binlog_format; -set @@global.wsrep_forced_binlog_format = @start_value; \ No newline at end of file +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_forced_binlog_format; +SET @@global.wsrep_forced_binlog_format=STATEMENT; +SELECT @@global.wsrep_forced_binlog_format; + +--echo +--echo # valid values +SET @@global.wsrep_forced_binlog_format=STATEMENT; +SELECT @@global.wsrep_forced_binlog_format; +SET @@global.wsrep_forced_binlog_format=ROW; +SELECT @@global.wsrep_forced_binlog_format; +SET @@global.wsrep_forced_binlog_format=MIXED; +SELECT @@global.wsrep_forced_binlog_format; +SET @@global.wsrep_forced_binlog_format=NONE; +SELECT @@global.wsrep_forced_binlog_format; +SET @@global.wsrep_forced_binlog_format=default; +SELECT @@global.wsrep_forced_binlog_format; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_forced_binlog_format=NULL; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_forced_binlog_format='junk'; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_forced_binlog_format=ON; + +--echo +--echo # restore the initial value +SET @@global.wsrep_forced_binlog_format = @wsrep_forced_binlog_format_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_load_data_splitting_basic.test b/mysql-test/suite/sys_vars/t/wsrep_load_data_splitting_basic.test index 61ff27d6894..d52e388fc60 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_load_data_splitting_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_load_data_splitting_basic.test @@ -1,13 +1,42 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -set @start_value = @@wsrep_load_data_splitting; +--echo # +--echo # wsrep_load_data_splitting +--echo # -set @@global.wsrep_load_data_splitting=ON; -set @@global.wsrep_load_data_splitting=OFF; -set @@global.wsrep_load_data_splitting=1; -set @@global.wsrep_load_data_splitting=0; ---Error 1231 -SET @@global.wsrep_load_data_splitting = -1; +--echo # save the initial value +SET @wsrep_load_data_splitting_global_saved = @@global.wsrep_load_data_splitting; -set @@global.wsrep_load_data_splitting = @start_value; \ No newline at end of file +--echo # default +SELECT @@global.wsrep_load_data_splitting; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_load_data_splitting; +SET @@global.wsrep_load_data_splitting=OFF; +SELECT @@global.wsrep_load_data_splitting; +SET @@global.wsrep_load_data_splitting=ON; +SELECT @@global.wsrep_load_data_splitting; + +--echo +--echo # valid values +SET @@global.wsrep_load_data_splitting='OFF'; +SELECT @@global.wsrep_load_data_splitting; +SET @@global.wsrep_load_data_splitting=ON; +SELECT @@global.wsrep_load_data_splitting; +SET @@global.wsrep_load_data_splitting=default; +SELECT @@global.wsrep_load_data_splitting; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_load_data_splitting=NULL; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_load_data_splitting='junk'; + +--echo +--echo # restore the initial value +SET @@global.wsrep_load_data_splitting = @wsrep_load_data_splitting_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_log_conflicts_basic.test b/mysql-test/suite/sys_vars/t/wsrep_log_conflicts_basic.test index dbd696c45a2..eee4d966855 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_log_conflicts_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_log_conflicts_basic.test @@ -1,13 +1,42 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -set @start_value = @@wsrep_log_conflicts; +--echo # +--echo # wsrep_log_conflicts +--echo # -set @@global.wsrep_log_conflicts=ON; -set @@global.wsrep_log_conflicts=OFF; -set @@global.wsrep_log_conflicts=1; -set @@global.wsrep_log_conflicts=0; ---Error 1231 -SET @@global.wsrep_log_conflicts = -1; +--echo # save the initial value +SET @wsrep_log_conflicts_global_saved = @@global.wsrep_log_conflicts; -set @@global.wsrep_log_conflicts = @start_value; \ No newline at end of file +--echo # default +SELECT @@global.wsrep_log_conflicts; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_log_conflicts; +SET @@global.wsrep_log_conflicts=OFF; +SELECT @@global.wsrep_log_conflicts; +SET @@global.wsrep_log_conflicts=ON; +SELECT @@global.wsrep_log_conflicts; + +--echo +--echo # valid values +SET @@global.wsrep_log_conflicts='OFF'; +SELECT @@global.wsrep_log_conflicts; +SET @@global.wsrep_log_conflicts=ON; +SELECT @@global.wsrep_log_conflicts; +SET @@global.wsrep_log_conflicts=default; +SELECT @@global.wsrep_log_conflicts; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_log_conflicts=NULL; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_log_conflicts='junk'; + +--echo +--echo # restore the initial value +SET @@global.wsrep_log_conflicts = @wsrep_log_conflicts_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_max_ws_rows_basic.test b/mysql-test/suite/sys_vars/t/wsrep_max_ws_rows_basic.test index f607a567d80..ed78662c02d 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_max_ws_rows_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_max_ws_rows_basic.test @@ -1,14 +1,45 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -set @start_value = @@wsrep_max_ws_rows; +--echo # +--echo # wsrep_max_ws_rows +--echo # -set @@global.wsrep_max_ws_rows=256000; -set @@global.wsrep_max_ws_rows=0; -show warnings; -set @@global.wsrep_max_ws_rows=-1; -show warnings; ---Error 1232 -SET @@global.wsrep_max_ws_rows = r; +--echo # save the initial value +SET @wsrep_max_ws_rows_global_saved = @@global.wsrep_max_ws_rows; -set @@global.wsrep_max_ws_rows = @start_value; \ No newline at end of file +--echo # default +SELECT @@global.wsrep_max_ws_rows; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_max_ws_rows; +SET @@global.wsrep_max_ws_rows=1; +SELECT @@global.wsrep_max_ws_rows; + +--echo +--echo # valid values +SET @@global.wsrep_max_ws_rows=131072; +SELECT @@global.wsrep_max_ws_rows; +SET @@global.wsrep_max_ws_rows=131073; +SELECT @@global.wsrep_max_ws_rows; +SET @@global.wsrep_max_ws_rows=0; +SELECT @@global.wsrep_max_ws_rows; +SET @@global.wsrep_max_ws_rows=default; +SELECT @global.wsrep_max_ws_rows; + +--echo +--echo # invalid values +--error ER_WRONG_TYPE_FOR_VAR +SET @@global.wsrep_max_ws_rows=NULL; +--error ER_WRONG_TYPE_FOR_VAR +SET @@global.wsrep_max_ws_rows='junk'; +# expect warnings (Truncated incorrect wsrep_max_ws_rows value: '-1') +SET @@global.wsrep_max_ws_rows=-1; +SELECT @global.wsrep_max_ws_rows; + +--echo +--echo # restore the initial value +SET @@global.wsrep_max_ws_rows = @wsrep_max_ws_rows_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_max_ws_size_basic.test b/mysql-test/suite/sys_vars/t/wsrep_max_ws_size_basic.test index 6b1d1f71090..e7af4558f24 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_max_ws_size_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_max_ws_size_basic.test @@ -1,14 +1,45 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -set @start_value = @@wsrep_max_ws_size; +--echo # +--echo # wsrep_max_ws_size +--echo # -set @@global.wsrep_max_ws_size=256000; -set @@global.wsrep_max_ws_size=0; -show warnings; -set @@global.wsrep_max_ws_size=-1; -show warnings; ---Error 1232 -SET @@global.wsrep_max_ws_size = r; +--echo # save the initial value +SET @wsrep_max_ws_size_global_saved = @@global.wsrep_max_ws_size; -set @@global.wsrep_max_ws_size = @start_value; \ No newline at end of file +--echo # default +SELECT @@global.wsrep_max_ws_size; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_max_ws_size; +SET @@global.wsrep_max_ws_size=1; +SELECT @@global.wsrep_max_ws_size; + +--echo +--echo # valid values +SET @@global.wsrep_max_ws_size=1073741824; +SELECT @@global.wsrep_max_ws_size; +SET @@global.wsrep_max_ws_size=1073741825; +SELECT @@global.wsrep_max_ws_size; +SET @@global.wsrep_max_ws_size=0; +SELECT @@global.wsrep_max_ws_size; +SET @@global.wsrep_max_ws_size=default; +SELECT @global.wsrep_max_ws_size; + +--echo +--echo # invalid values +--error ER_WRONG_TYPE_FOR_VAR +SET @@global.wsrep_max_ws_size=NULL; +--error ER_WRONG_TYPE_FOR_VAR +SET @@global.wsrep_max_ws_size='junk'; +SELECT @global.wsrep_max_ws_size; +SET @@global.wsrep_max_ws_size=-1; +SELECT @global.wsrep_max_ws_size; + +--echo +--echo # restore the initial value +SET @@global.wsrep_max_ws_size = @wsrep_max_ws_size_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_mysql_replication_bundle_basic.test b/mysql-test/suite/sys_vars/t/wsrep_mysql_replication_bundle_basic.test index 20a0dc9bf9f..c293048c43f 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_mysql_replication_bundle_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_mysql_replication_bundle_basic.test @@ -1,16 +1,45 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -set @start_value = @@wsrep_mysql_replication_bundle; +--echo # +--echo # wsrep_mysql_replication_bundle +--echo # -set @@global.wsrep_mysql_replication_bundle=0; -set @@global.wsrep_mysql_replication_bundle=1000; +--echo # save the initial value +SET @wsrep_mysql_replication_bundle_global_saved = @@global.wsrep_mysql_replication_bundle; -set @@global.wsrep_mysql_replication_bundle=-1; -show warnings; -set @@global.wsrep_mysql_replication_bundle=1001; -show warnings; ---Error 1232 -SET @@global.wsrep_mysql_replication_bundle = r; +--echo # default +SELECT @@global.wsrep_mysql_replication_bundle; -set @@global.wsrep_mysql_replication_bundle = @start_value; \ No newline at end of file +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_mysql_replication_bundle; +SELECT @@global.wsrep_mysql_replication_bundle; + +--echo +--echo # valid values +SET @@global.wsrep_mysql_replication_bundle=0; +SELECT @@global.wsrep_mysql_replication_bundle; +SET @@global.wsrep_mysql_replication_bundle=1000; +SELECT @@global.wsrep_mysql_replication_bundle; +SET @@global.wsrep_mysql_replication_bundle=default; +SELECT @@global.wsrep_mysql_replication_bundle; + +--echo +--echo # invalid values +--error ER_WRONG_TYPE_FOR_VAR +SET @@global.wsrep_mysql_replication_bundle=NULL; +--error ER_WRONG_TYPE_FOR_VAR +SET @@global.wsrep_mysql_replication_bundle='junk'; +# expect warning (truncated incorrect value) +SET @@global.wsrep_mysql_replication_bundle=-1; +SELECT @@global.wsrep_mysql_replication_bundle; +# expect warning (truncated incorrect value) +SET @@global.wsrep_mysql_replication_bundle=1001; +SELECT @@global.wsrep_mysql_replication_bundle; + +--echo +--echo # restore the initial value +SET @@global.wsrep_mysql_replication_bundle = @wsrep_mysql_replication_bundle_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_node_address_basic.test b/mysql-test/suite/sys_vars/t/wsrep_node_address_basic.test index feace325044..fccb40de6bf 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_node_address_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_node_address_basic.test @@ -1,42 +1,45 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -SELECT COUNT(@@GLOBAL.wsrep_node_address); ---echo 1 Expected +--echo # +--echo # wsrep_node_address +--echo # ---error 1232 -SET @@GLOBAL.wsrep_node_address=1; ---echo Expected error 'Read only variable' +--echo # save the initial value +SET @wsrep_node_address_global_saved = @@global.wsrep_node_address; -SELECT COUNT(@@GLOBAL.wsrep_node_address); ---echo 1 Expected +--echo # default +SELECT @@global.wsrep_node_address; -SELECT @@GLOBAL.wsrep_node_address = VARIABLE_VALUE -FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES -WHERE VARIABLE_NAME='wsrep_node_address'; ---echo 1 Expected +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_node_address; +SELECT @@global.wsrep_node_address; -SELECT COUNT(@@GLOBAL.wsrep_node_address); ---echo 1 Expected +--echo +--echo # valid values +SET @@global.wsrep_node_address='127.0.0.1'; +SELECT @@global.wsrep_node_address; +# default == '' +SET @@global.wsrep_node_address=default; +SELECT @@global.wsrep_node_address; -SELECT COUNT(VARIABLE_VALUE) -FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES -WHERE VARIABLE_NAME='wsrep_node_address'; ---echo 1 Expected +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_node_address=NULL; +SELECT @@global.wsrep_node_address; +# The values being assigned to wsrep_node_address are not verified so the +# following alues are currently valid too. +SET @@global.wsrep_node_address=ON; +SELECT @@global.wsrep_node_address; +SET @@global.wsrep_node_address='OFF'; +SELECT @@global.wsrep_node_address; +SET @@global.wsrep_node_address='junk'; +SELECT @@global.wsrep_node_address; -SELECT @@wsrep_node_address = @@GLOBAL.wsrep_node_address; ---echo 1 Expected +--echo +--echo # restore the initial value +SET @@global.wsrep_node_address = @wsrep_node_address_global_saved; -SELECT COUNT(@@wsrep_node_address); ---echo 1 Expected - ---Error ER_INCORRECT_GLOBAL_LOCAL_VAR -SELECT COUNT(@@local.wsrep_node_address); ---echo Expected error 'Variable is a GLOBAL variable' - ---Error ER_INCORRECT_GLOBAL_LOCAL_VAR -SELECT COUNT(@@SESSION.wsrep_node_address); ---echo Expected error 'Variable is a GLOBAL variable' - -SELECT COUNT(@@GLOBAL.wsrep_node_address); ---echo 1 Expected +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_node_incoming_address_basic.test b/mysql-test/suite/sys_vars/t/wsrep_node_incoming_address_basic.test index 188a5960eb9..9ab9525d2a9 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_node_incoming_address_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_node_incoming_address_basic.test @@ -1,42 +1,47 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -SELECT COUNT(@@GLOBAL.wsrep_node_incoming_address); ---echo 1 Expected +--echo # +--echo # wsrep_node_incoming_address +--echo # ---error 1232 -SET @@GLOBAL.wsrep_node_incoming_address=1; ---echo Expected error 'Read only variable' +--echo # save the initial value +SET @wsrep_node_incoming_address_global_saved = @@global.wsrep_node_incoming_address; -SELECT COUNT(@@GLOBAL.wsrep_node_incoming_address); ---echo 1 Expected +--echo # default +SELECT @@global.wsrep_node_incoming_address; -SELECT @@GLOBAL.wsrep_node_incoming_address = VARIABLE_VALUE -FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES -WHERE VARIABLE_NAME='wsrep_node_incoming_address'; ---echo 1 Expected +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_node_incoming_address; +SELECT @@global.wsrep_node_incoming_address; -SELECT COUNT(@@GLOBAL.wsrep_node_incoming_address); ---echo 1 Expected +--echo +--echo # valid values +SET @@global.wsrep_node_incoming_address='127.0.0.1:4444'; +SELECT @@global.wsrep_node_incoming_address; +SET @@global.wsrep_node_incoming_address='127.0.0.1'; +SELECT @@global.wsrep_node_incoming_address; +SET @@global.wsrep_node_incoming_address=AUTO; +SELECT @@global.wsrep_node_incoming_address; +SET @@global.wsrep_node_incoming_address=default; +SELECT @@global.wsrep_node_incoming_address; -SELECT COUNT(VARIABLE_VALUE) -FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES -WHERE VARIABLE_NAME='wsrep_node_incoming_address'; ---echo 1 Expected +--echo +--echo # invalid values +# The values being assigned to wsrep_node_incoming_address are not verified so +# the following values are currently valid too. +SET @@global.wsrep_node_incoming_address=ON; +SELECT @@global.wsrep_node_incoming_address; +SET @@global.wsrep_node_incoming_address='OFF'; +SELECT @@global.wsrep_node_incoming_address; +SET @@global.wsrep_node_incoming_address=NULL; +SELECT @@global.wsrep_node_incoming_address; +SET @@global.wsrep_node_incoming_address='junk'; +SELECT @@global.wsrep_node_incoming_address; -SELECT @@wsrep_node_incoming_address = @@GLOBAL.wsrep_node_incoming_address; ---echo 1 Expected +--echo +--echo # restore the initial value +SET @@global.wsrep_node_incoming_address = @wsrep_node_incoming_address_global_saved; -SELECT COUNT(@@wsrep_node_incoming_address); ---echo 1 Expected - ---Error ER_INCORRECT_GLOBAL_LOCAL_VAR -SELECT COUNT(@@local.wsrep_node_incoming_address); ---echo Expected error 'Variable is a GLOBAL variable' - ---Error ER_INCORRECT_GLOBAL_LOCAL_VAR -SELECT COUNT(@@SESSION.wsrep_node_incoming_address); ---echo Expected error 'Variable is a GLOBAL variable' - -SELECT COUNT(@@GLOBAL.wsrep_node_incoming_address); ---echo 1 Expected +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_node_name_basic.test b/mysql-test/suite/sys_vars/t/wsrep_node_name_basic.test index 3220ae373e2..1f3ccc0de2c 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_node_name_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_node_name_basic.test @@ -1,11 +1,44 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -set @start_value = @@wsrep_node_name; +--echo # +--echo # wsrep_node_name +--echo # -set @@global.wsrep_node_name='test'; -set @@global.wsrep_node_name=NULL; ---Error 1232 -SET @@global.wsrep_node_name = 1; +call mtr.add_suppression("WSREP: Failed to get provider options"); -set @@global.wsrep_node_name = @start_value; \ No newline at end of file +--echo # save the initial value +SET @wsrep_node_name_global_saved = @@global.wsrep_node_name; + +--echo # default +SELECT @@global.wsrep_node_name; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_node_name; +SET @@global.wsrep_node_name='node_name'; +SELECT @@global.wsrep_node_name; + +--echo +--echo # valid values +SET @@global.wsrep_node_name='my_node'; +SELECT @@global.wsrep_node_name; +SET @@global.wsrep_node_name='hyphenated-node-name'; +SELECT @@global.wsrep_node_name; +SET @@global.wsrep_node_name=default; +SELECT @@global.wsrep_node_name; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_node_name=NULL; +SELECT @@global.wsrep_node_name; +--error ER_WRONG_TYPE_FOR_VAR +SET @@global.wsrep_node_name=1; +SELECT @@global.wsrep_node_name; + +--echo +--echo # restore the initial value +SET @@global.wsrep_node_name = @wsrep_node_name_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_notify_cmd_basic.test b/mysql-test/suite/sys_vars/t/wsrep_notify_cmd_basic.test index d816453f8a3..6d1535ba148 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_notify_cmd_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_notify_cmd_basic.test @@ -1,11 +1,43 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -set @start_value = @@wsrep_notify_cmd; +--echo # +--echo # wsrep_notify_cmd +--echo # -set @@global.wsrep_notify_cmd='test'; -set @@global.wsrep_notify_cmd=NULL; ---Error 1232 -SET @@global.wsrep_notify_cmd = 1; +call mtr.add_suppression("WSREP: Failed to get provider options"); -set @@global.wsrep_notify_cmd = @start_value; \ No newline at end of file +--echo # save the initial value +SET @wsrep_notify_cmd_global_saved = @@global.wsrep_notify_cmd; + +--echo # default +SELECT @@global.wsrep_notify_cmd; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_notify_cmd; +SET @@global.wsrep_notify_cmd='notify_cmd'; +SELECT @@global.wsrep_notify_cmd; + +--echo +--echo # valid values +SET @@global.wsrep_notify_cmd='command'; +SELECT @@global.wsrep_notify_cmd; +SET @@global.wsrep_notify_cmd='hyphenated-command'; +SELECT @@global.wsrep_notify_cmd; +SET @@global.wsrep_notify_cmd=default; +SELECT @@global.wsrep_notify_cmd; +SET @@global.wsrep_notify_cmd=NULL; +SELECT @@global.wsrep_notify_cmd; + +--echo +--echo # invalid values +--error ER_WRONG_TYPE_FOR_VAR +SET @@global.wsrep_notify_cmd=1; +SELECT @@global.wsrep_notify_cmd; + +--echo +--echo # restore the initial value +SET @@global.wsrep_notify_cmd = @wsrep_notify_cmd_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_on_basic.test b/mysql-test/suite/sys_vars/t/wsrep_on_basic.test index 5afe5c4451f..229d771b5e7 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_on_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_on_basic.test @@ -1,13 +1,45 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -set @start_value = @@wsrep_on; +--echo # +--echo # wsrep_on +--echo # -set @@global.wsrep_on=ON; -set @@global.wsrep_on=OFF; -set @@global.wsrep_on=1; -set @@global.wsrep_on=0; ---Error 1231 -SET @@global.wsrep_on = -1; +--echo # save the initial values +SET @wsrep_on_global_saved = @@global.wsrep_on; +SET @wsrep_on_session_saved = @@session.wsrep_on; -set @@global.wsrep_on = @start_value; +--echo # default +SELECT @@global.wsrep_on; +SELECT @@session.wsrep_on; + +--echo +--echo # scope and valid values +SET @@global.wsrep_on=OFF; +SELECT @@global.wsrep_on; +SET @@global.wsrep_on=ON; +SELECT @@global.wsrep_on; + +SET @@session.wsrep_on=OFF; +SELECT @@session.wsrep_on; +SET @@session.wsrep_on=ON; +SELECT @@session.wsrep_on; +SET @@session.wsrep_on=default; +SELECT @@session.wsrep_on; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_on=NULL; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_on='junk'; +--error ER_WRONG_VALUE_FOR_VAR +SET @@session.wsrep_on=NULL; +--error ER_WRONG_VALUE_FOR_VAR +SET @@session.wsrep_on='junk'; + +--echo +--echo # restore the initial values +SET @@global.wsrep_on = @wsrep_on_global_saved; +SET @@session.wsrep_on = @wsrep_on_session_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_osu_method_basic.test b/mysql-test/suite/sys_vars/t/wsrep_osu_method_basic.test index 9e1adde76a3..d6d461075a5 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_osu_method_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_osu_method_basic.test @@ -1,18 +1,50 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -set @start_value = @@wsrep_osu_method; +--echo # +--echo # wsrep_osu_method +--echo # -set @@global.wsrep_osu_method='TOI'; -set @@global.wsrep_osu_method='RSU'; -set @@global.wsrep_osu_method=TOI; -set @@global.wsrep_osu_method=RSU; +--echo # save the initial value +SET @wsrep_osu_method_global_saved = @@global.wsrep_osu_method; ---Error 1231 -set @@global.wsrep_osu_method=TSU; ---Error 1231 -set @@global.wsrep_osu_method='TSU'; ---Error 1231 -SET @@global.wsrep_on = -1; +--echo # default +SELECT @@global.wsrep_osu_method; -set @@global.wsrep_osu_method = @start_value; +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_osu_method; +SET @@global.wsrep_osu_method=TOI; +SELECT @@global.wsrep_osu_method; + +--echo +--echo # valid values +SET @@global.wsrep_osu_method=TOI; +SELECT @@global.wsrep_osu_method; +SET @@global.wsrep_osu_method=RSU; +SELECT @@global.wsrep_osu_method; +SET @@global.wsrep_osu_method="RSU"; +SELECT @@global.wsrep_osu_method; +SET @@global.wsrep_osu_method=default; +SELECT @@global.wsrep_osu_method; +# numeric value +SET @@global.wsrep_osu_method=1; +SELECT @@global.wsrep_osu_method; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_osu_method=4; +SELECT @@global.wsrep_osu_method; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_osu_method=NULL; +SELECT @@global.wsrep_osu_method; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_osu_method='junk'; +SELECT @@global.wsrep_osu_method; + +--echo +--echo # restore the initial value +SET @@global.wsrep_osu_method = @wsrep_osu_method_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_provider_basic.test b/mysql-test/suite/sys_vars/t/wsrep_provider_basic.test index aae122c42fe..1190ab41bb0 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_provider_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_provider_basic.test @@ -1,5 +1,39 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -SELECT COUNT(@@GLOBAL.wsrep_provider); ---echo 1 Expected +--echo # +--echo # wsrep_provider +--echo # + +--echo # save the initial value +SET @wsrep_provider_global_saved = @@global.wsrep_provider; + +--echo # default +SELECT @@global.wsrep_provider; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_provider; +SELECT @@global.wsrep_provider; + +--echo +--echo # valid values +SET @@global.wsrep_provider=default; +SELECT @@global.wsrep_provider; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_provider='/invalid/libgalera_smm.so'; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_provider=NULL; +SELECT @@global.wsrep_provider; +--error ER_WRONG_TYPE_FOR_VAR +SET @@global.wsrep_provider=1; +SELECT @@global.wsrep_provider; + +--echo +--echo # restore the initial value +SET @@global.wsrep_provider = @wsrep_provider_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_provider_options_basic.test b/mysql-test/suite/sys_vars/t/wsrep_provider_options_basic.test index e2d8b63b2fd..10ca8298029 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_provider_options_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_provider_options_basic.test @@ -1,5 +1,44 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -SELECT COUNT(@@GLOBAL.wsrep_provider_options); ---echo 1 Expected +--echo # +--echo # wsrep_provider_options +--echo # + +call mtr.add_suppression("WSREP: Failed to get provider options"); + +--echo # save the initial value +SET @wsrep_provider_options_global_saved = @@global.wsrep_provider_options; + +--echo # default +SELECT @@global.wsrep_provider_options; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_provider_options; +SET @@global.wsrep_provider_options='option1'; +SELECT @@global.wsrep_provider_options; + +--echo +--echo # valid values +SET @@global.wsrep_provider_options='name1=value1;name2=value2'; +SELECT @@global.wsrep_provider_options; +SET @@global.wsrep_provider_options='hyphenated-name:value'; +SELECT @@global.wsrep_provider_options; +SET @@global.wsrep_provider_options=default; +SELECT @@global.wsrep_provider_options; + +--echo +--echo # invalid values +--error ER_WRONG_TYPE_FOR_VAR +SET @@global.wsrep_provider_options=1; +SELECT @@global.wsrep_provider_options; +--error ER_WRONG_ARGUMENTS +SET @@global.wsrep_provider_options=NULL; +SELECT @@global.wsrep_provider_options; + +--echo +--echo # restore the initial value +SET @@global.wsrep_provider_options = @wsrep_provider_options_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_recover_basic.test b/mysql-test/suite/sys_vars/t/wsrep_recover_basic.test index f4e1707a434..f935e12e258 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_recover_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_recover_basic.test @@ -1,47 +1,26 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -SELECT COUNT(@@GLOBAL.wsrep_recover); ---echo 1 Expected +--echo # +--echo # wsrep_recover +--echo # ---Error 1238 -set @@global.wsrep_recover=ON; ---echo Expected error 'Readonly variable' ---Error 1238 -set @@global.wsrep_recover=OFF; ---echo Expected error 'Readonly variable' +--echo # default +SELECT @@global.wsrep_recover; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_recover; -SELECT @@GLOBAL.wsrep_recover = VARIABLE_VALUE -FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES -WHERE VARIABLE_NAME='wsrep_recover'; ---echo 1 Expected +--echo +--echo # scope and valid values +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@global.wsrep_recover=OFF; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@global.wsrep_recover=ON; -SELECT COUNT(@@GLOBAL.wsrep_recover); ---echo 1 Expected - -SELECT COUNT(VARIABLE_VALUE) -FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES -WHERE VARIABLE_NAME='wsrep_recover'; ---echo 1 Expected - -SELECT @@wsrep_recover = @@GLOBAL.wsrep_recover; ---echo 1 Expected - -SELECT COUNT(@@wsrep_recover); ---echo 1 Expected - ---Error ER_INCORRECT_GLOBAL_LOCAL_VAR -SELECT COUNT(@@local.wsrep_recover); ---echo Expected error 'Variable is a GLOBAL variable' - ---Error ER_INCORRECT_GLOBAL_LOCAL_VAR -SELECT COUNT(@@SESSION.wsrep_recover); ---echo Expected error 'Variable is a GLOBAL variable' - -SELECT COUNT(@@GLOBAL.wsrep_recover); ---echo 1 Expected - ---Error ER_BAD_FIELD_ERROR -SELECT wsrep_recover = @@SESSION.wsrep_recover; ---echo Expected error 'Readonly variable' +--echo +--echo # invalid values +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@global.wsrep_recover=NULL; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@global.wsrep_recover='junk'; +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_replicate_myisam_basic.test b/mysql-test/suite/sys_vars/t/wsrep_replicate_myisam_basic.test index c03d76b5123..812fb0cfd73 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_replicate_myisam_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_replicate_myisam_basic.test @@ -1,13 +1,36 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -set @start_value = @@wsrep_replicate_myisam; +--echo # +--echo # wsrep_replicate_myisam +--echo # -set @@global.wsrep_replicate_myisam=ON; -set @@global.wsrep_replicate_myisam=OFF; -set @@global.wsrep_replicate_myisam=1; -set @@global.wsrep_replicate_myisam=0; ---Error 1231 -SET @@global.wsrep_replicate_myisam = -1; +--echo # save the initial value +SET @wsrep_replicate_myisam_global_saved = @@global.wsrep_replicate_myisam; -set @@global.wsrep_replicate_myisam = @start_value; \ No newline at end of file +--echo # default +SELECT @@global.wsrep_replicate_myisam; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_replicate_myisam; + +--echo +--echo # scope and valid values +#--error ER_INCORRECT_GLOBAL_LOCAL_VAR +#TODO: check if it is expected for variable to be dynamic? +SET @@global.wsrep_replicate_myisam=OFF; +SELECT @@global.wsrep_replicate_myisam; +#--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@global.wsrep_replicate_myisam=ON; +SELECT @@global.wsrep_replicate_myisam; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_replicate_myisam=NULL; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_replicate_myisam='junk'; + +--echo +--echo # restore the initial value +SET @@global.wsrep_replicate_myisam = @wsrep_replicate_myisam_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_restart_slave_basic.test b/mysql-test/suite/sys_vars/t/wsrep_restart_slave_basic.test index 82f5a97327d..c656111aed6 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_restart_slave_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_restart_slave_basic.test @@ -1,13 +1,36 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -set @start_value = @@wsrep_restart_slave; +--echo # +--echo # wsrep_restart_slave +--echo # -set @@global.wsrep_restart_slave=ON; -set @@global.wsrep_restart_slave=OFF; -set @@global.wsrep_restart_slave=1; -set @@global.wsrep_restart_slave=0; ---Error 1231 -SET @@global.wsrep_restart_slave = -1; +--echo # save the initial value +SET @wsrep_restart_slave_global_saved = @@global.wsrep_restart_slave; -set @@global.wsrep_restart_slave = @start_value; \ No newline at end of file +--echo # default +SELECT @@global.wsrep_restart_slave; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_restart_slave; + +--echo +--echo # scope and valid values +#--error ER_INCORRECT_GLOBAL_LOCAL_VAR +#TODO: check if it is expected for variable to be dynamic? +SET @@global.wsrep_restart_slave=OFF; +SELECT @@global.wsrep_restart_slave; +#--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@global.wsrep_restart_slave=ON; +SELECT @@global.wsrep_restart_slave; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_restart_slave=NULL; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_restart_slave='junk'; + +--echo +--echo # restore the initial value +SET @@global.wsrep_restart_slave = @wsrep_restart_slave_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_retry_autocommit_basic.test b/mysql-test/suite/sys_vars/t/wsrep_retry_autocommit_basic.test index 82f5a97327d..aa6f27f816d 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_retry_autocommit_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_retry_autocommit_basic.test @@ -1,13 +1,52 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -set @start_value = @@wsrep_restart_slave; +--echo # +--echo # wsrep_retry_autocommit +--echo # -set @@global.wsrep_restart_slave=ON; -set @@global.wsrep_restart_slave=OFF; -set @@global.wsrep_restart_slave=1; -set @@global.wsrep_restart_slave=0; ---Error 1231 -SET @@global.wsrep_restart_slave = -1; +--echo # save the initial values +SET @wsrep_retry_autocommit_global_saved = @@global.wsrep_retry_autocommit; +SET @wsrep_retry_autocommit_session_saved = @@session.wsrep_retry_autocommit; -set @@global.wsrep_restart_slave = @start_value; \ No newline at end of file +--echo # default +SELECT @@global.wsrep_retry_autocommit; + +--echo +--echo # scope +SET @@session.wsrep_retry_autocommit=1; +SELECT @@session.wsrep_retry_autocommit; +SET @@global.wsrep_retry_autocommit=1; +SELECT @@global.wsrep_retry_autocommit; + +--echo +--echo # valid values +SET @@global.wsrep_retry_autocommit=10; +SELECT @@global.wsrep_retry_autocommit; +SET @@global.wsrep_retry_autocommit=0; +SELECT @@global.wsrep_retry_autocommit; +SET @@global.wsrep_retry_autocommit=default; +SELECT @global.wsrep_retry_autocommit; + +SET @@session.wsrep_retry_autocommit=10; +SELECT @@session.wsrep_retry_autocommit; +SET @@session.wsrep_retry_autocommit=0; +SELECT @@session.wsrep_retry_autocommit; +SET @@session.wsrep_retry_autocommit=default; +SELECT @session.wsrep_retry_autocommit; + +--echo +--echo # invalid values +--error ER_WRONG_TYPE_FOR_VAR +SET @@global.wsrep_retry_autocommit=NULL; +--error ER_WRONG_TYPE_FOR_VAR +SET @@global.wsrep_retry_autocommit='junk'; +# expect warning : Truncated incorrect wsrep_retry_autocommit value: '-1' +SET @@global.wsrep_retry_autocommit=-1; +SELECT @global.wsrep_retry_autocommit; + +--echo +--echo # restore the initial value +SET @@global.wsrep_retry_autocommit = @wsrep_retry_autocommit_global_saved; +SET @@session.wsrep_retry_autocommit = @wsrep_retry_autocommit_session_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_slave_threads_basic.test b/mysql-test/suite/sys_vars/t/wsrep_slave_threads_basic.test index cff4f433846..80b4648982d 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_slave_threads_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_slave_threads_basic.test @@ -1,16 +1,43 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -set @start_value = @@wsrep_slave_threads; +--echo # +--echo # wsrep_slave_threads +--echo # -set @@global.wsrep_slave_threads=1; -set @@global.wsrep_slave_threads=4; -show warnings; -set @@global.wsrep_slave_threads=0; -show warnings; -set @@global.wsrep_slave_threads=-1; -show warnings; ---Error 1232 -SET @@global.wsrep_slave_threads = r; +--echo # save the initial value +SET @wsrep_slave_threads_global_saved = @@global.wsrep_slave_threads; -set @@global.wsrep_slave_threads = @start_value; \ No newline at end of file +--echo # default +SELECT @@global.wsrep_slave_threads; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_slave_threads; +SET @@global.wsrep_slave_threads=1; +SELECT @@global.wsrep_slave_threads; + +--echo +--echo # valid values +SET @@global.wsrep_slave_threads=10; +SELECT @@global.wsrep_slave_threads; +SET @@global.wsrep_slave_threads=0; +SELECT @@global.wsrep_slave_threads; +SET @@global.wsrep_slave_threads=default; +SELECT @global.wsrep_slave_threads; + +--echo +--echo # invalid values +--error ER_WRONG_TYPE_FOR_VAR +SET @@global.wsrep_slave_threads=NULL; +--error ER_WRONG_TYPE_FOR_VAR +SET @@global.wsrep_slave_threads='junk'; +# expect warning : Truncated incorrect wsrep_slave_threads value: '-1' +SET @@global.wsrep_slave_threads=-1; +SELECT @global.wsrep_slave_threads; + +--echo +--echo # restore the initial value +SET @@global.wsrep_slave_threads = @wsrep_slave_threads_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_sst_auth_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sst_auth_basic.test index 6db2a4cd844..aa901ef9ff7 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_sst_auth_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_sst_auth_basic.test @@ -1,12 +1,45 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -SELECT COUNT(@@wsrep_sst_auth); +--echo # +--echo # wsrep_sst_auth +--echo # -# Cause crash, fix later -#set @start_value = @@wsrep_sst_auth; -#set @@global.wsrep_sst_auth='root:pass'; -#set @@global.wsrep_sst_auth=NULL; -#set @@global.wsrep_sst_auth=r; -#set @@global.wsrep_sst_auth=1; -#set @@global.wsrep_sst_auth = @start_value; +--echo # save the initial value +SET @wsrep_sst_auth_global_saved = @@global.wsrep_sst_auth; + +--echo # default +SELECT @@global.wsrep_sst_auth; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_sst_auth; +SET @@global.wsrep_sst_auth='user:pass'; +SELECT @@global.wsrep_sst_auth; + +--echo +--echo # valid values +SET @@global.wsrep_sst_auth=user; +SELECT @@global.wsrep_sst_auth; +SET @@global.wsrep_sst_auth='user:1234'; +SELECT @@global.wsrep_sst_auth; +SET @@global.wsrep_sst_auth='hyphenated-user-name:'; +SELECT @@global.wsrep_sst_auth; +SET @@global.wsrep_sst_auth=default; +SELECT @@global.wsrep_sst_auth; +SET @@global.wsrep_sst_auth=NULL; +SELECT @@global.wsrep_sst_auth; + +--echo +--echo # invalid values +--error ER_WRONG_TYPE_FOR_VAR +SET @@global.wsrep_sst_auth=1; +SELECT @@global.wsrep_sst_auth; +--error ER_PARSE_ERROR +SET @@global.wsrep_sst_auth=user:pass; + +--echo +--echo # restore the initial value +SET @@global.wsrep_sst_auth = @wsrep_sst_auth_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_sst_donor_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sst_donor_basic.test index 58d005282a0..7d3d6598557 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_sst_donor_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_sst_donor_basic.test @@ -1,12 +1,43 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -SELECT COUNT(@@wsrep_sst_donor); +--echo # +--echo # wsrep_sst_donor +--echo # -set @start_value = @@wsrep_sst_donor; -set @@global.wsrep_sst_donor='foo'; -set @@global.wsrep_sst_donor=NULL; -set @@global.wsrep_sst_donor=r; ---error 1232 -set @@global.wsrep_sst_donor=1; -set @@global.wsrep_sst_donor = @start_value; +--echo # save the initial value +SET @wsrep_sst_donor_global_saved = @@global.wsrep_sst_donor; + +--echo # default +SELECT @@global.wsrep_sst_donor; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_sst_donor; +SET @@global.wsrep_sst_donor=rsync; +SELECT @@global.wsrep_sst_donor; + +--echo +--echo # valid values +SET @@global.wsrep_sst_donor=node1; +SELECT @@global.wsrep_sst_donor; +SET @@global.wsrep_sst_donor='node1,node2'; +SELECT @@global.wsrep_sst_donor; +SET @@global.wsrep_sst_donor='hyphenated-donor-name'; +SELECT @@global.wsrep_sst_donor; +SET @@global.wsrep_sst_donor=default; +SELECT @@global.wsrep_sst_donor; +SET @@global.wsrep_sst_donor=NULL; +SELECT @@global.wsrep_sst_donor; + +--echo +--echo # invalid values +--error ER_WRONG_TYPE_FOR_VAR +SET @@global.wsrep_sst_donor=1; +SELECT @@global.wsrep_sst_donor; + +--echo +--echo # restore the initial value +SET @@global.wsrep_sst_donor = @wsrep_sst_donor_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_sst_donor_rejects_queries_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sst_donor_rejects_queries_basic.test index fc8633ce00f..bd34e23cd2a 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_sst_donor_rejects_queries_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_sst_donor_rejects_queries_basic.test @@ -1,13 +1,42 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -set @start_value = @@wsrep_sst_donor_rejects_queries; +--echo # +--echo # wsrep_sst_donor_rejects_queries +--echo # -set @@global.wsrep_sst_donor_rejects_queries=ON; -set @@global.wsrep_sst_donor_rejects_queries=OFF; -set @@global.wsrep_sst_donor_rejects_queries=1; -set @@global.wsrep_sst_donor_rejects_queries=0; ---Error 1231 -SET @@global.wsrep_sst_donor_rejects_queries = -1; +--echo # save the initial value +SET @wsrep_sst_donor_rejects_queries_global_saved = @@global.wsrep_sst_donor_rejects_queries; -set @@global.wsrep_sst_donor_rejects_queries = @start_value; +--echo # default +SELECT @@global.wsrep_sst_donor_rejects_queries; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_sst_donor_rejects_queries; +SET @@global.wsrep_sst_donor_rejects_queries=OFF; +SELECT @@global.wsrep_sst_donor_rejects_queries; +SET @@global.wsrep_sst_donor_rejects_queries=ON; +SELECT @@global.wsrep_sst_donor_rejects_queries; + +--echo +--echo # valid values +SET @@global.wsrep_sst_donor_rejects_queries='OFF'; +SELECT @@global.wsrep_sst_donor_rejects_queries; +SET @@global.wsrep_sst_donor_rejects_queries=ON; +SELECT @@global.wsrep_sst_donor_rejects_queries; +SET @@global.wsrep_sst_donor_rejects_queries=default; +SELECT @@global.wsrep_sst_donor_rejects_queries; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_sst_donor_rejects_queries=NULL; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_sst_donor_rejects_queries='junk'; + +--echo +--echo # restore the initial value +SET @@global.wsrep_sst_donor_rejects_queries = @wsrep_sst_donor_rejects_queries_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_sst_method_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sst_method_basic.test index dab5831ff01..3f40a3922dd 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_sst_method_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_sst_method_basic.test @@ -1,17 +1,47 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -set @start_value = @@wsrep_sst_method; +--echo # +--echo # wsrep_sst_method +--echo # -set @@global.wsrep_sst_method='xtrabackup'; -set @@global.wsrep_sst_method='xtrabackup-v2'; -set @@global.wsrep_sst_method='rsync'; -set @@global.wsrep_sst_method='mysqldump'; -set @@global.wsrep_sst_method='myscript'; -set @@global.wsrep_sst_method='skip'; ---error 1231 -set @@global.wsrep_sst_method=NULL; ---Error 1232 -SET @@global.wsrep_sst_method = -1; +--echo # save the initial value +SET @wsrep_sst_method_global_saved = @@global.wsrep_sst_method; -set @@global.wsrep_sst_method = @start_value; \ No newline at end of file +--echo # default +SELECT @@global.wsrep_sst_method; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_sst_method; +SET @@global.wsrep_sst_method=rsync; +SELECT @@global.wsrep_sst_method; + +--echo +--echo # valid values +SET @@global.wsrep_sst_method=rsync; +SELECT @@global.wsrep_sst_method; +SET @@global.wsrep_sst_method=mysqldump; +SELECT @@global.wsrep_sst_method; +SET @@global.wsrep_sst_method=xtrabackup; +SELECT @@global.wsrep_sst_method; +SET @@global.wsrep_sst_method="xtrabackup-v2"; +SELECT @@global.wsrep_sst_method; +SET @@global.wsrep_sst_method=default; +SELECT @@global.wsrep_sst_method; + +# Its a valid name for an SST method +SET @@global.wsrep_sst_method='junk'; +SELECT @@global.wsrep_sst_method; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_sst_method=NULL; +SELECT @@global.wsrep_sst_method; + +--echo +--echo # restore the initial value +SET @@global.wsrep_sst_method = @wsrep_sst_method_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_sst_receive_address_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sst_receive_address_basic.test index 0a18098d77f..9e50cbf8947 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_sst_receive_address_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_sst_receive_address_basic.test @@ -1,13 +1,53 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -set @start_value = @@wsrep_sst_receive_address; +--echo # +--echo # wsrep_sst_receive_address +--echo # -set @@global.wsrep_sst_receive_address='128.0.2.1'; -set @@global.wsrep_sst_receive_address=AUTO; -set @@global.wsrep_sst_receive_address='AUTO'; -set @@global.wsrep_sst_receive_address=NULL; ---Error 1232 -SET @@global.wsrep_sst_receive_address = -1; +--echo # save the initial value +SET @wsrep_sst_receive_address_global_saved = @@global.wsrep_sst_receive_address; -set @@global.wsrep_sst_receive_address = @start_value; +--echo # default +SELECT @@global.wsrep_sst_receive_address; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_sst_receive_address; +SELECT @@global.wsrep_sst_receive_address; + +--echo +--echo # valid values +SET @@global.wsrep_sst_receive_address=AUTO; +SELECT @@global.wsrep_sst_receive_address; +SET @@global.wsrep_sst_receive_address=default; +SELECT @@global.wsrep_sst_receive_address; +SET @@global.wsrep_sst_receive_address='192.168.2.254'; +SELECT @@global.wsrep_sst_receive_address; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_sst_receive_address='127.0.0.1:4444'; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_sst_receive_address='127.0.0.1'; +SELECT @@global.wsrep_sst_receive_address; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_sst_receive_address=NULL; +SELECT @@global.wsrep_sst_receive_address; +# Currently there is no strict checking performed for wsrep_sst_receive_address +# so following values jusr pass through. +SET @@global.wsrep_sst_receive_address='OFF'; +SELECT @@global.wsrep_sst_receive_address; +SET @@global.wsrep_sst_receive_address=ON; +SELECT @@global.wsrep_sst_receive_address; +SET @@global.wsrep_sst_receive_address=''; +SELECT @@global.wsrep_sst_receive_address; +SET @@global.wsrep_sst_receive_address='junk'; +SELECT @@global.wsrep_sst_receive_address; + +--echo +--echo # restore the initial value +SET @@global.wsrep_sst_receive_address = @wsrep_sst_receive_address_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_start_position_basic.test b/mysql-test/suite/sys_vars/t/wsrep_start_position_basic.test index 3e30d10c016..3e57cfa6da2 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_start_position_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_start_position_basic.test @@ -1,14 +1,56 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/have_wsrep.inc -set @start_value = @@wsrep_start_position; +--echo # +--echo # wsrep_start_position +--echo # ---error 1231 -set @@global.wsrep_start_position='foo:bar'; ---error 1231 -set @@global.wsrep_start_position=NULL; ---Error 1232 -SET @@global.wsrep_start_position = -1; +--echo # save the initial value +SET @wsrep_start_position_global_saved = @@global.wsrep_start_position; -set @@global.wsrep_start_position = @start_value; +--echo # default +SELECT @@global.wsrep_start_position; +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_start_position; +SET @@global.wsrep_start_position='00000000-0000-0000-0000-000000000000:-1'; +SELECT @@global.wsrep_start_position; + +--echo +--echo # valid values +SET @@global.wsrep_start_position='00000000-0000-0000-0000-000000000000:-2'; +SELECT @@global.wsrep_start_position; +SET @@global.wsrep_start_position='12345678-1234-1234-1234-123456789012:100'; +SELECT @@global.wsrep_start_position; +SET @@global.wsrep_start_position=default; +SELECT @@global.wsrep_start_position; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_start_position='000000000000000-0000-0000-0000-000000000000:-1'; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_start_position='12345678-1234-1234-12345-123456789012:100'; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_start_position='12345678-1234-123-12345-123456789012:0'; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_start_position='12345678-1234-1234-1234-123456789012:_99999'; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_start_position='12345678-1234-1234-1234-123456789012:a'; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_start_position='OFF'; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_start_position=ON; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_start_position=''; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_start_position=NULL; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_start_position='junk'; + +--echo +--echo # restore the initial value +SET @@global.wsrep_start_position = @wsrep_start_position_global_saved; + +--echo # End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_wsrep_provider_basic.test b/mysql-test/suite/sys_vars/t/wsrep_wsrep_provider_basic.test deleted file mode 100644 index f4faaccc6a7..00000000000 --- a/mysql-test/suite/sys_vars/t/wsrep_wsrep_provider_basic.test +++ /dev/null @@ -1,11 +0,0 @@ ---source include/galera_cluster.inc ---source include/have_innodb.inc - -set @start_value = @@wsrep_provider; - -set @@global.wsrep_provider=none; - ---Error 1231 -SET @@global.wsrep_provider = -1; - -set @@global.wsrep_provider = @start_value; From bf30585eaf29139ee471a348fc394162ca3333bd Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Tue, 9 Sep 2014 13:26:23 +0400 Subject: [PATCH 037/153] MDEV-465: Optimizer : wrong index choice: Add a testcase. --- mysql-test/r/order_by.result | 36 +++++++++++++++++++++++++++++++++ mysql-test/t/order_by.test | 39 ++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index 294142737d9..28a276d16c1 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -2949,3 +2949,39 @@ explain update t1 set key1=key1+1 where key1 between 10 and 110 order by key1 li id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range key1 key1 5 NULL 2 Using where; Using buffer drop table t1,t2; +# +# MDEV-465: Optimizer : wrong index choice, leading to strong performances issues +# +CREATE TABLE t1 ( +id1 int(10) unsigned NOT NULL auto_increment, +id2 tinyint(3) unsigned NOT NULL default '0', +id3 tinyint(3) unsigned NOT NULL default '0', +id4 int(10) unsigned NOT NULL default '0', +date timestamp NOT NULL default CURRENT_TIMESTAMP, +PRIMARY KEY (id1), +KEY id_234_date (id2,id3,id4,date), +KEY id_23_date (id2,id3,date) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +# t1 has "bad" index declaration order.. +CREATE TABLE t2 ( +id1 int(10) unsigned NOT NULL auto_increment, +id2 tinyint(3) unsigned NOT NULL default '0', +id3 tinyint(3) unsigned NOT NULL default '0', +id4 int(10) unsigned NOT NULL default '0', +date timestamp NOT NULL default CURRENT_TIMESTAMP, +PRIMARY KEY (id1), +KEY id_23_date (id2,id3,date), +KEY id_234_date (id2,id3,id4,date) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +# t2 has a "good" index declaration order +INSERT INTO t1 (id2,id3,id4) VALUES (1,1,1),(1,1,1),(1,1,1),(1,1,1),(1,0,1),(1,2,1),(1,3,1); +INSERT INTO t2 (id2,id3,id4) VALUES (1,1,1),(1,1,1),(1,1,1),(1,1,1),(1,0,1),(1,2,1),(1,3,1); +# The following two must both use id_23_date and no "using filesort": +EXPLAIN SELECT id1 FROM t1 WHERE id2=1 AND id3=1 ORDER BY date DESC LIMIT 0,4; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range id_234_date,id_23_date id_23_date 2 NULL 3 Using where +# See above query +EXPLAIN SELECT id1 FROM t2 WHERE id2=1 AND id3=1 ORDER BY date DESC LIMIT 0,4; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ref id_23_date,id_234_date id_23_date 2 const,const 3 Using where +drop table t1,t2; diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test index cf6a4d473c3..bdd6f3b825f 100644 --- a/mysql-test/t/order_by.test +++ b/mysql-test/t/order_by.test @@ -1958,3 +1958,42 @@ select A.a + 10 * B.a + 100 * C.a, 1234 from t2 A, t2 B, t2 C; --echo # Should show rows=2, not rows=100 explain update t1 set key1=key1+1 where key1 between 10 and 110 order by key1 limit 2; drop table t1,t2; + +--echo # +--echo # MDEV-465: Optimizer : wrong index choice, leading to strong performances issues +--echo # +CREATE TABLE t1 ( + id1 int(10) unsigned NOT NULL auto_increment, + id2 tinyint(3) unsigned NOT NULL default '0', + id3 tinyint(3) unsigned NOT NULL default '0', + id4 int(10) unsigned NOT NULL default '0', + date timestamp NOT NULL default CURRENT_TIMESTAMP, + PRIMARY KEY (id1), + KEY id_234_date (id2,id3,id4,date), + KEY id_23_date (id2,id3,date) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +--echo # t1 has "bad" index declaration order.. + +CREATE TABLE t2 ( + id1 int(10) unsigned NOT NULL auto_increment, + id2 tinyint(3) unsigned NOT NULL default '0', + id3 tinyint(3) unsigned NOT NULL default '0', + id4 int(10) unsigned NOT NULL default '0', + date timestamp NOT NULL default CURRENT_TIMESTAMP, + PRIMARY KEY (id1), + KEY id_23_date (id2,id3,date), + KEY id_234_date (id2,id3,id4,date) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +--echo # t2 has a "good" index declaration order + +INSERT INTO t1 (id2,id3,id4) VALUES (1,1,1),(1,1,1),(1,1,1),(1,1,1),(1,0,1),(1,2,1),(1,3,1); +INSERT INTO t2 (id2,id3,id4) VALUES (1,1,1),(1,1,1),(1,1,1),(1,1,1),(1,0,1),(1,2,1),(1,3,1); + +--echo # The following two must both use id_23_date and no "using filesort": +EXPLAIN SELECT id1 FROM t1 WHERE id2=1 AND id3=1 ORDER BY date DESC LIMIT 0,4; +--echo # See above query +EXPLAIN SELECT id1 FROM t2 WHERE id2=1 AND id3=1 ORDER BY date DESC LIMIT 0,4; + +drop table t1,t2; + From 6748976d14882bfb6e1261eae635789ee95212a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Tue, 9 Sep 2014 13:35:39 +0300 Subject: [PATCH 038/153] Fix test failure on rpl_statements test by not listing wsrep variable. --- mysql-test/suite/perfschema/r/rpl_statements.result | 2 -- sql/sql_parse.cc | 9 +++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/mysql-test/suite/perfschema/r/rpl_statements.result b/mysql-test/suite/perfschema/r/rpl_statements.result index 211a7d3398d..4e1f03643f1 100644 --- a/mysql-test/suite/perfschema/r/rpl_statements.result +++ b/mysql-test/suite/perfschema/r/rpl_statements.result @@ -14,7 +14,6 @@ include/master-slave.inc show variables like 'binlog_format%'; Variable_name Value binlog_format MIXED -wsrep_forced_binlog_format NONE drop table if exists test.marker; select thread_id into @my_thread_id from performance_schema.threads @@ -59,7 +58,6 @@ Expect 1 show variables like 'binlog_format%'; Variable_name Value binlog_format MIXED -wsrep_forced_binlog_format NONE *** Clear statement events *** Create/drop table, create/drop database diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 741ba08386d..4d6becff599 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3275,10 +3275,11 @@ mysql_execute_command(THD *thd) /* in STATEMENT format, we probably have to replicate also temporary tables, like mysql replication does */ - if (WSREP_ON && (!thd->is_current_stmt_binlog_format_row() || - !(create_info.options & HA_LEX_CREATE_TMP_TABLE))) - WSREP_TO_ISOLATION_BEGIN(create_table->db, create_table->table_name, - NULL) + if (WSREP(thd) && (!thd->is_current_stmt_binlog_format_row() || + !(create_info.options & HA_LEX_CREATE_TMP_TABLE))) + { + WSREP_TO_ISOLATION_BEGIN(create_table->db, create_table->table_name, NULL) + } #endif /* WITH_WSREP */ /* Regular CREATE TABLE */ res= mysql_create_table(thd, create_table, From b67e1d3c98a221feb790a666c3ed7e10e02d9e88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 10 Sep 2014 09:44:57 +0300 Subject: [PATCH 039/153] Adjusted defrag test that fails randomly (timing problem) and fix result of innodb_sys_index test. --- .../r/innodb_defrag_stats_many_tables.result | 14 ++++++++------ .../innodb/t/innodb_defrag_stats_many_tables.test | 12 ++++++++---- mysql-test/suite/percona/innodb_sys_index.result | 3 --- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb_defrag_stats_many_tables.result b/mysql-test/suite/innodb/r/innodb_defrag_stats_many_tables.result index f19e5ddf590..e668c38e059 100644 --- a/mysql-test/suite/innodb/r/innodb_defrag_stats_many_tables.result +++ b/mysql-test/suite/innodb/r/innodb_defrag_stats_many_tables.result @@ -1,8 +1,10 @@ DROP TABLE if exists t1; SET @start_table_definition_cache = @@global.table_definition_cache; SET @@global.table_definition_cache = 400; +SET @start_flush_log_at_trx_commit = @@global.innodb_flush_log_at_trx_commit; +SET @@global.innodb_flush_log_at_trx_commit=2; SET @start_innodb_defragment_stats_accuracy = @@global.innodb_defragment_stats_accuracy; -SET @@global.innodb_defragment_stats_accuracy = 10; +SET @@global.innodb_defragment_stats_accuracy = 80; CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b VARCHAR(256), KEY SECOND(a, b)) ENGINE=INNODB; INSERT INTO t1 VALUES(1, REPEAT('A', 256)); INSERT INTO t1 (b) SELECT b from t1; @@ -18,16 +20,16 @@ INSERT INTO t1 (b) SELECT b from t1; INSERT INTO t1 (b) SELECT b from t1; select stat_value > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name = 'n_page_split'; stat_value > 0 -Create 405 table to overflow the table cache. +Create 505 table to overflow the table cache. Sleep for a while to make sure t1 is evicted. -select sleep(10); -sleep(10) +select sleep(15); +sleep(15) 0 Reload t1 to get defrag stats from persistent storage INSERT INTO t1 (b) SELECT b from t1; make sure the stats thread will wake up and do the write even if there's a race condition between set and reset. -select sleep(12); -sleep(12) +select sleep(15); +sleep(15) 0 select stat_value > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name = 'n_page_split'; stat_value > 0 diff --git a/mysql-test/suite/innodb/t/innodb_defrag_stats_many_tables.test b/mysql-test/suite/innodb/t/innodb_defrag_stats_many_tables.test index 601883c35aa..a0f43fa6841 100644 --- a/mysql-test/suite/innodb/t/innodb_defrag_stats_many_tables.test +++ b/mysql-test/suite/innodb/t/innodb_defrag_stats_many_tables.test @@ -7,14 +7,17 @@ DROP TABLE if exists t1; --enable_warnings -let $num_tables = 405; +let $num_tables = 505; SET @start_table_definition_cache = @@global.table_definition_cache; SET @@global.table_definition_cache = 400; +SET @start_flush_log_at_trx_commit = @@global.innodb_flush_log_at_trx_commit; +SET @@global.innodb_flush_log_at_trx_commit=2; + # set stats accuracy to be pretty high so stats sync is easily triggered. SET @start_innodb_defragment_stats_accuracy = @@global.innodb_defragment_stats_accuracy; -SET @@global.innodb_defragment_stats_accuracy = 10; +SET @@global.innodb_defragment_stats_accuracy = 80; # Create table. CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b VARCHAR(256), KEY SECOND(a, b)) ENGINE=INNODB; @@ -48,13 +51,13 @@ while ($count) } --enable_query_log --echo Sleep for a while to make sure t1 is evicted. -select sleep(10); +select sleep(15); --echo Reload t1 to get defrag stats from persistent storage INSERT INTO t1 (b) SELECT b from t1; --echo make sure the stats thread will wake up and do the write even if there's a race condition between set and reset. -select sleep(12); +select sleep(15); select stat_value > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name = 'n_page_split'; @@ -69,5 +72,6 @@ while ($count) EVAL DROP TABLE t_$count; dec $count; } +set @@global.innodb_flush_log_at_trx_commit = @start_flush_log_at_trx_commit; --enable_query_log DROP TABLE t1; diff --git a/mysql-test/suite/percona/innodb_sys_index.result b/mysql-test/suite/percona/innodb_sys_index.result index 1c4cc63c467..7573720f5ee 100644 --- a/mysql-test/suite/percona/innodb_sys_index.result +++ b/mysql-test/suite/percona/innodb_sys_index.result @@ -1,9 +1,6 @@ drop table if exists t1; Warnings: Note 1051 Unknown table 'test.t1' -select @@version_comment limit 1 ; -@@version_comment -Source distribution, wsrep_25.10.r3991 SELECT COUNT(*) FROM `information_schema`.`INNODB_SYS_INDEXES` ; CREATE TABLE test.t1 ( `a` SERIAL NOT NULL , `b` VARCHAR( 255 ) NOT NULL , INDEX ( `b` ) ) ENGINE = InnoDB ; SHOW TABLE STATUS FROM `information_schema` LIKE 'INNODB\_SYS\_INDEXES%' ; From 595bcb7947716e7b1758ae7c14ef29c5bbb7630e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 10 Sep 2014 18:48:26 +0300 Subject: [PATCH 040/153] Fix merge error on binlog_remove_pending_rows causing failure on binlog_innodb_row test. --- sql/log.h | 9 ++++++++- sql/mysqld.cc | 23 ++++------------------- sql/sql_class.cc | 4 ++-- 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/sql/log.h b/sql/log.h index 3e9a11b8b94..619d7ed19cd 100644 --- a/sql/log.h +++ b/sql/log.h @@ -1083,6 +1083,13 @@ end: DBUG_RETURN(error); } - +static inline TC_LOG *get_tc_log_implementation() +{ + if (total_ha_2pc <= 1) + return &tc_log_dummy; + if (opt_bin_log) + return &mysql_bin_log; + return &tc_log_mmap; +} #endif /* LOG_H */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index b077563918f..0794d7fee61 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5204,27 +5204,12 @@ a file name for --log-bin-index option", opt_binlog_index_name); } #endif - /* if total_ha_2pc <= 1 - tc_log = tc_log_dummy - else - if opt_bin_log == true - tc_log = mysql_bin_log - else - if WITH_WSREP - if WSREP_ON - tc_log = tc_log_dummy - else - tc_log = tc_log_mmap - else - tc_log=tc_log_mmap - */ - tc_log= (total_ha_2pc > 1 ? (opt_bin_log ? - (TC_LOG *) &mysql_bin_log : - IF_WSREP((WSREP_ON ? (TC_LOG *) &tc_log_dummy : - (TC_LOG *) &tc_log_mmap), (TC_LOG *) &tc_log_mmap)) : - (TC_LOG *) &tc_log_dummy); + tc_log= get_tc_log_implementation(); #ifdef WITH_WSREP + if (WSREP_ON && tc_log == &tc_log_mmap) + tc_log= &tc_log_dummy; + WSREP_DEBUG("Initial TC log open: %s", (tc_log == &mysql_bin_log) ? "binlog" : (tc_log == &tc_log_mmap) ? "mmap" : diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 8bceffca0bd..db2638254ec 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -5793,8 +5793,8 @@ int THD::binlog_remove_pending_rows_event(bool clear_maps, { DBUG_ENTER("THD::binlog_remove_pending_rows_event"); - IF_WSREP(!(WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open()), - !mysql_bin_log.is_open()); + if(IF_WSREP(!(WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open()), + !mysql_bin_log.is_open())) DBUG_RETURN(0); /* Ensure that all events in a GTID group are in the same cache */ From 7e2bc140e347ecff90b272a8b2ea9ed1852c5974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 10 Sep 2014 20:19:41 +0300 Subject: [PATCH 041/153] Remove unnecessary debug output causing unnecessary warnings. --- storage/innobase/os/os0file.cc | 5 ----- storage/xtradb/os/os0file.cc | 6 ------ 2 files changed, 11 deletions(-) diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index 971ff14e45c..ea232444af6 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -2365,11 +2365,6 @@ os_file_set_size( current_size = 0; -#ifdef UNIV_DEBUG - fprintf(stderr, "InnoDB: Note: File %s current_size %lu extended_size %lu\n", - name, os_file_get_size(file), size); -#endif - #ifdef HAVE_POSIX_FALLOCATE if (srv_use_posix_fallocate) { diff --git a/storage/xtradb/os/os0file.cc b/storage/xtradb/os/os0file.cc index bec3d1b0080..d67573d14aa 100644 --- a/storage/xtradb/os/os0file.cc +++ b/storage/xtradb/os/os0file.cc @@ -2486,12 +2486,6 @@ os_file_set_size( current_size = 0; -#ifdef UNIV_DEBUG - fprintf(stderr, "InnoDB: Note: File %s current_size %lu extended_size %lu\n", - name, os_file_get_size(file), size); -#endif - - #ifdef HAVE_POSIX_FALLOCATE if (srv_use_posix_fallocate) { From d0a5f33ccd986dfc027ac171b6eed3e92d836012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Thu, 11 Sep 2014 07:10:37 +0300 Subject: [PATCH 042/153] Remove incorrect test file. --- .../wsrep/r/innodb_load_xa_with_wsrep.result | 19 ------------------- .../wsrep/t/innodb_load_xa_with_wsrep.opt | 1 - .../wsrep/t/innodb_load_xa_with_wsrep.test | 19 ------------------- 3 files changed, 39 deletions(-) delete mode 100644 mysql-test/suite/wsrep/r/innodb_load_xa_with_wsrep.result delete mode 100644 mysql-test/suite/wsrep/t/innodb_load_xa_with_wsrep.opt delete mode 100644 mysql-test/suite/wsrep/t/innodb_load_xa_with_wsrep.test diff --git a/mysql-test/suite/wsrep/r/innodb_load_xa_with_wsrep.result b/mysql-test/suite/wsrep/r/innodb_load_xa_with_wsrep.result deleted file mode 100644 index 90faf766145..00000000000 --- a/mysql-test/suite/wsrep/r/innodb_load_xa_with_wsrep.result +++ /dev/null @@ -1,19 +0,0 @@ -install plugin innodb soname 'ha_innodb'; -select engine,support,transactions,xa from information_schema.engines where engine='innodb'; -engine support transactions xa -InnoDB YES YES YES -create table t1 (a int) engine=innodb; -start transaction; -insert t1 values (1); -insert t1 values (2); -commit; -include/show_binlog_events.inc -Log_name Pos Event_type Server_id End_log_pos Info -mysqld-bin.000001 # Gtid # # GTID #-#-# -mysqld-bin.000001 # Query # # use `test`; create table t1 (a int) engine=innodb -mysqld-bin.000001 # Gtid # # BEGIN GTID #-#-# -mysqld-bin.000001 # Query # # use `test`; insert t1 values (1) -mysqld-bin.000001 # Query # # use `test`; insert t1 values (2) -mysqld-bin.000001 # Xid # # COMMIT /* XID */ -drop table t1; -uninstall plugin innodb; diff --git a/mysql-test/suite/wsrep/t/innodb_load_xa_with_wsrep.opt b/mysql-test/suite/wsrep/t/innodb_load_xa_with_wsrep.opt deleted file mode 100644 index 4ff27e659ce..00000000000 --- a/mysql-test/suite/wsrep/t/innodb_load_xa_with_wsrep.opt +++ /dev/null @@ -1 +0,0 @@ ---ignore-builtin-innodb --loose-innodb --log-bin diff --git a/mysql-test/suite/wsrep/t/innodb_load_xa_with_wsrep.test b/mysql-test/suite/wsrep/t/innodb_load_xa_with_wsrep.test deleted file mode 100644 index 413faf54864..00000000000 --- a/mysql-test/suite/wsrep/t/innodb_load_xa_with_wsrep.test +++ /dev/null @@ -1,19 +0,0 @@ -# -# MDEV-6082 Assertion `0' fails in TC_LOG_DUMMY::log_and_order on DML after installing TokuDB at runtime on server with disabled InnoDB -# ---source include/not_embedded.inc ---source include/have_wsrep.inc - -if (!$HA_INNODB_SO) { - --skip Need InnoDB plugin -} -install plugin innodb soname 'ha_innodb'; -select engine,support,transactions,xa from information_schema.engines where engine='innodb'; -create table t1 (a int) engine=innodb; -start transaction; -insert t1 values (1); -insert t1 values (2); -commit; ---source include/show_binlog_events.inc -drop table t1; -uninstall plugin innodb; From 8aa88db3c2f39cadeb8960f514d27cc7f071dcac Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Fri, 12 Sep 2014 02:19:49 +0400 Subject: [PATCH 043/153] MDEV-6402: Optimizer doesn't choose best execution plan when composite... Fix test_if_skip_sort_order() logic: WHEN we use index X, which doesn't produce needed ordering, but there is an index Y which does and has the same prefix as used prefix of X THEN don't just switch to using ref access on Y. If range(Y) would use more key parts, use range(Y). --- mysql-test/r/order_by_optimizer_innodb.result | 48 +++++++++++ mysql-test/t/order_by_optimizer_innodb.test | 43 ++++++++++ sql/sql_select.cc | 86 +++++++++++++------ 3 files changed, 149 insertions(+), 28 deletions(-) create mode 100644 mysql-test/r/order_by_optimizer_innodb.result create mode 100644 mysql-test/t/order_by_optimizer_innodb.test diff --git a/mysql-test/r/order_by_optimizer_innodb.result b/mysql-test/r/order_by_optimizer_innodb.result new file mode 100644 index 00000000000..212139a287e --- /dev/null +++ b/mysql-test/r/order_by_optimizer_innodb.result @@ -0,0 +1,48 @@ +drop table if exists t0,t1,t2,t3; +# +# MDEV-6402: Optimizer doesn't choose best execution plan when composite key is used +# +create table t0(a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1(a int); +insert into t1 select A.a + B.a* 10 + C.a * 100 from t0 A, t0 B, t0 C; +CREATE TABLE t2 ( +pk1 int(11) NOT NULL, +pk2 int(11) NOT NULL, +fd5 bigint(20) DEFAULT NULL, +filler1 char(200), +filler2 char(200), +PRIMARY KEY (pk1,pk2), +UNIQUE KEY ux_pk1_fd5 (pk1,fd5) +) ENGINE=InnoDB; +insert into t2 +select +round(log(2,t1.a+1)), +t1.a, +t1.a, +REPEAT('filler-data-', 10), +REPEAT('filler-data-', 10) +from +t1; +select pk1, count(*) from t2 group by pk1; +pk1 count(*) +0 1 +1 1 +2 3 +3 6 +4 11 +5 23 +6 45 +7 91 +8 181 +9 362 +10 276 +# The following should use range(ux_pk1_fd5), two key parts (key_len=5+8=13) +EXPLAIN SELECT * FROM t2 USE INDEX(ux_pk1_fd5) WHERE pk1=9 AND fd5 < 500 ORDER BY fd5 DESC LIMIT 10; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range ux_pk1_fd5 ux_pk1_fd5 13 NULL 137 Using where +# This also must use range, not ref. key_len must be 13 +EXPLAIN SELECT * FROM t2 WHERE pk1=9 AND fd5 < 500 ORDER BY fd5 DESC LIMIT 10; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range PRIMARY,ux_pk1_fd5 ux_pk1_fd5 13 NULL 137 Using where +drop table t0,t1, t2; diff --git a/mysql-test/t/order_by_optimizer_innodb.test b/mysql-test/t/order_by_optimizer_innodb.test new file mode 100644 index 00000000000..d3c71e8772f --- /dev/null +++ b/mysql-test/t/order_by_optimizer_innodb.test @@ -0,0 +1,43 @@ +--source include/have_innodb.inc + +--disable_warnings +drop table if exists t0,t1,t2,t3; +--enable_warnings + +--echo # +--echo # MDEV-6402: Optimizer doesn't choose best execution plan when composite key is used +--echo # +create table t0(a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); + +create table t1(a int); +insert into t1 select A.a + B.a* 10 + C.a * 100 from t0 A, t0 B, t0 C; + +CREATE TABLE t2 ( + pk1 int(11) NOT NULL, + pk2 int(11) NOT NULL, + fd5 bigint(20) DEFAULT NULL, + filler1 char(200), + filler2 char(200), + PRIMARY KEY (pk1,pk2), + UNIQUE KEY ux_pk1_fd5 (pk1,fd5) + ) ENGINE=InnoDB; + +insert into t2 +select + round(log(2,t1.a+1)), + t1.a, + t1.a, + REPEAT('filler-data-', 10), + REPEAT('filler-data-', 10) +from + t1; + +select pk1, count(*) from t2 group by pk1; + +--echo # The following should use range(ux_pk1_fd5), two key parts (key_len=5+8=13) +EXPLAIN SELECT * FROM t2 USE INDEX(ux_pk1_fd5) WHERE pk1=9 AND fd5 < 500 ORDER BY fd5 DESC LIMIT 10; +--echo # This also must use range, not ref. key_len must be 13 +EXPLAIN SELECT * FROM t2 WHERE pk1=9 AND fd5 < 500 ORDER BY fd5 DESC LIMIT 10; + +drop table t0,t1, t2; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9c87ddcc4b4..442f8536fb6 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -19868,7 +19868,12 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts, uint best= MAX_KEY; KEY_PART_INFO *ref_key_part= table->key_info[ref].key_part; KEY_PART_INFO *ref_key_part_end= ref_key_part + ref_key_parts; - + + /* + Find the shortest key that + - produces the required ordering + - has key #ref (up to ref_key_parts) as its subkey. + */ for (nr= 0 ; nr < table->s->keys ; nr++) { if (usable_keys->is_set(nr) && @@ -20061,7 +20066,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, been taken into account. */ usable_keys= *map; - + + /* Find indexes that cover all ORDER/GROUP BY fields */ for (ORDER *tmp_order=order; tmp_order ; tmp_order=tmp_order->next) { Item *item= (*tmp_order->item)->real_item(); @@ -20081,6 +20087,10 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, { ref_key= tab->ref.key; ref_key_parts= tab->ref.key_parts; + /* + todo: why does JT_REF_OR_NULL mean filesort? We could find another index + that satisfies the ordering. I would just set ref_key=MAX_KEY here... + */ if (tab->type == JT_REF_OR_NULL || tab->type == JT_FT) goto use_filesort; } @@ -20107,15 +20117,12 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, if (ref_key >= 0 && ref_key != MAX_KEY) { - /* - We come here when there is a REF key. - */ + /* Current access method uses index ref_key with ref_key_parts parts */ if (!usable_keys.is_set(ref_key)) { - /* - We come here when ref_key is not among usable_keys - */ + /* However, ref_key doesn't match the needed ordering */ uint new_ref_key; + /* If using index only read, only consider other possible index only keys @@ -20131,27 +20138,23 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, if ((new_ref_key= test_if_subkey(order, table, ref_key, ref_key_parts, &usable_keys)) < MAX_KEY) { - if (tab->ref.key >= 0) - { - /* - We'll use ref access method on key new_ref_key. In general case - the index search tuple for new_ref_key will be different (e.g. - when one index is defined as (part1, part2, ...) and another as - (part1, part2(N), ...) and the WHERE clause contains - "part1 = const1 AND part2=const2". - So we build tab->ref from scratch here. - */ - KEYUSE *keyuse= tab->keyuse; - while (keyuse->key != new_ref_key && keyuse->table == tab->table) - keyuse++; - if (create_ref_for_key(tab->join, tab, keyuse, FALSE, - (tab->join->const_table_map | - OUTER_REF_TABLE_BIT))) - goto use_filesort; + /* + Index new_ref_key + - produces the required ordering, + - also has the same columns as ref_key for #ref_key_parts (this + means we will read the same number of rows as with ref_key). + */ - pick_table_access_method(tab); - } - else + /* + If new_ref_key allows to construct a quick select which uses more key + parts than ref(new_ref_key) would, do that. + + Otherwise, construct a ref access (todo: it's not clear what is the + win in using ref access when we could use quick select also?) + */ + if ((table->quick_keys.is_set(new_ref_key) && + table->quick_key_parts[new_ref_key] > ref_key_parts) || + !(tab->ref.key >= 0)) { /* The range optimizer constructed QUICK_RANGE for ref_key, and @@ -20183,12 +20186,39 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, select->cond= save_cond; goto use_filesort; } + DBUG_ASSERT(tab->select->quick); + tab->type= JT_ALL; + tab->ref.key= -1; + tab->ref.key_parts= 0; + tab->use_quick= 1; /* We don't restore select->cond as we want to use the original condition as index condition pushdown is not active for the new index. + todo: why not perform index condition pushdown for the new index? */ } + else + { + /* + We'll use ref access method on key new_ref_key. In general case + the index search tuple for new_ref_key will be different (e.g. + when one index is defined as (part1, part2, ...) and another as + (part1, part2(N), ...) and the WHERE clause contains + "part1 = const1 AND part2=const2". + So we build tab->ref from scratch here. + */ + KEYUSE *keyuse= tab->keyuse; + while (keyuse->key != new_ref_key && keyuse->table == tab->table) + keyuse++; + if (create_ref_for_key(tab->join, tab, keyuse, FALSE, + (tab->join->const_table_map | + OUTER_REF_TABLE_BIT))) + goto use_filesort; + + pick_table_access_method(tab); + } + ref_key= new_ref_key; changed_key= true; } From f5d845426eb38f0b5641c30d0d3a56c2b6a2b6a0 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Wed, 24 Sep 2014 11:56:22 +0400 Subject: [PATCH 044/153] Better comments --- sql/sql_select.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9c87ddcc4b4..e7424b4a318 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -24706,6 +24706,11 @@ void JOIN::cache_const_exprs() - if there is a ref(const) access, we try to use it, too. - quick and ref(const) use different cost formulas, so if both are possible we should make a cost-based choice. + + @param tab JOIN_TAB with table access (is NULL for single-table + UPDATE/DELETE) + @param read_time OUT Cost of reading using quick or ref(const) access. + @return true There was a possible quick or ref access, its cost is in the OUT From 3f2d9a902ec93327515ae94ae0c8c0c2c485d15f Mon Sep 17 00:00:00 2001 From: Monty Date: Wed, 24 Sep 2014 23:52:17 +0300 Subject: [PATCH 045/153] Fixed failing test temp_table_frm The problem was that the internal temporary table created for information_schema overflow to MyISAM because it has a row width of > 3000 characters, which filled the in memory temporary tables. Fix was to increase size for the heap table. --- mysql-test/r/temp_table_frm.result | 1 + mysql-test/t/temp_table_frm.test | 3 +++ 2 files changed, 4 insertions(+) diff --git a/mysql-test/r/temp_table_frm.result b/mysql-test/r/temp_table_frm.result index ff809957a3d..4f60ccc32c8 100644 --- a/mysql-test/r/temp_table_frm.result +++ b/mysql-test/r/temp_table_frm.result @@ -1,3 +1,4 @@ +set @@session.max_heap_table_size=16*1024*1024; create table t1 select * from information_schema.session_status where variable_name like 'Opened%'; create temporary table t2 (a int) engine=memory; select variable_name, session_status.variable_value - t1.variable_value diff --git a/mysql-test/t/temp_table_frm.test b/mysql-test/t/temp_table_frm.test index f78de71a756..178bd15004b 100644 --- a/mysql-test/t/temp_table_frm.test +++ b/mysql-test/t/temp_table_frm.test @@ -1,6 +1,9 @@ # # MDEV-4260 Don't create frm files for temporary tables # + +# Ensure we don't overflow the internal heap table size in the join +set @@session.max_heap_table_size=16*1024*1024; create table t1 select * from information_schema.session_status where variable_name like 'Opened%'; create temporary table t2 (a int) engine=memory; select variable_name, session_status.variable_value - t1.variable_value From e74bf0798297551bc02e6d8cac76e0d13ffdad0e Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Thu, 25 Sep 2014 14:29:14 +0400 Subject: [PATCH 046/153] Better comments --- sql/sql_select.cc | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index e7424b4a318..8a7cb9cdafa 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -25224,15 +25224,18 @@ uint get_index_for_order(ORDER *order, TABLE *table, SQL_SELECT *select, return MAX_KEY; } + /* - Count how much times conditions are true for several first rows of the table + Count how many times the specified conditions are true for first rows_to_read + rows of the table. - @param thd thread handle - @param rows_to_read how much rows to check - @param table table which should be checked - @conds conds list of conditions and countars for them + @param thd Thread handle + @param rows_to_read How many rows to sample + @param table Table to use + @conds conds INOUT List of conditions and counters for them - @return number of really checked rows or 0 in case of error or empty table + @return Number of we've checked. It can be equal or less than rows_to_read. + 0 is returned for error or when the table had no rows. */ ulong check_selectivity(THD *thd, From 532334cb11835d18f2705ecfd014659b4a2e8252 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Thu, 25 Sep 2014 18:27:20 +0400 Subject: [PATCH 047/153] MDEV-6788: The variable 'role' is being used without being initialized at sql_acl.cc:8840 [Re-commit in git] Don't check the value of 'role' variable in the cases where we don't need it. (it may be marked as uninitialized and we get a runtime error). --- sql/sql_acl.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index e67a019d1f7..258522329d2 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -8687,7 +8687,7 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop, int elements; const char *UNINIT_VAR(user); const char *UNINIT_VAR(host); - const char *UNINIT_VAR(role); + const char *role; ACL_USER *acl_user= NULL; ACL_ROLE *acl_role= NULL; ACL_DB *acl_db= NULL; @@ -8837,8 +8837,6 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop, user= ""; if (! host) host= ""; - if (! role) - role= ""; #ifdef EXTRA_DEBUG DBUG_PRINT("loop",("scan struct: %u index: %u user: '%s' host: '%s'", @@ -8847,6 +8845,8 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop, if (struct_no == ROLES_MAPPINGS_HASH) { + if (! role) + role= ""; if (user_from->is_role() ? strcmp(user_from->user.str, role) : (strcmp(user_from->user.str, user) || my_strcasecmp(system_charset_info, user_from->host.str, host))) From 30fab5fb511ac29dcaef1f17a653f461ab32f029 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Thu, 25 Sep 2014 19:14:16 +0400 Subject: [PATCH 048/153] MDEV-6788: The variable 'role' is being used without being initialized at sql_acl.cc:8840 [re-commit in git] Second variant of the fix: reduce the scope of 'role' variable --- sql/sql_acl.cc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 258522329d2..bae2d15ba20 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -8687,7 +8687,6 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop, int elements; const char *UNINIT_VAR(user); const char *UNINIT_VAR(host); - const char *role; ACL_USER *acl_user= NULL; ACL_ROLE *acl_role= NULL; ACL_DB *acl_db= NULL; @@ -8827,7 +8826,6 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop, role_grant_pair= (ROLE_GRANT_PAIR *) my_hash_element(roles_mappings_hash, idx); user= role_grant_pair->u_uname; host= role_grant_pair->u_hname; - role= role_grant_pair->r_uname; break; default: @@ -8845,8 +8843,7 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop, if (struct_no == ROLES_MAPPINGS_HASH) { - if (! role) - role= ""; + const char* role= role_grant_pair->r_uname? role_grant_pair->r_uname: ""; if (user_from->is_role() ? strcmp(user_from->user.str, role) : (strcmp(user_from->user.str, user) || my_strcasecmp(system_charset_info, user_from->host.str, host))) From a28c9a5857dc47b74aa739e814fafb9aa7dade6d Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Thu, 25 Sep 2014 11:46:52 -0400 Subject: [PATCH 049/153] MDEV-6790: 10.1: debian build failure Updated 33_scripts__mysql_create_system_tables__no_test.dpatch to reflect user.default_role. --- .../33_scripts__mysql_create_system_tables__no_test.dpatch | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/debian/patches/33_scripts__mysql_create_system_tables__no_test.dpatch b/debian/patches/33_scripts__mysql_create_system_tables__no_test.dpatch index 7ce692a96b0..0beaecec833 100755 --- a/debian/patches/33_scripts__mysql_create_system_tables__no_test.dpatch +++ b/debian/patches/33_scripts__mysql_create_system_tables__no_test.dpatch @@ -28,9 +28,9 @@ -- from local machine if "user" table didn't exist before CREATE TEMPORARY TABLE tmp_user LIKE user; @@ -43,8 +33,6 @@ INSERT INTO tmp_user VALUES ('localhost' - REPLACE INTO tmp_user SELECT @current_hostname,'root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N','N' FROM dual WHERE @current_hostname != 'localhost'; - REPLACE INTO tmp_user VALUES ('127.0.0.1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N','N'); - REPLACE INTO tmp_user VALUES ('::1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N','N'); + REPLACE INTO tmp_user SELECT @current_hostname,'root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N','N','' FROM dual WHERE @current_hostname != 'localhost'; + REPLACE INTO tmp_user VALUES ('127.0.0.1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N','N', ''); + REPLACE INTO tmp_user VALUES ('::1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N','N', ''); -INSERT INTO tmp_user (host,user) VALUES ('localhost',''); -INSERT INTO tmp_user (host,user) SELECT @current_hostname,'' FROM dual WHERE @current_hostname != 'localhost'; INSERT INTO user SELECT * FROM tmp_user WHERE @had_user_table=0; From d6a67ce080aaf4238cd531dac83633005d7fbb46 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Thu, 25 Sep 2014 13:32:55 -0400 Subject: [PATCH 050/153] Fix for syntax error in debian control file. --- debian/dist/Debian/control | 2 +- debian/dist/Ubuntu/control | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/dist/Debian/control b/debian/dist/Debian/control index 869e9be032c..5fd6b1eac16 100644 --- a/debian/dist/Debian/control +++ b/debian/dist/Debian/control @@ -192,7 +192,7 @@ Architecture: any Suggests: tinyca, mailx, mariadb-test Recommends: libhtml-template-perl Pre-Depends: mariadb-common, adduser (>= 3.40), debconf -Depends: mariadb-client-10.1 (>= ${source:Version}), libdbi-perl, perl (>= 5.6), ${shlibs:Depends}, ${misc:Depends}, psmisc, passwd, lsb-base (>= 3.0-10), mariadb-server-core-10.1 (>= ${binary:Version}), galera (>=25.2) rsync, lsof, socat, grep, gawk, iproute, coreutils, findutils +Depends: mariadb-client-10.1 (>= ${source:Version}), libdbi-perl, perl (>= 5.6), ${shlibs:Depends}, ${misc:Depends}, psmisc, passwd, lsb-base (>= 3.0-10), mariadb-server-core-10.1 (>= ${binary:Version}), galera (>=25.2), rsync, lsof, socat, grep, gawk, iproute, coreutils, findutils Provides: mariadb-server, mysql-server, virtual-mysql-server Conflicts: mariadb-server (<< ${source:Version}), mysql-server (<< ${source:Version}), mysql-server-4.1, mysql-server-5.0, mysql-server-5.1, mysql-server-5.5, diff --git a/debian/dist/Ubuntu/control b/debian/dist/Ubuntu/control index 941f756ea3c..c5f417d121b 100644 --- a/debian/dist/Ubuntu/control +++ b/debian/dist/Ubuntu/control @@ -186,7 +186,7 @@ Architecture: any Suggests: tinyca, mailx, mariadb-test Recommends: libhtml-template-perl Pre-Depends: mariadb-common, adduser (>= 3.40), debconf -Depends: mariadb-client-10.1 (>= ${source:Version}), libdbi-perl, perl (>= 5.6), ${shlibs:Depends}, ${misc:Depends}, psmisc, passwd, lsb-base (>= 3.0-10), mariadb-server-core-10.1 (>= ${binary:Version}), galera (>=25.2) rsync, lsof, socat, grep, gawk, iproute, coreutils, findutils +Depends: mariadb-client-10.1 (>= ${source:Version}), libdbi-perl, perl (>= 5.6), ${shlibs:Depends}, ${misc:Depends}, psmisc, passwd, lsb-base (>= 3.0-10), mariadb-server-core-10.1 (>= ${binary:Version}), galera (>=25.2), rsync, lsof, socat, grep, gawk, iproute, coreutils, findutils Provides: mariadb-server, mysql-server, virtual-mysql-server Conflicts: mariadb-server (<< ${source:Version}), mysql-server (<< ${source:Version}), mysql-server-4.1, mysql-server-5.0, mysql-server-5.1, mysql-server-5.5, From 98c95ff1e23452395aa58eabf9346d8d1f234000 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Thu, 25 Sep 2014 22:12:18 +0400 Subject: [PATCH 051/153] Better comments about KEY::ext_key_part_map --- sql/structs.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/sql/structs.h b/sql/structs.h index 2de7abb666d..da8d4beb754 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -93,7 +93,19 @@ typedef struct st_key { uint usable_key_parts; /* Should normally be = user_defined_key_parts */ uint ext_key_parts; /* Number of key parts in extended key */ ulong ext_key_flags; /* Flags for extended key */ - key_part_map ext_key_part_map; /* Bitmap of pk key parts in extension */ + /* + Parts of primary key that are in the extension of this index. + + Example: if this structure describes idx1, which is defined as + INDEX idx1 (pk2, col2) + and pk is defined as: + PRIMARY KEY (pk1, pk2) + then + pk1 is in the extension idx1, ext_key_part_map.is_set(0) == true + pk2 is explicitly present in idx1, it is not in the extension, so + ext_key_part_map.is_set(1) == false + */ + key_part_map ext_key_part_map; uint block_size; uint name_length; enum ha_key_alg algorithm; From 236cc6cd49f250a43f0f6a794d5052207b2d9348 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Thu, 25 Sep 2014 20:59:15 -0400 Subject: [PATCH 052/153] wsrep-related changes: removed some unnecessary files & minor modifications. --- cmake/wsrep.cmake | 5 +- debian/additions/my.cnf | 16 +- scripts/wsrep_sst_common | 157 ------ scripts/wsrep_sst_mysqldump | 131 ----- scripts/wsrep_sst_rsync | 335 ----------- scripts/wsrep_sst_xtrabackup | 715 ------------------------ scripts/wsrep_sst_xtrabackup-v2 | 930 ------------------------------- support-files/CMakeLists.txt | 3 +- support-files/mysql.server.sh | 5 +- support-files/rpm/server.cnf | 2 +- support-files/wsrep.cnf | 129 ----- support-files/wsrep.cnf.sh.moved | 129 ----- support-files/wsrep_notify | 102 ---- 13 files changed, 21 insertions(+), 2638 deletions(-) delete mode 100755 scripts/wsrep_sst_common delete mode 100755 scripts/wsrep_sst_mysqldump delete mode 100755 scripts/wsrep_sst_rsync delete mode 100755 scripts/wsrep_sst_xtrabackup delete mode 100755 scripts/wsrep_sst_xtrabackup-v2 delete mode 100644 support-files/wsrep.cnf delete mode 100644 support-files/wsrep.cnf.sh.moved delete mode 100644 support-files/wsrep_notify diff --git a/cmake/wsrep.cmake b/cmake/wsrep.cmake index 7dc797e9a05..d3c8da6a72a 100644 --- a/cmake/wsrep.cmake +++ b/cmake/wsrep.cmake @@ -14,14 +14,11 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -# We need to generate a proper spec file even without --with-wsrep flag, -# so WSREP_VERSION is produced regardless - # Set the patch version SET(WSREP_PATCH_VERSION "10") # MariaDB addition: Revision number of the last revision merged from -# codership branch visible in @@visible_comment. +# codership branch visible in @@version_comment. # Branch : codership-mysql/5.6 SET(WSREP_PATCH_REVNO "4123") # Should be updated on every merge. diff --git a/debian/additions/my.cnf b/debian/additions/my.cnf index a27f8543f0b..1e0b97bf0b7 100644 --- a/debian/additions/my.cnf +++ b/debian/additions/my.cnf @@ -151,7 +151,21 @@ innodb_flush_method = O_DIRECT # ssl-cert=/etc/mysql/server-cert.pem # ssl-key=/etc/mysql/server-key.pem - +# +# * Galera-related settings +# +[galera] +# Mandatory settings +#wsrep_provider= +#wsrep_cluster_address= +#wsrep_slave_threads=1 +#binlog_format=row +#default_storage_engine=InnoDB +#innodb_autoinc_lock_mode=2 +#bind-address=0.0.0.0 +# +# Optional setting +#innodb_flush_log_at_trx_commit=0 [mysqldump] quick diff --git a/scripts/wsrep_sst_common b/scripts/wsrep_sst_common deleted file mode 100755 index 88f5d80f53a..00000000000 --- a/scripts/wsrep_sst_common +++ /dev/null @@ -1,157 +0,0 @@ -# Copyright (C) 2012-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 -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; see the file COPYING. If not, write to the -# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston -# MA 02110-1301 USA. - -# This is a common command line parser to be sourced by other SST scripts - -set -u - -WSREP_SST_OPT_BYPASS=0 -WSREP_SST_OPT_BINLOG="" -WSREP_SST_OPT_DATA="" -WSREP_SST_OPT_AUTH="" - -while [ $# -gt 0 ]; do -case "$1" in - '--address') - readonly WSREP_SST_OPT_ADDR="$2" - shift - ;; - '--auth') - WSREP_SST_OPT_AUTH="$2" - shift - ;; - '--bypass') - WSREP_SST_OPT_BYPASS=1 - ;; - '--datadir') - readonly WSREP_SST_OPT_DATA="$2" - shift - ;; - '--defaults-file') - readonly WSREP_SST_OPT_CONF="$2" - shift - ;; - '--host') - readonly WSREP_SST_OPT_HOST="$2" - shift - ;; - '--local-port') - readonly WSREP_SST_OPT_LPORT="$2" - shift - ;; - '--parent') - readonly WSREP_SST_OPT_PARENT="$2" - shift - ;; - '--password') - WSREP_SST_OPT_PSWD="$2" - shift - ;; - '--port') - readonly WSREP_SST_OPT_PORT="$2" - shift - ;; - '--role') - readonly WSREP_SST_OPT_ROLE="$2" - shift - ;; - '--socket') - readonly WSREP_SST_OPT_SOCKET="$2" - shift - ;; - '--user') - WSREP_SST_OPT_USER="$2" - shift - ;; - '--gtid') - readonly WSREP_SST_OPT_GTID="$2" - shift - ;; - '--binlog') - WSREP_SST_OPT_BINLOG="$2" - shift - ;; - *) # must be command - # usage - # exit 1 - ;; -esac -shift -done -readonly WSREP_SST_OPT_BYPASS -readonly WSREP_SST_OPT_BINLOG - -# State Snapshot Transfer authentication password was displayed in the ps output. Bug fixed #1200727. -if my_print_defaults -c $WSREP_SST_OPT_CONF sst | grep -q "wsrep_sst_auth";then - if [ -z "$WSREP_SST_OPT_AUTH" -o "$WSREP_SST_OPT_AUTH" = "(null)" ];then - WSREP_SST_OPT_AUTH=$(my_print_defaults -c $WSREP_SST_OPT_CONF sst | grep -- "--wsrep_sst_auth" | cut -d= -f2) - fi -fi - -if [ -n "${WSREP_SST_OPT_DATA:-}" ] -then - SST_PROGRESS_FILE="$WSREP_SST_OPT_DATA/sst_in_progress" -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 "$tst WSREP_SST: " >&2 -} - -wsrep_log_error() -{ - wsrep_log "[ERROR] $*" -} - -wsrep_log_info() -{ - wsrep_log "[INFO] $*" -} - -wsrep_cleanup_progress_file() -{ - [ -n "$SST_PROGRESS_FILE" ] && rm -f "$SST_PROGRESS_FILE" 2>/dev/null -} - -wsrep_check_program() -{ - local prog=$1 - - if ! which $prog >/dev/null - then - echo "'$prog' not found in PATH" - return 2 # no such file or directory - fi -} - -wsrep_check_programs() -{ - local ret=0 - - while [ $# -gt 0 ] - do - wsrep_check_program $1 || ret=$? - shift - done - - return $ret -} diff --git a/scripts/wsrep_sst_mysqldump b/scripts/wsrep_sst_mysqldump deleted file mode 100755 index d4093dbcaef..00000000000 --- a/scripts/wsrep_sst_mysqldump +++ /dev/null @@ -1,131 +0,0 @@ -#!/bin/bash -e -# Copyright (C) 2009 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 -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; see the file COPYING. If not, write to the -# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston -# MA 02110-1301 USA. - -# This is a reference script for mysqldump-based state snapshot tansfer - -# This variable is not used in mysqldump sst, so better initialize it -# to avoid shell's "parameter not set" message. -WSREP_SST_OPT_CONF="" - -. $(dirname $0)/wsrep_sst_common - -EINVAL=22 -PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin - -local_ip() -{ - [ "$1" = "127.0.0.1" ] && return 0 - [ "$1" = "localhost" ] && return 0 - [ "$1" = "$(hostname -s)" ] && return 0 - [ "$1" = "$(hostname -f)" ] && return 0 - [ "$1" = "$(hostname -d)" ] && return 0 - - # Now if ip program is not found in the path, we can't return 0 since - # it would block any address. Thankfully grep should fail in this case - ip route get "$1" | grep local >/dev/null && return 0 - - return 1 -} - -if test -z "$WSREP_SST_OPT_USER"; then wsrep_log_error "USER cannot be nil"; exit $EINVAL; fi -if test -z "$WSREP_SST_OPT_HOST"; then wsrep_log_error "HOST cannot be nil"; exit $EINVAL; fi -if test -z "$WSREP_SST_OPT_PORT"; then wsrep_log_error "PORT cannot be nil"; exit $EINVAL; fi -if test -z "$WSREP_SST_OPT_LPORT"; then wsrep_log_error "LPORT cannot be nil"; exit $EINVAL; fi -if test -z "$WSREP_SST_OPT_SOCKET";then wsrep_log_error "SOCKET cannot be nil";exit $EINVAL; fi -if test -z "$WSREP_SST_OPT_GTID"; then wsrep_log_error "GTID cannot be nil"; exit $EINVAL; fi - -if local_ip $WSREP_SST_OPT_HOST && \ - [ "$WSREP_SST_OPT_PORT" = "$WSREP_SST_OPT_LPORT" ] -then - wsrep_log_error \ - "destination address '$WSREP_SST_OPT_HOST:$WSREP_SST_OPT_PORT' matches source address." - exit $EINVAL -fi - -# Check client version -if ! mysql --version | grep 'Distrib 10' >/dev/null -then - mysql --version >&2 - wsrep_log_error "this operation requires MySQL client version 10 or newer" - exit $EINVAL -fi - -# For Bug:1293798 -if [ -z "$WSREP_SST_OPT_PSWD" -a -n "$WSREP_SST_OPT_AUTH" ]; then - WSREP_SST_OPT_USER=$(echo $WSREP_SST_OPT_AUTH | cut -d: -f1) - WSREP_SST_OPT_PSWD=$(echo $WSREP_SST_OPT_AUTH | cut -d: -f2) -fi -AUTH="-u$WSREP_SST_OPT_USER" -if test -n "$WSREP_SST_OPT_PSWD"; then AUTH="$AUTH -p$WSREP_SST_OPT_PSWD"; fi - -STOP_WSREP="SET wsrep_on=OFF;" - -# NOTE: we don't use --routines here because we're dumping mysql.proc table -MYSQLDUMP="mysqldump $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" - -# mysqldump cannot restore CSV tables, fix this issue -CSV_TABLES_FIX=" -set sql_mode=''; - -USE mysql; - -SET @cond = (SELECT (SUPPORT = 'YES' or SUPPORT = 'DEFAULT') FROM INFORMATION_SCHEMA.ENGINES WHERE ENGINE = 'csv'); - -SET @stmt = IF (@cond = '1', 'CREATE TABLE IF NOT EXISTS general_log ( event_time timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), user_host mediumtext NOT NULL, thread_id bigint(21) unsigned NOT NULL, server_id int(10) unsigned NOT NULL, command_type varchar(64) NOT NULL, argument mediumtext NOT NULL) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT=\"General log\"', 'SET @dummy = 0'); - -PREPARE stmt FROM @stmt; -EXECUTE stmt; -DROP PREPARE stmt; - -SET @stmt = IF (@cond = '1', 'CREATE TABLE IF NOT EXISTS slow_log ( start_time timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), user_host mediumtext NOT NULL, query_time time(6) NOT NULL, lock_time time(6) NOT NULL, rows_sent int(11) NOT NULL, rows_examined int(11) NOT NULL, db varchar(512) NOT NULL, last_insert_id int(11) NOT NULL, insert_id int(11) NOT NULL, server_id int(10) unsigned NOT NULL, sql_text mediumtext NOT NULL, thread_id bigint(21) unsigned NOT NULL) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT=\"Slow log\"', 'SET @dummy = 0'); - -PREPARE stmt FROM @stmt; -EXECUTE stmt; -DROP PREPARE stmt;" - -SET_START_POSITION="SET GLOBAL wsrep_start_position='$WSREP_SST_OPT_GTID';" - -MYSQL="mysql $AUTH -h$WSREP_SST_OPT_HOST -P$WSREP_SST_OPT_PORT "\ -"--disable-reconnect --connect_timeout=10" - -# need to disable logging when loading the dump -# reason is that dump contains ALTER TABLE for log tables, and -# this causes an error if logging is enabled -GENERAL_LOG_OPT=`$MYSQL --skip-column-names -e"$STOP_WSREP SELECT @@GENERAL_LOG"` -SLOW_LOG_OPT=`$MYSQL --skip-column-names -e"$STOP_WSREP SELECT @@SLOW_QUERY_LOG"` -$MYSQL -e"$STOP_WSREP SET GLOBAL GENERAL_LOG=OFF" -$MYSQL -e"$STOP_WSREP SET GLOBAL SLOW_QUERY_LOG=OFF" - -# commands to restore log settings -RESTORE_GENERAL_LOG="SET GLOBAL GENERAL_LOG=$GENERAL_LOG_OPT;" -RESTORE_SLOW_QUERY_LOG="SET GLOBAL SLOW_QUERY_LOG=$SLOW_LOG_OPT;" - -if [ $WSREP_SST_OPT_BYPASS -eq 0 ] -then - (echo $STOP_WSREP && $MYSQLDUMP && echo $CSV_TABLES_FIX \ - && echo $RESTORE_GENERAL_LOG && echo $RESTORE_SLOW_QUERY_LOG \ - && echo $SET_START_POSITION \ - || echo "SST failed to complete;") | $MYSQL -else - wsrep_log_info "Bypassing state dump." - echo $SET_START_POSITION | $MYSQL -fi - -# diff --git a/scripts/wsrep_sst_rsync b/scripts/wsrep_sst_rsync deleted file mode 100755 index 86bf557662d..00000000000 --- a/scripts/wsrep_sst_rsync +++ /dev/null @@ -1,335 +0,0 @@ -#!/bin/bash -ue - -# 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 -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; see the file COPYING. If not, write to the -# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston -# MA 02110-1301 USA. - -# This is a reference script for rsync-based state snapshot tansfer - -RSYNC_PID= -RSYNC_CONF= -OS=$(uname) -[ "$OS" == "Darwin" ] && export -n LD_LIBRARY_PATH - -# Setting the path for lsof on CentOS -export PATH="/usr/sbin:/sbin:$PATH" - -. $(dirname $0)/wsrep_sst_common - -wsrep_check_programs rsync - -cleanup_joiner() -{ - wsrep_log_info "Joiner cleanup." - local PID=$(cat "$RSYNC_PID" 2>/dev/null || echo 0) - [ "0" != "$PID" ] && kill $PID && sleep 0.5 && kill -9 $PID >/dev/null 2>&1 \ - || : - rm -rf "$RSYNC_CONF" - rm -rf "$MAGIC_FILE" - rm -rf "$RSYNC_PID" - wsrep_log_info "Joiner cleanup done." - if [ "${WSREP_SST_OPT_ROLE}" = "joiner" ];then - wsrep_cleanup_progress_file - fi -} - -check_pid() -{ - local pid_file=$1 - [ -r "$pid_file" ] && ps -p $(cat $pid_file) >/dev/null 2>&1 -} - -check_pid_and_port() -{ - local pid_file=$1 - local rsync_pid=$2 - local rsync_port=$3 - - if ! which lsof > /dev/null; then - wsrep_log_error "lsof tool not found in PATH! Make sure you have it installed." - exit 2 # ENOENT - fi - - local port_info=$(lsof -i :$rsync_port -Pn 2>/dev/null | \ - grep "(LISTEN)") - local is_rsync=$(echo $port_info | \ - grep -w '^rsync[[:space:]]\+'"$rsync_pid" 2>/dev/null) - - if [ -n "$port_info" -a -z "$is_rsync" ]; then - wsrep_log_error "rsync daemon port '$rsync_port' has been taken" - exit 16 # EBUSY - fi - check_pid $pid_file && \ - [ -n "$port_info" ] && [ -n "$is_rsync" ] && \ - [ $(cat $pid_file) -eq $rsync_pid ] -} - -MAGIC_FILE="$WSREP_SST_OPT_DATA/rsync_sst_complete" -rm -rf "$MAGIC_FILE" - -BINLOG_TAR_FILE="$WSREP_SST_OPT_DATA/wsrep_sst_binlog.tar" -BINLOG_N_FILES=1 -rm -f "$BINLOG_TAR_FILE" || : - -if ! [ -z $WSREP_SST_OPT_BINLOG ] -then - BINLOG_DIRNAME=$(dirname $WSREP_SST_OPT_BINLOG) - BINLOG_FILENAME=$(basename $WSREP_SST_OPT_BINLOG) -fi - -WSREP_LOG_DIR=${WSREP_LOG_DIR:-""} -# if WSREP_LOG_DIR env. variable is not set, try to get it from my.cnf -if [ -z "$WSREP_LOG_DIR" ]; then - SCRIPT_DIR="$(cd $(dirname "$0"); pwd -P)" - WSREP_LOG_DIR=$($SCRIPT_DIR/my_print_defaults --defaults-file \ - "$WSREP_SST_OPT_CONF" mysqld server mysqld-10.0 mariadb mariadb-10.0 \ - | grep -- '--innodb[-_]log[-_]group[-_]home[-_]dir=' \ - | cut -b 29- ) -fi - -if [ -n "$WSREP_LOG_DIR" ]; then - # handle both relative and absolute paths - WSREP_LOG_DIR=$(cd $WSREP_SST_OPT_DATA; mkdir -p "$WSREP_LOG_DIR"; cd $WSREP_LOG_DIR; pwd -P) -else - # default to datadir - WSREP_LOG_DIR=$(cd $WSREP_SST_OPT_DATA; pwd -P) -fi - -# Old filter - include everything except selected -# FILTER=(--exclude '*.err' --exclude '*.pid' --exclude '*.sock' \ -# --exclude '*.conf' --exclude core --exclude 'galera.*' \ -# --exclude grastate.txt --exclude '*.pem' \ -# --exclude '*.[0-9][0-9][0-9][0-9][0-9][0-9]' --exclude '*.index') - -# New filter - exclude everything except dirs (schemas) and innodb files -FILTER=(-f '- /lost+found' -f '- /.fseventsd' -f '- /.Trashes' - -f '+ /wsrep_sst_binlog.tar' -f '+ /ib_lru_dump' -f '+ /ibdata*' -f '+ /*/' -f '- /*') - -if [ "$WSREP_SST_OPT_ROLE" = "donor" ] -then - - if [ $WSREP_SST_OPT_BYPASS -eq 0 ] - then - - FLUSHED="$WSREP_SST_OPT_DATA/tables_flushed" - rm -rf "$FLUSHED" - - # Use deltaxfer only for WAN - inv=$(basename $0) - [ "$inv" = "wsrep_sst_rsync_wan" ] && WHOLE_FILE_OPT="" \ - || WHOLE_FILE_OPT="--whole-file" - - echo "flush tables" - - # wait for tables flushed and state ID written to the file - while [ ! -r "$FLUSHED" ] && ! grep -q ':' "$FLUSHED" >/dev/null 2>&1 - do - sleep 0.2 - done - - STATE="$(cat $FLUSHED)" - rm -rf "$FLUSHED" - - sync - - if ! [ -z $WSREP_SST_OPT_BINLOG ] - then - # Prepare binlog files - pushd $BINLOG_DIRNAME &> /dev/null - binlog_files_full=$(tail -n $BINLOG_N_FILES ${BINLOG_FILENAME}.index) - binlog_files="" - for ii in $binlog_files_full - do - binlog_files="$binlog_files $(basename $ii)" - done - if ! [ -z "$binlog_files" ] - then - wsrep_log_info "Preparing binlog files for transfer:" - tar -cvf $BINLOG_TAR_FILE $binlog_files >&2 - fi - popd &> /dev/null - fi - - # first, the normal directories, so that we can detect incompatible protocol - RC=0 - rsync --owner --group --perms --links --specials \ - --ignore-times --inplace --dirs --delete --quiet \ - $WHOLE_FILE_OPT "${FILTER[@]}" "$WSREP_SST_OPT_DATA/" \ - rsync://$WSREP_SST_OPT_ADDR >&2 || RC=$? - - if [ "$RC" -ne 0 ]; then - wsrep_log_error "rsync returned code $RC:" - - case $RC in - 12) RC=71 # EPROTO - wsrep_log_error \ - "rsync server on the other end has incompatible protocol. " \ - "Make sure you have the same version of rsync on all nodes." - ;; - 22) RC=12 # ENOMEM - ;; - *) RC=255 # unknown error - ;; - esac - exit $RC - fi - - # second, we transfer InnoDB log files - rsync --owner --group --perms --links --specials \ - --ignore-times --inplace --dirs --delete --quiet \ - $WHOLE_FILE_OPT -f '+ /ib_logfile[0-9]*' -f '- **' "$WSREP_LOG_DIR/" \ - rsync://$WSREP_SST_OPT_ADDR-log_dir >&2 || RC=$? - - if [ $RC -ne 0 ]; then - wsrep_log_error "rsync innodb_log_group_home_dir returned code $RC:" - exit 255 # unknown error - fi - - # then, we parallelize the transfer of database directories, use . so that pathconcatenation works - pushd "$WSREP_SST_OPT_DATA" >/dev/null - - count=1 - [ "$OS" == "Linux" ] && count=$(grep -c processor /proc/cpuinfo) - [ "$OS" == "Darwin" -o "$OS" == "FreeBSD" ] && count=$(sysctl -n hw.ncpu) - - find . -maxdepth 1 -mindepth 1 -type d -print0 | xargs -I{} -0 -P $count \ - rsync --owner --group --perms --links --specials \ - --ignore-times --inplace --recursive --delete --quiet \ - $WHOLE_FILE_OPT --exclude '*/ib_logfile*' "$WSREP_SST_OPT_DATA"/{}/ \ - rsync://$WSREP_SST_OPT_ADDR/{} >&2 || RC=$? - - popd >/dev/null - - if [ $RC -ne 0 ]; then - wsrep_log_error "find/rsync returned code $RC:" - exit 255 # unknown error - fi - - else # BYPASS - wsrep_log_info "Bypassing state dump." - STATE="$WSREP_SST_OPT_GTID" - fi - - echo "continue" # now server can resume updating data - - echo "$STATE" > "$MAGIC_FILE" - rsync --archive --quiet --checksum "$MAGIC_FILE" rsync://$WSREP_SST_OPT_ADDR - - echo "done $STATE" - -elif [ "$WSREP_SST_OPT_ROLE" = "joiner" ] -then - wsrep_check_programs lsof - - touch $SST_PROGRESS_FILE - MYSQLD_PID=$WSREP_SST_OPT_PARENT - - MODULE="rsync_sst" - - RSYNC_PID="$WSREP_SST_OPT_DATA/$MODULE.pid" - - if check_pid $RSYNC_PID - then - wsrep_log_error "rsync daemon already running." - exit 114 # EALREADY - fi - rm -rf "$RSYNC_PID" - - ADDR=$WSREP_SST_OPT_ADDR - RSYNC_PORT=$(echo $ADDR | awk -F ':' '{ print $2 }') - if [ -z "$RSYNC_PORT" ] - then - RSYNC_PORT=4444 - ADDR="$(echo $ADDR | awk -F ':' '{ print $1 }'):$RSYNC_PORT" - fi - - trap "exit 32" HUP PIPE - trap "exit 3" INT TERM ABRT - trap cleanup_joiner EXIT - - RSYNC_CONF="$WSREP_SST_OPT_DATA/$MODULE.conf" - -cat << EOF > "$RSYNC_CONF" -pid file = $RSYNC_PID -use chroot = no -read only = no -timeout = 300 -[$MODULE] - path = $WSREP_SST_OPT_DATA -[$MODULE-log_dir] - path = $WSREP_LOG_DIR -EOF - -# rm -rf "$DATA"/ib_logfile* # we don't want old logs around - - # listen at all interfaces (for firewalled setups) - rsync --daemon --no-detach --port $RSYNC_PORT --config "$RSYNC_CONF" & - RSYNC_REAL_PID=$! - - until check_pid_and_port $RSYNC_PID $RSYNC_REAL_PID $RSYNC_PORT - do - sleep 0.2 - done - - echo "ready $ADDR/$MODULE" - - # wait for SST to complete by monitoring magic file - while [ ! -r "$MAGIC_FILE" ] && check_pid "$RSYNC_PID" && \ - ps -p $MYSQLD_PID >/dev/null - do - sleep 1 - done - - if ! ps -p $MYSQLD_PID >/dev/null - then - wsrep_log_error \ - "Parent mysqld process (PID:$MYSQLD_PID) terminated unexpectedly." - exit 32 - fi - - if ! [ -z $WSREP_SST_OPT_BINLOG ] - then - - pushd $BINLOG_DIRNAME &> /dev/null - if [ -f $BINLOG_TAR_FILE ] - then - # Clean up old binlog files first - rm -f ${BINLOG_FILENAME}.* - wsrep_log_info "Extracting binlog files:" - tar -xvf $BINLOG_TAR_FILE >&2 - for ii in $(ls -1 ${BINLOG_FILENAME}.*) - do - echo ${BINLOG_DIRNAME}/${ii} >> ${BINLOG_FILENAME}.index - done - fi - popd &> /dev/null - fi - if [ -r "$MAGIC_FILE" ] - then - cat "$MAGIC_FILE" # output UUID:seqno - else - # this message should cause joiner to abort - echo "rsync process ended without creating '$MAGIC_FILE'" - fi - wsrep_cleanup_progress_file -# cleanup_joiner -else - wsrep_log_error "Unrecognized role: '$WSREP_SST_OPT_ROLE'" - exit 22 # EINVAL -fi - -rm -f $BINLOG_TAR_FILE || : - -exit 0 diff --git a/scripts/wsrep_sst_xtrabackup b/scripts/wsrep_sst_xtrabackup deleted file mode 100755 index 6b33eabee23..00000000000 --- a/scripts/wsrep_sst_xtrabackup +++ /dev/null @@ -1,715 +0,0 @@ -#!/bin/bash -ue -# Copyright (C) 2013 Percona Inc -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; see the file COPYING. If not, write to the -# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston -# MA 02110-1301 USA. - -# Optional dependencies and options documented here: http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html -# Make sure to read that before proceeding! - - - - -. $(dirname $0)/wsrep_sst_common - -ealgo="" -ekey="" -ekeyfile="" -encrypt=0 -nproc=1 -ecode=0 -XTRABACKUP_PID="" -SST_PORT="" -REMOTEIP="" -tcert="" -tpem="" -sockopt="" -progress="" -ttime=0 -totime=0 -lsn="" -incremental=0 -ecmd="" -rlimit="" - -sfmt="tar" -strmcmd="" -tfmt="" -tcmd="" -rebuild=0 -rebuildcmd="" -payload=0 -pvformat="-F '%N => Rate:%r Avg:%a Elapsed:%t %e Bytes: %b %p' " -pvopts="-f -i 10 -N $WSREP_SST_OPT_ROLE " -uextra=0 - -if which pv &>/dev/null && pv --help | grep -q FORMAT;then - pvopts+=$pvformat -fi -pcmd="pv $pvopts" -declare -a RC - -INNOBACKUPEX_BIN=innobackupex -readonly AUTH=(${WSREP_SST_OPT_AUTH//:/ }) -DATA="${WSREP_SST_OPT_DATA}" -INFO_FILE="xtrabackup_galera_info" -IST_FILE="xtrabackup_ist" -MAGIC_FILE="${DATA}/${INFO_FILE}" - -# Setting the path for ss and ip -export PATH="/usr/sbin:/sbin:$PATH" - -timeit(){ - local stage=$1 - shift - local cmd="$@" - local x1 x2 took extcode - - if [[ $ttime -eq 1 ]];then - x1=$(date +%s) - wsrep_log_info "Evaluating $cmd" - eval "$cmd" - extcode=$? - x2=$(date +%s) - took=$(( x2-x1 )) - wsrep_log_info "NOTE: $stage took $took seconds" - totime=$(( totime+took )) - else - wsrep_log_info "Evaluating $cmd" - eval "$cmd" - extcode=$? - fi - return $extcode -} - -get_keys() -{ - if [[ $encrypt -eq 2 ]];then - return - fi - - if [[ $encrypt -eq 0 ]];then - if my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -q encrypt;then - wsrep_log_error "Unexpected option combination. SST may fail. Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html " - fi - return - fi - - if [[ $sfmt == 'tar' ]];then - wsrep_log_info "NOTE: Xtrabackup-based encryption - encrypt=1 - cannot be enabled with tar format" - encrypt=0 - return - fi - - wsrep_log_info "Xtrabackup based encryption enabled in my.cnf - Supported only from Xtrabackup 2.1.4" - - if [[ -z $ealgo ]];then - wsrep_log_error "FATAL: Encryption algorithm empty from my.cnf, bailing out" - exit 3 - fi - - if [[ -z $ekey && ! -r $ekeyfile ]];then - wsrep_log_error "FATAL: Either key or keyfile must be readable" - exit 3 - fi - - if [[ -z $ekey ]];then - ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key-file=$ekeyfile" - else - ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key=$ekey" - fi - - if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then - ecmd+=" -d" - fi -} - -get_transfer() -{ - if [[ -z $SST_PORT ]];then - TSST_PORT=4444 - else - TSST_PORT=$SST_PORT - fi - - if [[ $tfmt == 'nc' ]];then - if [[ ! -x `which nc` ]];then - wsrep_log_error "nc(netcat) not found in path: $PATH" - exit 2 - fi - wsrep_log_info "Using netcat as streamer" - if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then - tcmd="nc -dl ${TSST_PORT}" - else - tcmd="nc ${REMOTEIP} ${TSST_PORT}" - fi - else - tfmt='socat' - wsrep_log_info "Using socat as streamer" - if [[ ! -x `which socat` ]];then - wsrep_log_error "socat not found in path: $PATH" - exit 2 - fi - - if [[ $encrypt -eq 2 ]] && ! socat -V | grep -q OPENSSL;then - wsrep_log_info "NOTE: socat is not openssl enabled, falling back to plain transfer" - encrypt=0 - fi - - if [[ $encrypt -eq 2 ]];then - wsrep_log_info "Using openssl based encryption with socat" - if [[ -z $tpem || -z $tcert ]];then - wsrep_log_error "Both PEM and CRT files required" - exit 22 - fi - if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then - wsrep_log_info "Decrypting with PEM $tpem, CA: $tcert" - tcmd="socat -u openssl-listen:${TSST_PORT},reuseaddr,cert=$tpem,cafile=${tcert}${sockopt} stdio" - else - wsrep_log_info "Encrypting with PEM $tpem, CA: $tcert" - tcmd="socat -u stdio openssl-connect:${REMOTEIP}:${TSST_PORT},cert=$tpem,cafile=${tcert}${sockopt}" - 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 - fi - fi - -} - -parse_cnf() -{ - local group=$1 - local var=$2 - reval=$(my_print_defaults -c $WSREP_SST_OPT_CONF $group | awk -F= '{if ($1 ~ /_/) { gsub(/_/,"-",$1); print $1"="$2 } else { print $0 }}' | grep -- "--$var=" | cut -d= -f2-) - if [[ -z $reval ]];then - [[ -n $3 ]] && reval=$3 - fi - echo $reval -} - -get_footprint() -{ - pushd $WSREP_SST_OPT_DATA 1>/dev/null - payload=$(find . -regex '.*\.ibd$\|.*\.MYI$\|.*\.MYD$\|.*ibdata1$' -type f -print0 | xargs -0 du --block-size=1 -c | awk 'END { print $1 }') - if my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -q -- "--compress";then - # QuickLZ has around 50% compression ratio - # When compression/compaction used, the progress is only an approximate. - payload=$(( payload*1/2 )) - fi - popd 1>/dev/null - pcmd+=" -s $payload" - adjust_progress -} - -adjust_progress() -{ - if [[ -n $progress && $progress != '1' ]];then - if [[ -e $progress ]];then - pcmd+=" 2>>$progress" - else - pcmd+=" 2>$progress" - fi - elif [[ -z $progress && -n $rlimit ]];then - # When rlimit is non-zero - pcmd="pv -q" - fi - - if [[ -n $rlimit && "$WSREP_SST_OPT_ROLE" == "donor" ]];then - wsrep_log_info "Rate-limiting SST to $rlimit" - pcmd+=" -L \$rlimit" - fi -} - -read_cnf() -{ - sfmt=$(parse_cnf sst streamfmt "tar") - tfmt=$(parse_cnf sst transferfmt "socat") - tcert=$(parse_cnf sst tca "") - tpem=$(parse_cnf sst tcert "") - encrypt=$(parse_cnf sst encrypt 0) - sockopt=$(parse_cnf sst sockopt "") - progress=$(parse_cnf sst progress "") - rebuild=$(parse_cnf sst rebuild 0) - ttime=$(parse_cnf sst time 0) - incremental=$(parse_cnf sst incremental 0) - ealgo=$(parse_cnf xtrabackup encrypt "") - ekey=$(parse_cnf xtrabackup encrypt-key "") - ekeyfile=$(parse_cnf xtrabackup encrypt-key-file "") - - # Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html - if [[ -z $ealgo ]];then - ealgo=$(parse_cnf sst encrypt-algo "") - ekey=$(parse_cnf sst encrypt-key "") - ekeyfile=$(parse_cnf sst encrypt-key-file "") - fi - rlimit=$(parse_cnf sst rlimit "") - uextra=$(parse_cnf sst use_extra 0) -} - -get_stream() -{ - if [[ $sfmt == 'xbstream' ]];then - wsrep_log_info "Streaming with xbstream" - if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then - strmcmd="xbstream -x" - else - strmcmd="xbstream -c \${INFO_FILE} \${IST_FILE}" - fi - else - sfmt="tar" - wsrep_log_info "Streaming with tar" - if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then - strmcmd="tar xfi - --recursive-unlink -h" - else - strmcmd="tar cf - \${INFO_FILE} \${IST_FILE}" - fi - - fi -} - -get_proc() -{ - set +e - nproc=$(grep -c processor /proc/cpuinfo) - [[ -z $nproc || $nproc -eq 0 ]] && nproc=1 - set -e -} - -sig_joiner_cleanup() -{ - wsrep_log_error "Removing $MAGIC_FILE file due to signal" - 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" - fi - if [ "${WSREP_SST_OPT_ROLE}" = "joiner" ];then - wsrep_log_info "Removing the sst_in_progress file" - wsrep_cleanup_progress_file - fi - if [[ -n $progress && -p $progress ]];then - wsrep_log_info "Cleaning up fifo file $progress" - rm $progress - fi -} - -check_pid() -{ - local pid_file="$1" - [ -r "$pid_file" ] && ps -p $(cat "$pid_file") >/dev/null 2>&1 -} - -cleanup_donor() -{ - # Since this is invoked just after exit NNN - local estatus=$? - if [[ $estatus -ne 0 ]];then - wsrep_log_error "Cleanup after exit with status:$estatus" - fi - - if [[ -n $XTRABACKUP_PID ]];then - if check_pid $XTRABACKUP_PID - then - wsrep_log_error "xtrabackup process is still running. Killing... " - kill_xtrabackup - fi - - rm -f $XTRABACKUP_PID - fi - rm -f ${DATA}/${IST_FILE} - - if [[ -n $progress && -p $progress ]];then - wsrep_log_info "Cleaning up fifo file $progress" - rm $progress - fi -} - -kill_xtrabackup() -{ - local PID=$(cat $XTRABACKUP_PID) - [ -n "$PID" -a "0" != "$PID" ] && kill $PID && (kill $PID && kill -9 $PID) || : - rm -f "$XTRABACKUP_PID" -} - -setup_ports() -{ - if [[ "$WSREP_SST_OPT_ROLE" == "donor" ]];then - SST_PORT=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $2 }') - REMOTEIP=$(echo $WSREP_SST_OPT_ADDR | awk -F ':' '{ print $1 }') - lsn=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $4 }') - else - SST_PORT=$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $2 }') - fi -} - -# waits ~10 seconds for 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 - ss -p state listening "( sport = :$PORT )" | grep -qE 'socat|nc' && break - sleep 0.2 - done - if [[ $incremental -eq 1 ]];then - echo "ready ${ADDR}/${MODULE}/$lsn" - else - echo "ready ${ADDR}/${MODULE}" - fi -} - -check_extra() -{ - local use_socket=1 - if [[ $uextra -eq 1 ]];then - if my_print_defaults -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--thread-handling=" | grep -q 'pool-of-threads';then - local eport=$(my_print_defaults -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--extra-port=" | cut -d= -f2) - if [[ -n $eport ]];then - # Xtrabackup works only locally. - # Hence, setting host to 127.0.0.1 unconditionally. - wsrep_log_info "SST through extra_port $eport" - INNOEXTRA+=" --host=127.0.0.1 --port=$eport " - use_socket=0 - else - wsrep_log_error "Extra port $eport null, failing" - exit 1 - fi - else - wsrep_log_info "Thread pool not set, ignore the option use_extra" - fi - fi - if [[ $use_socket -eq 1 ]] && [[ -n "${WSREP_SST_OPT_SOCKET}" ]];then - INNOEXTRA+=" --socket=${WSREP_SST_OPT_SOCKET}" - fi -} - -if [[ ! -x `which innobackupex` ]];then - wsrep_log_error "innobackupex not in path: $PATH" - exit 2 -fi - -rm -f "${MAGIC_FILE}" - -if [[ ! ${WSREP_SST_OPT_ROLE} == 'joiner' && ! ${WSREP_SST_OPT_ROLE} == 'donor' ]];then - wsrep_log_error "Invalid role ${WSREP_SST_OPT_ROLE}" - exit 22 -fi - -read_cnf -setup_ports -get_stream -get_transfer - -INNOEXTRA="" -INNOAPPLY="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} --apply-log \$rebuildcmd \${DATA} &>\${DATA}/innobackup.prepare.log" -INNOBACKUP="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} \$INNOEXTRA --galera-info --stream=\$sfmt \${TMPDIR} 2>\${DATA}/innobackup.backup.log" - -if [ "$WSREP_SST_OPT_ROLE" = "donor" ] -then - trap cleanup_donor EXIT - - if [ $WSREP_SST_OPT_BYPASS -eq 0 ] - then - TMPDIR="${TMPDIR:-/tmp}" - - if [ "${AUTH[0]}" != "(null)" ]; then - INNOEXTRA+=" --user=${AUTH[0]}" - fi - - if [ ${#AUTH[*]} -eq 2 ]; then - INNOEXTRA+=" --password=${AUTH[1]}" - elif [ "${AUTH[0]}" != "(null)" ]; then - # Empty password, used for testing, debugging etc. - INNOEXTRA+=" --password=" - fi - - get_keys - if [[ $encrypt -eq 1 ]];then - if [[ -n $ekey ]];then - INNOEXTRA+=" --encrypt=$ealgo --encrypt-key=$ekey " - else - INNOEXTRA+=" --encrypt=$ealgo --encrypt-key-file=$ekeyfile " - fi - fi - - if [[ -n $lsn ]];then - INNOEXTRA+=" --incremental --incremental-lsn=$lsn " - fi - - check_extra - - wsrep_log_info "Streaming the backup to joiner at ${REMOTEIP} ${SST_PORT}" - - if [[ -n $progress ]];then - get_footprint - tcmd="$pcmd | $tcmd" - elif [[ -n $rlimit ]];then - adjust_progress - tcmd="$pcmd | $tcmd" - fi - - set +e - timeit "Donor-Transfer" "$INNOBACKUP | $tcmd; RC=( "\${PIPESTATUS[@]}" )" - set -e - - if [ ${RC[0]} -ne 0 ]; then - wsrep_log_error "${INNOBACKUPEX_BIN} finished with error: ${RC[0]}. " \ - "Check ${DATA}/innobackup.backup.log" - exit 22 - elif [[ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]];then - wsrep_log_error "$tcmd finished with error: ${RC[1]}" - exit 22 - fi - - # innobackupex implicitly writes PID to fixed location in ${TMPDIR} - XTRABACKUP_PID="${TMPDIR}/xtrabackup_pid" - - - else # BYPASS FOR IST - - wsrep_log_info "Bypassing the SST for IST" - STATE="${WSREP_SST_OPT_GTID}" - echo "continue" # now server can resume updating data - echo "${STATE}" > "${MAGIC_FILE}" - echo "1" > "${DATA}/${IST_FILE}" - get_keys - pushd ${DATA} 1>/dev/null - set +e - if [[ $encrypt -eq 1 ]];then - tcmd=" $ecmd | $tcmd" - fi - timeit "Donor-IST-Unencrypted-transfer" "$strmcmd | $tcmd; RC=( "\${PIPESTATUS[@]}" )" - set -e - popd 1>/dev/null - - for ecode in "${RC[@]}";do - if [[ $ecode -ne 0 ]];then - wsrep_log_error "Error while streaming data to joiner node: " \ - "exit codes: ${RC[@]}" - exit 1 - fi - done - fi - - echo "done ${WSREP_SST_OPT_GTID}" - wsrep_log_info "Total time on donor: $totime seconds" - -elif [ "${WSREP_SST_OPT_ROLE}" = "joiner" ] -then - [[ -e $SST_PROGRESS_FILE ]] && wsrep_log_info "Stale sst_in_progress file: $SST_PROGRESS_FILE" - touch $SST_PROGRESS_FILE - - if [[ ! -e ${DATA}/ibdata1 ]];then - incremental=0 - fi - - if [[ $incremental -eq 1 ]];then - wsrep_log_info "Incremental SST enabled" - #lsn=$(/pxc/bin/mysqld --defaults-file=$WSREP_SST_OPT_CONF --basedir=/pxc --wsrep-recover 2>&1 | grep -o 'log sequence number .*' | cut -d " " -f 4 | head -1) - lsn=$(grep to_lsn xtrabackup_checkpoints | cut -d= -f2 | tr -d ' ') - wsrep_log_info "Recovered LSN: $lsn" - fi - - sencrypted=1 - nthreads=1 - - MODULE="xtrabackup_sst" - - # May need xtrabackup_checkpoints later on - rm -f ${DATA}/xtrabackup_binary ${DATA}/xtrabackup_galera_info ${DATA}/xtrabackup_logfile - - ADDR=${WSREP_SST_OPT_ADDR} - if [ -z "${SST_PORT}" ] - then - SST_PORT=4444 - ADDR="$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $1 }'):${SST_PORT}" - fi - - wait_for_listen ${SST_PORT} ${ADDR} ${MODULE} & - - trap sig_joiner_cleanup HUP PIPE INT TERM - trap cleanup_joiner EXIT - - if [[ -n $progress ]];then - adjust_progress - tcmd+=" | $pcmd" - fi - - if [[ $incremental -eq 1 ]];then - BDATA=$DATA - DATA=$(mktemp -d) - MAGIC_FILE="${DATA}/${INFO_FILE}" - fi - - get_keys - set +e - if [[ $encrypt -eq 1 && $sencrypted -eq 1 ]];then - strmcmd=" $ecmd | $strmcmd" - fi - - pushd ${DATA} 1>/dev/null - timeit "Joiner-Recv-Unencrypted" "$tcmd | $strmcmd; RC=( "\${PIPESTATUS[@]}" )" - popd 1>/dev/null - - set -e - - if [[ $sfmt == 'xbstream' ]];then - # Special handling till lp:1193240 is fixed" - if [[ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]];then - wsrep_log_error "Xbstream failed" - wsrep_log_error "Data directory ${DATA} may not be empty: lp:1193240" \ - "Manual intervention required in that case" - exit 32 - fi - fi - - wait %% # join for wait_for_listen thread - - for ecode in "${RC[@]}";do - if [[ $ecode -ne 0 ]];then - wsrep_log_error "Error while getting data from donor node: " \ - "exit codes: ${RC[@]}" - exit 32 - fi - done - - if [ ! -r "${MAGIC_FILE}" ] - then - # this message should cause joiner to abort - wsrep_log_error "xtrabackup process ended without creating '${MAGIC_FILE}'" - wsrep_log_info "Contents of datadir" - wsrep_log_info "$(ls -l ${DATA}/**/*)" - exit 32 - fi - - if ! ps -p ${WSREP_SST_OPT_PARENT} &>/dev/null - then - wsrep_log_error "Parent mysqld process (PID:${WSREP_SST_OPT_PARENT}) terminated unexpectedly." - exit 32 - fi - - if [ ! -r "${DATA}/${IST_FILE}" ] - then - wsrep_log_info "Proceeding with SST" - wsrep_log_info "Removing existing ib_logfile files" - if [[ $incremental -ne 1 ]];then - rm -f ${DATA}/ib_logfile* - else - rm -f ${BDATA}/ib_logfile* - fi - - get_proc - - # Rebuild indexes for compact backups - if grep -q 'compact = 1' ${DATA}/xtrabackup_checkpoints;then - wsrep_log_info "Index compaction detected" - rebuild=1 - fi - - if [[ $rebuild -eq 1 ]];then - nthreads=$(parse_cnf xtrabackup rebuild-threads $nproc) - wsrep_log_info "Rebuilding during prepare with $nthreads threads" - rebuildcmd="--rebuild-indexes --rebuild-threads=$nthreads" - fi - - if test -n "$(find ${DATA} -maxdepth 1 -type f -name '*.qp' -print -quit)";then - - wsrep_log_info "Compressed qpress files found" - - if [[ ! -x `which qpress` ]];then - wsrep_log_error "qpress not found in path: $PATH" - exit 22 - fi - - if [[ -n $progress ]] && pv --help | grep -q 'line-mode';then - count=$(find ${DATA} -type f -name '*.qp' | wc -l) - count=$(( count*2 )) - if pv --help | grep -q FORMAT;then - pvopts="-f -s $count -l -N Decompression -F '%N => Rate:%r Elapsed:%t %e Progress: [%b/$count]'" - else - pvopts="-f -s $count -l -N Decompression" - fi - pcmd="pv $pvopts" - adjust_progress - dcmd="$pcmd | xargs -n 2 qpress -T${nproc}d" - else - dcmd="xargs -n 2 qpress -T${nproc}d" - fi - - wsrep_log_info "Removing existing ibdata1 file" - rm -f ${DATA}/ibdata1 - - # Decompress the qpress files - wsrep_log_info "Decompression with $nproc threads" - timeit "Decompression" "find ${DATA} -type f -name '*.qp' -printf '%p\n%h\n' | $dcmd" - extcode=$? - - if [[ $extcode -eq 0 ]];then - wsrep_log_info "Removing qpress files after decompression" - find ${DATA} -type f -name '*.qp' -delete - if [[ $? -ne 0 ]];then - wsrep_log_error "Something went wrong with deletion of qpress files. Investigate" - fi - else - wsrep_log_error "Decompression failed. Exit code: $extcode" - exit 22 - fi - fi - - if [[ $incremental -eq 1 ]];then - # Added --ibbackup=xtrabackup_55 because it fails otherwise citing connection issues. - INNOAPPLY="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} \ - --ibbackup=xtrabackup_55 --apply-log $rebuildcmd --redo-only $BDATA --incremental-dir=${DATA} &>>${BDATA}/innobackup.prepare.log" - fi - - wsrep_log_info "Preparing the backup at ${DATA}" - timeit "Xtrabackup prepare stage" "$INNOAPPLY" - - if [[ $incremental -eq 1 ]];then - wsrep_log_info "Cleaning up ${DATA} after incremental SST" - [[ -d ${DATA} ]] && rm -rf ${DATA} - DATA=$BDATA - fi - - if [ $? -ne 0 ]; - then - wsrep_log_error "${INNOBACKUPEX_BIN} finished with errors. Check ${DATA}/innobackup.prepare.log" - exit 22 - fi - else - 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" - exit 2 - fi - - cat "${MAGIC_FILE}" # output UUID:seqno - wsrep_log_info "Total time on joiner: $totime seconds" -fi - -exit 0 diff --git a/scripts/wsrep_sst_xtrabackup-v2 b/scripts/wsrep_sst_xtrabackup-v2 deleted file mode 100755 index f4d133d4f8e..00000000000 --- a/scripts/wsrep_sst_xtrabackup-v2 +++ /dev/null @@ -1,930 +0,0 @@ -#!/bin/bash -ue -# Copyright (C) 2013 Percona Inc -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; see the file COPYING. If not, write to the -# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston -# MA 02110-1301 USA. - -# Documentation: http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html -# Make sure to read that before proceeding! - - - - -. $(dirname $0)/wsrep_sst_common - -ealgo="" -ekey="" -ekeyfile="" -encrypt=0 -nproc=1 -ecode=0 -XTRABACKUP_PID="" -SST_PORT="" -REMOTEIP="" -tcert="" -tpem="" -tkey="" -sockopt="" -progress="" -ttime=0 -totime=0 -lsn="" -incremental=0 -ecmd="" -rlimit="" -# Initially -stagemsg="${WSREP_SST_OPT_ROLE}" -cpat="" -speciald=0 -ib_home_dir="" -ib_log_dir="" - -sfmt="tar" -strmcmd="" -tfmt="" -tcmd="" -rebuild=0 -rebuildcmd="" -payload=0 -pvformat="-F '%N => Rate:%r Avg:%a Elapsed:%t %e Bytes: %b %p' " -pvopts="-f -i 10 -N $WSREP_SST_OPT_ROLE " -STATDIR="" -uextra=0 -disver="" - -tmpopts="" -itmpdir="" -xtmpdir="" - -scomp="" -sdecomp="" - -if which pv &>/dev/null && pv --help | grep -q FORMAT;then - pvopts+=$pvformat -fi -pcmd="pv $pvopts" -declare -a RC - -INNOBACKUPEX_BIN=innobackupex -readonly AUTH=(${WSREP_SST_OPT_AUTH//:/ }) -DATA="${WSREP_SST_OPT_DATA}" -INFO_FILE="xtrabackup_galera_info" -IST_FILE="xtrabackup_ist" -MAGIC_FILE="${DATA}/${INFO_FILE}" - -# Setting the path for ss and ip -export PATH="/usr/sbin:/sbin:$PATH" - -timeit(){ - local stage=$1 - shift - local cmd="$@" - local x1 x2 took extcode - - if [[ $ttime -eq 1 ]];then - x1=$(date +%s) - wsrep_log_info "Evaluating $cmd" - eval "$cmd" - extcode=$? - x2=$(date +%s) - took=$(( x2-x1 )) - wsrep_log_info "NOTE: $stage took $took seconds" - totime=$(( totime+took )) - else - wsrep_log_info "Evaluating $cmd" - eval "$cmd" - extcode=$? - fi - return $extcode -} - -get_keys() -{ - # $encrypt -eq 1 is for internal purposes only - if [[ $encrypt -ge 2 || $encrypt -eq -1 ]];then - return - fi - - if [[ $encrypt -eq 0 ]];then - if my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -q encrypt;then - wsrep_log_error "Unexpected option combination. SST may fail. Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html " - fi - return - fi - - if [[ $sfmt == 'tar' ]];then - wsrep_log_info "NOTE: Xtrabackup-based encryption - encrypt=1 - cannot be enabled with tar format" - encrypt=-1 - return - fi - - wsrep_log_info "Xtrabackup based encryption enabled in my.cnf - Supported only from Xtrabackup 2.1.4" - - if [[ -z $ealgo ]];then - wsrep_log_error "FATAL: Encryption algorithm empty from my.cnf, bailing out" - exit 3 - fi - - if [[ -z $ekey && ! -r $ekeyfile ]];then - wsrep_log_error "FATAL: Either key or keyfile must be readable" - exit 3 - fi - - if [[ -z $ekey ]];then - ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key-file=$ekeyfile" - else - ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key=$ekey" - fi - - if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then - ecmd+=" -d" - fi - - stagemsg+="-XB-Encrypted" -} - -get_transfer() -{ - if [[ -z $SST_PORT ]];then - TSST_PORT=4444 - else - TSST_PORT=$SST_PORT - fi - - if [[ $tfmt == 'nc' ]];then - if [[ ! -x `which nc` ]];then - wsrep_log_error "nc(netcat) not found in path: $PATH" - exit 2 - fi - wsrep_log_info "Using netcat as streamer" - if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then - tcmd="nc -dl ${TSST_PORT}" - else - tcmd="nc ${REMOTEIP} ${TSST_PORT}" - fi - else - tfmt='socat' - wsrep_log_info "Using socat as streamer" - if [[ ! -x `which socat` ]];then - wsrep_log_error "socat not found in path: $PATH" - exit 2 - fi - - if [[ $encrypt -eq 2 || $encrypt -eq 3 ]] && ! socat -V | grep -q WITH_OPENSSL;then - wsrep_log_info "NOTE: socat is not openssl enabled, falling back to plain transfer" - encrypt=-1 - fi - - if [[ $encrypt -eq 2 ]];then - wsrep_log_info "Using openssl based encryption with socat: with crt and pem" - if [[ -z $tpem || -z $tcert ]];then - wsrep_log_error "Both PEM and CRT files required" - exit 22 - fi - stagemsg+="-OpenSSL-Encrypted-2" - if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then - wsrep_log_info "Decrypting with PEM $tpem, CA: $tcert" - tcmd="socat -u openssl-listen:${TSST_PORT},reuseaddr,cert=$tpem,cafile=${tcert}${sockopt} stdio" - else - wsrep_log_info "Encrypting with PEM $tpem, CA: $tcert" - tcmd="socat -u stdio openssl-connect:${REMOTEIP}:${TSST_PORT},cert=$tpem,cafile=${tcert}${sockopt}" - fi - elif [[ $encrypt -eq 3 ]];then - wsrep_log_info "Using openssl based encryption with socat: with key and crt" - if [[ -z $tpem || -z $tkey ]];then - wsrep_log_error "Both certificate and key files required" - exit 22 - fi - stagemsg+="-OpenSSL-Encrypted-3" - if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then - wsrep_log_info "Decrypting with certificate $tpem, key $tkey" - tcmd="socat -u openssl-listen:${TSST_PORT},reuseaddr,cert=$tpem,key=${tkey},verify=0${sockopt} stdio" - else - wsrep_log_info "Encrypting with certificate $tpem, key $tkey" - tcmd="socat -u stdio openssl-connect:${REMOTEIP}:${TSST_PORT},cert=$tpem,key=${tkey},verify=0${sockopt}" - 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 - fi - fi - -} - -parse_cnf() -{ - local group=$1 - local var=$2 - reval=$(my_print_defaults -c $WSREP_SST_OPT_CONF $group | awk -F= '{if ($1 ~ /_/) { gsub(/_/,"-",$1); print $1"="$2 } else { print $0 }}' | grep -- "--$var=" | cut -d= -f2-) - if [[ -z $reval ]];then - [[ -n $3 ]] && reval=$3 - fi - echo $reval -} - -get_footprint() -{ - pushd $WSREP_SST_OPT_DATA 1>/dev/null - payload=$(find . -regex '.*\.ibd$\|.*\.MYI$\|.*\.MYD$\|.*ibdata1$' -type f -print0 | xargs -0 du --block-size=1 -c | awk 'END { print $1 }') - if my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -q -- "--compress";then - # QuickLZ has around 50% compression ratio - # When compression/compaction used, the progress is only an approximate. - payload=$(( payload*1/2 )) - fi - popd 1>/dev/null - pcmd+=" -s $payload" - adjust_progress -} - -adjust_progress() -{ - if [[ -n $progress && $progress != '1' ]];then - if [[ -e $progress ]];then - pcmd+=" 2>>$progress" - else - pcmd+=" 2>$progress" - fi - elif [[ -z $progress && -n $rlimit ]];then - # When rlimit is non-zero - pcmd="pv -q" - fi - - if [[ -n $rlimit && "$WSREP_SST_OPT_ROLE" == "donor" ]];then - wsrep_log_info "Rate-limiting SST to $rlimit" - pcmd+=" -L \$rlimit" - fi -} - -read_cnf() -{ - sfmt=$(parse_cnf sst streamfmt "xbstream") - tfmt=$(parse_cnf sst transferfmt "socat") - tcert=$(parse_cnf sst tca "") - tpem=$(parse_cnf sst tcert "") - tkey=$(parse_cnf sst tkey "") - encrypt=$(parse_cnf sst encrypt 0) - sockopt=$(parse_cnf sst sockopt "") - progress=$(parse_cnf sst progress "") - rebuild=$(parse_cnf sst rebuild 0) - ttime=$(parse_cnf sst time 0) - cpat=$(parse_cnf sst cpat '.*galera\.cache$\|.*sst_in_progress$\|.*grastate\.dat$\|.*\.err$\|.*\.log$\|.*RPM_UPGRADE_MARKER$\|.*RPM_UPGRADE_HISTORY$') - incremental=$(parse_cnf sst incremental 0) - ealgo=$(parse_cnf xtrabackup encrypt "") - ekey=$(parse_cnf xtrabackup encrypt-key "") - ekeyfile=$(parse_cnf xtrabackup encrypt-key-file "") - scomp=$(parse_cnf sst compressor "") - sdecomp=$(parse_cnf sst decompressor "") - - - # Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html - if [[ -z $ealgo ]];then - ealgo=$(parse_cnf sst encrypt-algo "") - ekey=$(parse_cnf sst encrypt-key "") - ekeyfile=$(parse_cnf sst encrypt-key-file "") - fi - rlimit=$(parse_cnf sst rlimit "") - uextra=$(parse_cnf sst use-extra 0) - speciald=$(parse_cnf sst sst-special-dirs 1) - iopts=$(parse_cnf sst inno-backup-opts "") - iapts=$(parse_cnf sst inno-apply-opts "") - impts=$(parse_cnf sst inno-move-opts "") - stimeout=$(parse_cnf sst sst-initial-timeout 100) -} - -get_stream() -{ - if [[ $sfmt == 'xbstream' ]];then - wsrep_log_info "Streaming with xbstream" - if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then - strmcmd="xbstream -x" - else - strmcmd="xbstream -c \${INFO_FILE}" - fi - else - sfmt="tar" - wsrep_log_info "Streaming with 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 || $nproc -eq 0 ]] && nproc=1 - set -e -} - -sig_joiner_cleanup() -{ - wsrep_log_error "Removing $MAGIC_FILE file due to signal" - 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" - fi - if [ "${WSREP_SST_OPT_ROLE}" = "joiner" ];then - wsrep_log_info "Removing the sst_in_progress file" - wsrep_cleanup_progress_file - fi - if [[ -n $progress && -p $progress ]];then - wsrep_log_info "Cleaning up fifo file $progress" - rm $progress - fi - if [[ -n ${STATDIR:-} ]];then - [[ -d $STATDIR ]] && rm -rf $STATDIR - fi -} - -check_pid() -{ - local pid_file="$1" - [ -r "$pid_file" ] && ps -p $(cat "$pid_file") >/dev/null 2>&1 -} - -cleanup_donor() -{ - # Since this is invoked just after exit NNN - local estatus=$? - if [[ $estatus -ne 0 ]];then - wsrep_log_error "Cleanup after exit with status:$estatus" - fi - - if [[ -n ${XTRABACKUP_PID:-} ]];then - if check_pid $XTRABACKUP_PID - then - wsrep_log_error "xtrabackup process is still running. Killing... " - kill_xtrabackup - fi - - fi - rm -f ${DATA}/${IST_FILE} || true - - if [[ -n $progress && -p $progress ]];then - wsrep_log_info "Cleaning up fifo file $progress" - rm -f $progress || true - fi - - wsrep_log_info "Cleaning up temporary directories" - - if [[ -n $xtmpdir ]];then - [[ -d $xtmpdir ]] && rm -rf $xtmpdir || true - fi - - if [[ -n $itmpdir ]];then - [[ -d $itmpdir ]] && rm -rf $itmpdir || true - fi -} - -kill_xtrabackup() -{ - local PID=$(cat $XTRABACKUP_PID) - [ -n "$PID" -a "0" != "$PID" ] && kill $PID && (kill $PID && kill -9 $PID) || : - wsrep_log_info "Removing xtrabackup pid file $XTRABACKUP_PID" - rm -f "$XTRABACKUP_PID" || true -} - -setup_ports() -{ - if [[ "$WSREP_SST_OPT_ROLE" == "donor" ]];then - SST_PORT=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $2 }') - REMOTEIP=$(echo $WSREP_SST_OPT_ADDR | awk -F ':' '{ print $1 }') - lsn=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $4 }') - else - SST_PORT=$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $2 }') - fi -} - -# waits ~10 seconds for 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 - ss -p state listening "( sport = :$PORT )" | grep -qE 'socat|nc' && break - sleep 0.2 - done - if [[ $incremental -eq 1 ]];then - echo "ready ${ADDR}/${MODULE}/$lsn" - else - echo "ready ${ADDR}/${MODULE}" - fi -} - -check_extra() -{ - local use_socket=1 - if [[ $uextra -eq 1 ]];then - if my_print_defaults -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--thread-handling=" | grep -q 'pool-of-threads';then - local eport=$(my_print_defaults -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--extra-port=" | cut -d= -f2) - if [[ -n $eport ]];then - # Xtrabackup works only locally. - # Hence, setting host to 127.0.0.1 unconditionally. - wsrep_log_info "SST through extra_port $eport" - INNOEXTRA+=" --host=127.0.0.1 --port=$eport " - use_socket=0 - else - wsrep_log_error "Extra port $eport null, failing" - exit 1 - fi - else - wsrep_log_info "Thread pool not set, ignore the option use_extra" - fi - fi - if [[ $use_socket -eq 1 ]] && [[ -n "${WSREP_SST_OPT_SOCKET}" ]];then - INNOEXTRA+=" --socket=${WSREP_SST_OPT_SOCKET}" - fi -} - -recv_joiner() -{ - local dir=$1 - local msg=$2 - local tmt=$3 - local ltcmd - - pushd ${dir} 1>/dev/null - set +e - - if [[ $tmt -gt 0 && -x `which timeout` ]];then - if timeout --help | grep -q -- '-k';then - ltcmd="timeout -k $(( tmt+10 )) $tmt $tcmd" - else - ltcmd="timeout $tmt $tcmd" - fi - timeit "$msg" "$ltcmd | $strmcmd; RC=( "\${PIPESTATUS[@]}" )" - else - timeit "$msg" "$tcmd | $strmcmd; RC=( "\${PIPESTATUS[@]}" )" - fi - - set -e - popd 1>/dev/null - - if [[ ${RC[0]} -eq 124 ]];then - wsrep_log_error "Possible timeout in receving first data from donor in gtid stage" - exit 32 - fi - - for ecode in "${RC[@]}";do - if [[ $ecode -ne 0 ]];then - wsrep_log_error "Error while getting data from donor node: " \ - "exit codes: ${RC[@]}" - exit 32 - fi - done - - if [ ! -r "${MAGIC_FILE}" ];then - # this message should cause joiner to abort - wsrep_log_error "xtrabackup process ended without creating '${MAGIC_FILE}'" - wsrep_log_info "Contents of datadir" - wsrep_log_info "$(ls -l ${dir}/*)" - exit 32 - fi -} - - -send_donor() -{ - local dir=$1 - local msg=$2 - - pushd ${dir} 1>/dev/null - set +e - timeit "$msg" "$strmcmd | $tcmd; RC=( "\${PIPESTATUS[@]}" )" - set -e - popd 1>/dev/null - - - for ecode in "${RC[@]}";do - if [[ $ecode -ne 0 ]];then - wsrep_log_error "Error while getting data from donor node: " \ - "exit codes: ${RC[@]}" - exit 32 - fi - done - -} - -if [[ ! -x `which $INNOBACKUPEX_BIN` ]];then - wsrep_log_error "innobackupex not in path: $PATH" - exit 2 -fi - -rm -f "${MAGIC_FILE}" - -if [[ ! ${WSREP_SST_OPT_ROLE} == 'joiner' && ! ${WSREP_SST_OPT_ROLE} == 'donor' ]];then - wsrep_log_error "Invalid role ${WSREP_SST_OPT_ROLE}" - exit 22 -fi - -read_cnf -setup_ports -get_stream -get_transfer - -if ${INNOBACKUPEX_BIN} /tmp --help | grep -q -- '--version-check'; then - disver="--no-version-check" -fi - - -INNOEXTRA="" -INNOAPPLY="${INNOBACKUPEX_BIN} $disver $iapts --apply-log \$rebuildcmd \${DATA} &>\${DATA}/innobackup.prepare.log" -INNOMOVE="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} $disver $impts --move-back --force-non-empty-directories \${DATA} &>\${DATA}/innobackup.move.log" -INNOBACKUP="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} $disver $iopts \$tmpopts \$INNOEXTRA --galera-info --stream=\$sfmt \$itmpdir 2>\${DATA}/innobackup.backup.log" - -if [ "$WSREP_SST_OPT_ROLE" = "donor" ] -then - trap cleanup_donor EXIT - - if [ $WSREP_SST_OPT_BYPASS -eq 0 ] - then - - if [[ -z $(parse_cnf mysqld tmpdir "") && -z $(parse_cnf xtrabackup tmpdir "") ]];then - xtmpdir=$(mktemp -d) - tmpopts=" --tmpdir=$xtmpdir " - wsrep_log_info "Using $xtmpdir as xtrabackup temporary directory" - fi - - itmpdir=$(mktemp -d) - wsrep_log_info "Using $itmpdir as innobackupex temporary directory" - - if [ "${AUTH[0]}" != "(null)" ]; then - INNOEXTRA+=" --user=${AUTH[0]}" - fi - - if [ ${#AUTH[*]} -eq 2 ]; then - INNOEXTRA+=" --password=${AUTH[1]}" - elif [ "${AUTH[0]}" != "(null)" ]; then - # Empty password, used for testing, debugging etc. - INNOEXTRA+=" --password=" - fi - - get_keys - if [[ $encrypt -eq 1 ]];then - if [[ -n $ekey ]];then - INNOEXTRA+=" --encrypt=$ealgo --encrypt-key=$ekey " - else - INNOEXTRA+=" --encrypt=$ealgo --encrypt-key-file=$ekeyfile " - fi - fi - - if [[ -n $lsn ]];then - INNOEXTRA+=" --incremental --incremental-lsn=$lsn " - fi - - check_extra - - wsrep_log_info "Streaming GTID file before SST" - - echo "${WSREP_SST_OPT_GTID}" > "${MAGIC_FILE}" - - ttcmd="$tcmd" - - if [[ $encrypt -eq 1 ]];then - if [[ -n $scomp ]];then - tcmd=" $ecmd | $scomp | $tcmd " - else - tcmd=" $ecmd | $tcmd " - fi - elif [[ -n $scomp ]];then - tcmd=" $scomp | $tcmd " - fi - - - send_donor $DATA "${stagemsg}-gtid" - - tcmd="$ttcmd" - if [[ -n $progress ]];then - get_footprint - tcmd="$pcmd | $tcmd" - elif [[ -n $rlimit ]];then - adjust_progress - tcmd="$pcmd | $tcmd" - fi - - wsrep_log_info "Sleeping before data transfer for SST" - sleep 10 - - wsrep_log_info "Streaming the backup to joiner at ${REMOTEIP} ${SST_PORT:-4444}" - - if [[ -n $scomp ]];then - tcmd="$scomp | $tcmd" - fi - - set +e - timeit "${stagemsg}-SST" "$INNOBACKUP | $tcmd; RC=( "\${PIPESTATUS[@]}" )" - set -e - - if [ ${RC[0]} -ne 0 ]; then - wsrep_log_error "${INNOBACKUPEX_BIN} finished with error: ${RC[0]}. " \ - "Check ${DATA}/innobackup.backup.log" - exit 22 - elif [[ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]];then - wsrep_log_error "$tcmd finished with error: ${RC[1]}" - exit 22 - fi - - # innobackupex implicitly writes PID to fixed location in $xtmpdir - XTRABACKUP_PID="$xtmpdir/xtrabackup_pid" - - - else # BYPASS FOR IST - - wsrep_log_info "Bypassing the SST for IST" - echo "continue" # now server can resume updating data - echo "${WSREP_SST_OPT_GTID}" > "${MAGIC_FILE}" - echo "1" > "${DATA}/${IST_FILE}" - get_keys - if [[ $encrypt -eq 1 ]];then - if [[ -n $scomp ]];then - tcmd=" $ecmd | $scomp | $tcmd " - else - tcmd=" $ecmd | $tcmd " - fi - elif [[ -n $scomp ]];then - tcmd=" $scomp | $tcmd " - fi - strmcmd+=" \${IST_FILE}" - - send_donor $DATA "${stagemsg}-IST" - - fi - - echo "done ${WSREP_SST_OPT_GTID}" - wsrep_log_info "Total time on donor: $totime seconds" - -elif [ "${WSREP_SST_OPT_ROLE}" = "joiner" ] -then - [[ -e $SST_PROGRESS_FILE ]] && wsrep_log_info "Stale sst_in_progress file: $SST_PROGRESS_FILE" - [[ -n $SST_PROGRESS_FILE ]] && touch $SST_PROGRESS_FILE - - if [[ $speciald -eq 1 ]];then - ib_home_dir=$(parse_cnf mysqld innodb-data-home-dir "") - ib_log_dir=$(parse_cnf mysqld innodb-log-group-home-dir "") - if [[ -z $ib_home_dir && -z $ib_log_dir ]];then - speciald=0 - fi - fi - - stagemsg="Joiner-Recv" - - if [[ ! -e ${DATA}/ibdata1 ]];then - incremental=0 - fi - - if [[ $incremental -eq 1 ]];then - wsrep_log_info "Incremental SST enabled: NOT SUPPORTED yet" - lsn=$(grep to_lsn xtrabackup_checkpoints | cut -d= -f2 | tr -d ' ') - wsrep_log_info "Recovered LSN: $lsn" - fi - - sencrypted=1 - nthreads=1 - - MODULE="xtrabackup_sst" - - rm -f "${DATA}/${IST_FILE}" - - # May need xtrabackup_checkpoints later on - rm -f ${DATA}/xtrabackup_binary ${DATA}/xtrabackup_galera_info ${DATA}/xtrabackup_logfile - - ADDR=${WSREP_SST_OPT_ADDR} - if [ -z "${SST_PORT}" ] - then - SST_PORT=4444 - ADDR="$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $1 }'):${SST_PORT}" - fi - - wait_for_listen ${SST_PORT} ${ADDR} ${MODULE} & - - trap sig_joiner_cleanup HUP PIPE INT TERM - trap cleanup_joiner EXIT - - if [[ -n $progress ]];then - adjust_progress - tcmd+=" | $pcmd" - fi - - if [[ $incremental -eq 1 ]];then - BDATA=$DATA - DATA=$(mktemp -d) - MAGIC_FILE="${DATA}/${INFO_FILE}" - fi - - get_keys - if [[ $encrypt -eq 1 && $sencrypted -eq 1 ]];then - if [[ -n $sdecomp ]];then - strmcmd=" $sdecomp | $ecmd | $strmcmd" - else - strmcmd=" $ecmd | $strmcmd" - fi - elif [[ -n $sdecomp ]];then - strmcmd=" $sdecomp | $strmcmd" - fi - - STATDIR=$(mktemp -d) - MAGIC_FILE="${STATDIR}/${INFO_FILE}" - recv_joiner $STATDIR "${stagemsg}-gtid" $stimeout - - if ! ps -p ${WSREP_SST_OPT_PARENT} &>/dev/null - then - wsrep_log_error "Parent mysqld process (PID:${WSREP_SST_OPT_PARENT}) terminated unexpectedly." - exit 32 - fi - - if [ ! -r "${STATDIR}/${IST_FILE}" ] - then - wsrep_log_info "Proceeding with SST" - - if [[ $speciald -eq 1 && -d ${DATA}/.sst ]];then - wsrep_log_info "WARNING: Stale temporary SST directory: ${DATA}/.sst from previous SST" - fi - - if [[ $incremental -ne 1 ]];then - if [[ $speciald -eq 1 ]];then - wsrep_log_info "Cleaning the existing datadir and innodb-data/log directories" - find $ib_home_dir $ib_log_dir $DATA -mindepth 1 -regex $cpat -prune -o -exec rm -rfv {} 1>&2 \+ - else - wsrep_log_info "Cleaning the existing datadir" - find $DATA -mindepth 1 -regex $cpat -prune -o -exec rm -rfv {} 1>&2 \+ - fi - tempdir=$(parse_cnf mysqld log-bin "") - if [[ -n ${tempdir:-} ]];then - binlog_dir=$(dirname $tempdir) - binlog_file=$(basename $tempdir) - if [[ -n ${binlog_dir:-} && $binlog_dir != '.' && $binlog_dir != $DATA ]];then - pattern="$binlog_dir/$binlog_file\.[0-9]+$" - wsrep_log_info "Cleaning the binlog directory $binlog_dir as well" - find $binlog_dir -maxdepth 1 -type f -regex $pattern -exec rm -fv {} 1>&2 \+ - rm $binlog_dir/*.index || true - fi - fi - - else - wsrep_log_info "Removing existing ib_logfile files" - rm -f ${BDATA}/ib_logfile* - fi - - - if [[ $speciald -eq 1 ]];then - mkdir -p ${DATA}/.sst - TDATA=${DATA} - DATA="${DATA}/.sst" - fi - - - MAGIC_FILE="${DATA}/${INFO_FILE}" - recv_joiner $DATA "${stagemsg}-SST" 0 - - get_proc - - # Rebuild indexes for compact backups - if grep -q 'compact = 1' ${DATA}/xtrabackup_checkpoints;then - wsrep_log_info "Index compaction detected" - rebuild=1 - fi - - if [[ $rebuild -eq 1 ]];then - nthreads=$(parse_cnf xtrabackup rebuild-threads $nproc) - wsrep_log_info "Rebuilding during prepare with $nthreads threads" - rebuildcmd="--rebuild-indexes --rebuild-threads=$nthreads" - fi - - if test -n "$(find ${DATA} -maxdepth 1 -type f -name '*.qp' -print -quit)";then - - wsrep_log_info "Compressed qpress files found" - - if [[ ! -x `which qpress` ]];then - wsrep_log_error "qpress not found in path: $PATH" - exit 22 - fi - - if [[ -n $progress ]] && pv --help | grep -q 'line-mode';then - count=$(find ${DATA} -type f -name '*.qp' | wc -l) - count=$(( count*2 )) - if pv --help | grep -q FORMAT;then - pvopts="-f -s $count -l -N Decompression -F '%N => Rate:%r Elapsed:%t %e Progress: [%b/$count]'" - else - pvopts="-f -s $count -l -N Decompression" - fi - pcmd="pv $pvopts" - adjust_progress - dcmd="$pcmd | xargs -n 2 qpress -T${nproc}d" - else - dcmd="xargs -n 2 qpress -T${nproc}d" - fi - - - # Decompress the qpress files - wsrep_log_info "Decompression with $nproc threads" - timeit "Joiner-Decompression" "find ${DATA} -type f -name '*.qp' -printf '%p\n%h\n' | $dcmd" - extcode=$? - - if [[ $extcode -eq 0 ]];then - wsrep_log_info "Removing qpress files after decompression" - find ${DATA} -type f -name '*.qp' -delete - if [[ $? -ne 0 ]];then - wsrep_log_error "Something went wrong with deletion of qpress files. Investigate" - fi - else - wsrep_log_error "Decompression failed. Exit code: $extcode" - exit 22 - fi - fi - - - if [[ ! -z $WSREP_SST_OPT_BINLOG ]];then - - BINLOG_DIRNAME=$(dirname $WSREP_SST_OPT_BINLOG) - BINLOG_FILENAME=$(basename $WSREP_SST_OPT_BINLOG) - - # To avoid comparing data directory and BINLOG_DIRNAME - mv $DATA/${BINLOG_FILENAME}.* $BINLOG_DIRNAME/ 2>/dev/null || true - - pushd $BINLOG_DIRNAME &>/dev/null - for bfiles in $(ls -1 ${BINLOG_FILENAME}.*);do - echo ${BINLOG_DIRNAME}/${bfiles} >> ${BINLOG_FILENAME}.index - done - popd &> /dev/null - - fi - - if [[ $incremental -eq 1 ]];then - # Added --ibbackup=xtrabackup_55 because it fails otherwise citing connection issues. - INNOAPPLY="${INNOBACKUPEX_BIN} $disver --defaults-file=${WSREP_SST_OPT_CONF} \ - --ibbackup=xtrabackup_56 --apply-log $rebuildcmd --redo-only $BDATA --incremental-dir=${DATA} &>>${BDATA}/innobackup.prepare.log" - fi - - wsrep_log_info "Preparing the backup at ${DATA}" - timeit "Xtrabackup prepare stage" "$INNOAPPLY" - - if [ $? -ne 0 ]; - then - wsrep_log_error "${INNOBACKUPEX_BIN} apply finished with errors. Check ${DATA}/innobackup.prepare.log" - exit 22 - fi - - if [[ $speciald -eq 1 ]];then - MAGIC_FILE="${TDATA}/${INFO_FILE}" - set +e - rm $TDATA/innobackup.prepare.log $TDATA/innobackup.move.log - set -e - wsrep_log_info "Moving the backup to ${TDATA}" - timeit "Xtrabackup move stage" "$INNOMOVE" - if [[ $? -eq 0 ]];then - 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 ${DATA}/innobackup.move.log for details" - fi - fi - - if [[ $incremental -eq 1 ]];then - wsrep_log_info "Cleaning up ${DATA} after incremental SST" - [[ -d ${DATA} ]] && rm -rf ${DATA} - DATA=$BDATA - fi - - else - 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" - exit 2 - fi - cat "${MAGIC_FILE}" # output UUID:seqno - wsrep_log_info "Total time on joiner: $totime seconds" -fi - -exit 0 diff --git a/support-files/CMakeLists.txt b/support-files/CMakeLists.txt index e9abb63a7dc..923eb52c1cb 100644 --- a/support-files/CMakeLists.txt +++ b/support-files/CMakeLists.txt @@ -50,7 +50,7 @@ ENDFOREACH() IF(UNIX) SET(prefix ${CMAKE_INSTALL_PREFIX}) - FOREACH(script mysqld_multi.server mysql-log-rotate binary-configure wsrep_notify) + FOREACH(script mysqld_multi.server mysql-log-rotate binary-configure wsrep_notify) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/${script}.sh ${CMAKE_CURRENT_BINARY_DIR}/${script} @ONLY ) @@ -65,7 +65,6 @@ IF(UNIX) IF(INSTALL_SUPPORTFILESDIR) INSTALL(FILES magic DESTINATION ${inst_location} COMPONENT SupportFiles) INSTALL(DIRECTORY RHEL4-SElinux/ DESTINATION ${inst_location}/SELinux/RHEL4 COMPONENT SupportFiles) - INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/wsrep_notify DESTINATION ${inst_location} COMPONENT SupportFiles) ENDIF() INSTALL(FILES mysql.m4 DESTINATION ${INSTALL_SHAREDIR}/aclocal COMPONENT Development) diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh index c98c8284a97..bdc481d39c2 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -52,6 +52,7 @@ datadir= # 0 means don't wait at all # Negative numbers mean to wait indefinitely service_startup_timeout=900 +startup_sleep=1 # Lock directory for RedHat / SuSE. lockdir='/var/lock/subsys' @@ -264,13 +265,13 @@ wait_for_ready () { fi if test -e $sst_progress_file && [ $startup_sleep -ne 10 ];then - echo $echo_n "SST in progress, setting sleep higher" + echo $echo_n "SST in progress, setting sleep intervals to 10 seconds" startup_sleep=10 fi echo $echo_n ".$echo_c" i=`expr $i + 1` - sleep 1 + sleep $startup_sleep done diff --git a/support-files/rpm/server.cnf b/support-files/rpm/server.cnf index 6170a2e4c49..b3c3a3abb38 100644 --- a/support-files/rpm/server.cnf +++ b/support-files/rpm/server.cnf @@ -22,7 +22,7 @@ #binlog_format=row #default_storage_engine=InnoDB #innodb_autoinc_lock_mode=2 -#query_cache_size=0 +#bind-address=0.0.0.0 # # Optional setting #innodb_flush_log_at_trx_commit=0 diff --git a/support-files/wsrep.cnf b/support-files/wsrep.cnf deleted file mode 100644 index 756d4f6783b..00000000000 --- a/support-files/wsrep.cnf +++ /dev/null @@ -1,129 +0,0 @@ -# This file contains wsrep-related mysqld options. It should be included -# in the main MySQL configuration file. -# -# Options that need to be customized: -# - wsrep_provider -# - wsrep_cluster_address -# - wsrep_sst_auth -# The rest of defaults should work out of the box. - -## -## mysqld options _MANDATORY_ for correct opration of the cluster -## -[mysqld] - -# (This must be substituted by wsrep_format) -binlog_format=ROW - -# Currently only InnoDB storage engine is supported -default-storage-engine=innodb - -# to avoid issues with 'bulk mode inserts' using autoinc -innodb_autoinc_lock_mode=2 - -# This is a must for paralell applying -innodb_locks_unsafe_for_binlog=1 - -# Query Cache is not supported with wsrep -query_cache_size=0 -query_cache_type=0 - -# Override bind-address -# In some systems bind-address defaults to 127.0.0.1, and with mysqldump SST -# it will have (most likely) disastrous consequences on donor node -bind-address=0.0.0.0 - -## -## WSREP options -## - -# Full path to wsrep provider library or 'none' -wsrep_provider=none - -# Provider specific configuration options -#wsrep_provider_options= - -# Logical cluster name. Should be the same for all nodes. -wsrep_cluster_name="my_wsrep_cluster" - -# Group communication system handle -#wsrep_cluster_address="dummy://" - -# Human-readable node name (non-unique). Hostname by default. -#wsrep_node_name= - -# Base replication [:port] of the node. -# The values supplied will be used as defaults for state transfer receiving, -# listening ports and so on. Default: address of the first network interface. -#wsrep_node_address= - -# Address for incoming client connections. Autodetect by default. -#wsrep_node_incoming_address= - -# How many threads will process writesets from other nodes -wsrep_slave_threads=1 - -# DBUG options for wsrep provider -#wsrep_dbug_option - -# Generate fake primary keys for non-PK tables (required for multi-master -# and parallel applying operation) -wsrep_certify_nonPK=1 - -# Maximum number of rows in write set -wsrep_max_ws_rows=131072 - -# Maximum size of write set -wsrep_max_ws_size=1073741824 - -# to enable debug level logging, set this to 1 -wsrep_debug=0 - -# convert locking sessions into transactions -wsrep_convert_LOCK_to_trx=0 - -# how many times to retry deadlocked autocommits -wsrep_retry_autocommit=1 - -# change auto_increment_increment and auto_increment_offset automatically -wsrep_auto_increment_control=1 - -# retry autoinc insert, which failed for duplicate key error -wsrep_drupal_282555_workaround=0 - -# enable "strictly synchronous" semantics for read operations -wsrep_causal_reads=0 - -# Command to call when node status or cluster membership changes. -# Will be passed all or some of the following options: -# --status - new status of this node -# --uuid - UUID of the cluster -# --primary - whether the component is primary or not ("yes"/"no") -# --members - comma-separated list of members -# --index - index of this node in the list -wsrep_notify_cmd= - -## -## WSREP State Transfer options -## - -# State Snapshot Transfer method -wsrep_sst_method=rsync - -# Address which donor should send State Snapshot to. -# Should be the address of THIS node. DON'T SET IT TO DONOR ADDRESS!!! -# (SST method dependent. Defaults to the first IP of the first interface) -#wsrep_sst_receive_address= - -# SST authentication string. This will be used to send SST to joining nodes. -# Depends on SST method. For mysqldump method it is root: -wsrep_sst_auth=root: - -# Desired SST donor name. -#wsrep_sst_donor= - -# Reject client queries when donating SST (false) -#wsrep_sst_donor_rejects_queries=0 - -# Protocol version to use -# wsrep_protocol_version= diff --git a/support-files/wsrep.cnf.sh.moved b/support-files/wsrep.cnf.sh.moved deleted file mode 100644 index 756d4f6783b..00000000000 --- a/support-files/wsrep.cnf.sh.moved +++ /dev/null @@ -1,129 +0,0 @@ -# This file contains wsrep-related mysqld options. It should be included -# in the main MySQL configuration file. -# -# Options that need to be customized: -# - wsrep_provider -# - wsrep_cluster_address -# - wsrep_sst_auth -# The rest of defaults should work out of the box. - -## -## mysqld options _MANDATORY_ for correct opration of the cluster -## -[mysqld] - -# (This must be substituted by wsrep_format) -binlog_format=ROW - -# Currently only InnoDB storage engine is supported -default-storage-engine=innodb - -# to avoid issues with 'bulk mode inserts' using autoinc -innodb_autoinc_lock_mode=2 - -# This is a must for paralell applying -innodb_locks_unsafe_for_binlog=1 - -# Query Cache is not supported with wsrep -query_cache_size=0 -query_cache_type=0 - -# Override bind-address -# In some systems bind-address defaults to 127.0.0.1, and with mysqldump SST -# it will have (most likely) disastrous consequences on donor node -bind-address=0.0.0.0 - -## -## WSREP options -## - -# Full path to wsrep provider library or 'none' -wsrep_provider=none - -# Provider specific configuration options -#wsrep_provider_options= - -# Logical cluster name. Should be the same for all nodes. -wsrep_cluster_name="my_wsrep_cluster" - -# Group communication system handle -#wsrep_cluster_address="dummy://" - -# Human-readable node name (non-unique). Hostname by default. -#wsrep_node_name= - -# Base replication [:port] of the node. -# The values supplied will be used as defaults for state transfer receiving, -# listening ports and so on. Default: address of the first network interface. -#wsrep_node_address= - -# Address for incoming client connections. Autodetect by default. -#wsrep_node_incoming_address= - -# How many threads will process writesets from other nodes -wsrep_slave_threads=1 - -# DBUG options for wsrep provider -#wsrep_dbug_option - -# Generate fake primary keys for non-PK tables (required for multi-master -# and parallel applying operation) -wsrep_certify_nonPK=1 - -# Maximum number of rows in write set -wsrep_max_ws_rows=131072 - -# Maximum size of write set -wsrep_max_ws_size=1073741824 - -# to enable debug level logging, set this to 1 -wsrep_debug=0 - -# convert locking sessions into transactions -wsrep_convert_LOCK_to_trx=0 - -# how many times to retry deadlocked autocommits -wsrep_retry_autocommit=1 - -# change auto_increment_increment and auto_increment_offset automatically -wsrep_auto_increment_control=1 - -# retry autoinc insert, which failed for duplicate key error -wsrep_drupal_282555_workaround=0 - -# enable "strictly synchronous" semantics for read operations -wsrep_causal_reads=0 - -# Command to call when node status or cluster membership changes. -# Will be passed all or some of the following options: -# --status - new status of this node -# --uuid - UUID of the cluster -# --primary - whether the component is primary or not ("yes"/"no") -# --members - comma-separated list of members -# --index - index of this node in the list -wsrep_notify_cmd= - -## -## WSREP State Transfer options -## - -# State Snapshot Transfer method -wsrep_sst_method=rsync - -# Address which donor should send State Snapshot to. -# Should be the address of THIS node. DON'T SET IT TO DONOR ADDRESS!!! -# (SST method dependent. Defaults to the first IP of the first interface) -#wsrep_sst_receive_address= - -# SST authentication string. This will be used to send SST to joining nodes. -# Depends on SST method. For mysqldump method it is root: -wsrep_sst_auth=root: - -# Desired SST donor name. -#wsrep_sst_donor= - -# Reject client queries when donating SST (false) -#wsrep_sst_donor_rejects_queries=0 - -# Protocol version to use -# wsrep_protocol_version= diff --git a/support-files/wsrep_notify b/support-files/wsrep_notify deleted file mode 100644 index bdbe3d12a39..00000000000 --- a/support-files/wsrep_notify +++ /dev/null @@ -1,102 +0,0 @@ -#!/bin/sh -eu - -# This is a simple example of wsrep notification script (wsrep_notify_cmd). -# It will create 'wsrep' schema and two tables in it: 'membeship' and 'status' -# and fill them on every membership or node status change. -# -# Edit parameters below to specify the address and login to server. - -USER=root -PSWD=rootpass -HOST=127.0.0.1 -PORT=3306 - -SCHEMA="wsrep" -MEMB_TABLE="$SCHEMA.membership" -STATUS_TABLE="$SCHEMA.status" - -BEGIN=" -SET wsrep_on=0; -DROP SCHEMA IF EXISTS $SCHEMA; CREATE SCHEMA $SCHEMA; -CREATE TABLE $MEMB_TABLE ( - idx INT UNIQUE PRIMARY KEY, - uuid CHAR(40) UNIQUE, /* node UUID */ - name VARCHAR(32), /* node name */ - addr VARCHAR(256) /* node address */ -) ENGINE=MEMORY; -CREATE TABLE $STATUS_TABLE ( - size INT, /* component size */ - idx INT, /* this node index */ - status CHAR(16), /* this node status */ - uuid CHAR(40), /* cluster UUID */ - prim BOOLEAN /* if component is primary */ -) ENGINE=MEMORY; -BEGIN; -DELETE FROM $MEMB_TABLE; -DELETE FROM $STATUS_TABLE; -" -END="COMMIT;" - -configuration_change() -{ - echo "$BEGIN;" - - local idx=0 - - for NODE in $(echo $MEMBERS | sed s/,/\ /g) - do - echo "INSERT INTO $MEMB_TABLE VALUES ( $idx, " - # Don't forget to properly quote string values - echo "'$NODE'" | sed s/\\//\',\'/g - echo ");" - idx=$(( $idx + 1 )) - done - - echo "INSERT INTO $STATUS_TABLE VALUES($idx, $INDEX, '$STATUS', '$CLUSTER_UUID', $PRIMARY);" - - echo "$END" -} - -status_update() -{ - echo "SET wsrep_on=0; BEGIN; UPDATE $STATUS_TABLE SET status='$STATUS'; COMMIT;" -} - -COM=status_update # not a configuration change by default - -while [ $# -gt 0 ] -do - case $1 in - --status) - STATUS=$2 - shift - ;; - --uuid) - CLUSTER_UUID=$2 - shift - ;; - --primary) - [ "$2" = "yes" ] && PRIMARY="1" || PRIMARY="0" - COM=configuration_change - shift - ;; - --index) - INDEX=$2 - shift - ;; - --members) - MEMBERS=$2 - shift - ;; - esac - shift -done - -# Undefined means node is shutting down -if [ "$STATUS" != "Undefined" ] -then - $COM | mysql -B -u$USER -p$PSWD -h$HOST -P$PORT -fi - -exit 0 -# From bef30f2e306dc6107f0ec314bf7bde8939c124e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Fri, 26 Sep 2014 12:16:05 +0300 Subject: [PATCH 053/153] Fix test failures seen on -- innodb-wl5522-debug-zip (path differences win/unix) -- innodb_defragment_fill_factor (stabilise) -- innodb_force_pk (case difference win/unix) --- .../innodb/r/innodb-wl5522-debug-zip.result | 6 +- .../r/innodb_defragment_fill_factor.result | 40 ++++++++---- .../suite/innodb/r/innodb_force_pk.result | 58 ++++++++--------- .../innodb/t/innodb-wl5522-debug-zip.test | 11 ++-- .../t/innodb_defragment_fill_factor.test | 64 +++++++++++-------- .../suite/innodb/t/innodb_force_pk.test | 44 ++++++------- 6 files changed, 122 insertions(+), 101 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb-wl5522-debug-zip.result b/mysql-test/suite/innodb/r/innodb-wl5522-debug-zip.result index a4e44be1c72..0e863f5849e 100644 --- a/mysql-test/suite/innodb/r/innodb-wl5522-debug-zip.result +++ b/mysql-test/suite/innodb/r/innodb-wl5522-debug-zip.result @@ -104,7 +104,7 @@ restore: t1 .ibd and .cfg files SET SESSION debug_dbug="-d,ib_import_reset_space_and_lsn_failure"; SET SESSION debug_dbug="+d,ib_import_open_tablespace_failure"; ALTER TABLE test_wl5522.t1 IMPORT TABLESPACE; -ERROR HY000: Got error 44 'Tablespace not found' from ./test_wl5522/t1.ibd +ERROR HY000: Got error 44 't1.ibd SET SESSION debug_dbug="-d,ib_import_open_tablespace_failure"; restore: t1 .ibd and .cfg files SET SESSION debug_dbug="+d,ib_import_check_bitmap_failure"; @@ -537,7 +537,7 @@ ERROR HY000: Tablespace has been discarded for table 't1' restore: t1 .ibd and .cfg files SET SESSION debug_dbug="+d,fil_space_create_failure"; ALTER TABLE test_wl5522.t1 IMPORT TABLESPACE; -ERROR HY000: Got error 11 'Generic error' from ./test_wl5522/t1.ibd +ERROR HY000: Got error 11 't1.ibd SET SESSION debug_dbug="-d,fil_space_create_failure"; DROP TABLE test_wl5522.t1; unlink: t1.ibd @@ -550,7 +550,7 @@ ERROR HY000: Tablespace has been discarded for table 't1' restore: t1 .ibd and .cfg files SET SESSION debug_dbug="+d,dict_tf_to_fsp_flags_failure"; ALTER TABLE test_wl5522.t1 IMPORT TABLESPACE; -ERROR HY000: Got error 39 'Data structure corruption' from ./test_wl5522/t1.ibd +ERROR HY000: Got error 39 't1.ibd SET SESSION debug_dbug="-d,dict_tf_to_fsp_flags_failure"; DROP TABLE test_wl5522.t1; unlink: t1.ibd diff --git a/mysql-test/suite/innodb/r/innodb_defragment_fill_factor.result b/mysql-test/suite/innodb/r/innodb_defragment_fill_factor.result index 7c153eaaa93..04e41046a6a 100644 --- a/mysql-test/suite/innodb/r/innodb_defragment_fill_factor.result +++ b/mysql-test/suite/innodb/r/innodb_defragment_fill_factor.result @@ -2,32 +2,48 @@ DROP TABLE if exists t1; DROP TABLE if exists t2; Testing tables with large records CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b VARCHAR(256), KEY SECOND(a, b)) ENGINE=INNODB; +INSERT INTO t1 VALUES (1, REPEAT('A', 256)); +INSERT INTO t1 (b) SELECT b from t1; +INSERT INTO t1 (b) SELECT b from t1; +INSERT INTO t1 (b) SELECT b from t1; +INSERT INTO t1 (b) SELECT b from t1; +INSERT INTO t1 (b) SELECT b from t1; +INSERT INTO t1 (b) SELECT b from t1; +INSERT INTO t1 (b) SELECT b from t1; +INSERT INTO t1 (b) SELECT b from t1; +INSERT INTO t1 (b) SELECT b from t1; +INSERT INTO t1 (b) SELECT b from t1; optimize table t1; Table Op Msg_type Msg_text test.t1 optimize status OK +select sleep(1); +sleep(1) +0 select count(*) from t1; count(*) -790 +927 select count(*) from t1 force index (second); count(*) -790 +927 # A few more insertions on the page should not cause a page split. insert into t1 values (81, REPEAT('A', 256)); insert into t1 values (83, REPEAT('A', 256)); -# More insertions will cause page splits -insert into t1 values (88, REPEAT('A', 50)); -insert into t1 values (85, REPEAT('A', 256)); -insert into t1 values (84, REPEAT('A', 256)); insert into t1 values (87, REPEAT('A', 256)); -insert into t1 values (89, REPEAT('A', 256)); insert into t1 values (82, REPEAT('A', 256)); insert into t1 values (86, REPEAT('A', 256)); +# More insertions will cause page splits +insert into t1 values (88, REPEAT('A', 256)); +insert into t1 values (85, REPEAT('A', 256)); +insert into t1 values (84, REPEAT('A', 256)); DROP TABLE t1; Testing table with small records CREATE TABLE t2 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b VARchar(16), KEY SECOND(a,b)) ENGINE=INNODB; optimize table t2; Table Op Msg_type Msg_text test.t2 optimize status OK +select sleep(1); +sleep(1) +0 select count(*) from t2 force index(second); count(*) 3701 @@ -49,16 +65,12 @@ insert into t2 values(1197, REPEAT('A', 16)); insert into t2 values(1188, REPEAT('A', 16)); insert into t2 values(1198, REPEAT('A', 16)); insert into t2 values(1189, REPEAT('A', 16)); +insert into t2 values(1199, REPEAT('A', 16)); +insert into t2 values(1190, REPEAT('A', 16)); +insert into t2 values(1180, REPEAT('A', 16)); More insertions will cause page split. insert into t2 values(1280, REPEAT('A', 16)); insert into t2 values(1290, REPEAT('A', 16)); insert into t2 values(1281, REPEAT('A', 16)); insert into t2 values(1291, REPEAT('A', 16)); -insert into t2 values(1199, REPEAT('A', 16)); -insert into t2 values(1190, REPEAT('A', 16)); -insert into t2 values(1180, REPEAT('A', 16)); -insert into t2 values(1295, REPEAT('A', 16)); -insert into t2 values(1294, REPEAT('A', 16)); -insert into t2 values(1292, REPEAT('A', 16)); -insert into t2 values(1293, REPEAT('A', 16)); DROP TABLE t2; diff --git a/mysql-test/suite/innodb/r/innodb_force_pk.result b/mysql-test/suite/innodb/r/innodb_force_pk.result index d8abfda35e1..ea8fd784320 100644 --- a/mysql-test/suite/innodb/r/innodb_force_pk.result +++ b/mysql-test/suite/innodb/r/innodb_force_pk.result @@ -1,53 +1,53 @@ -CREATE TABLE T1(A INTEGER) ENGINE=INNODB; +create table t1(a integer) engine=innodb; ERROR 42000: This table type requires a primary key -SHOW WARNINGS; +show warnings; Level Code Message Error 1173 This table type requires a primary key -CREATE TABLE T1(A INTEGER UNIQUE KEY) ENGINE=INNODB; +create table t1(a integer unique key) engine=innodb; ERROR 42000: This table type requires a primary key -SHOW WARNINGS; +show warnings; Level Code Message Error 1173 This table type requires a primary key -CREATE TABLE T1(A INTEGER NOT NULL, B INTEGER, -UNIQUE KEY(A,B)) ENGINE=INNODB; +create table t1(a integer not null, b integer, +unique key(a,b)) engine=innodb; ERROR 42000: This table type requires a primary key -SHOW WARNINGS; +show warnings; Level Code Message Error 1173 This table type requires a primary key -CREATE TABLE T1(A INTEGER NOT NULL PRIMARY KEY) ENGINE=INNODB; -SHOW CREATE TABLE T1; +create table t1(a integer not null primary key) engine=innodb; +show create table t1; Table Create Table -T1 CREATE TABLE `T1` ( - `A` int(11) NOT NULL, - PRIMARY KEY (`A`) +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + PRIMARY KEY (`a`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 -SHOW WARNINGS; +show warnings; Level Code Message -DROP TABLE T1; -CREATE TABLE T1(A INTEGER NOT NULL UNIQUE KEY) ENGINE=INNODB; -SHOW CREATE TABLE T1; +drop table t1; +create table t1(a integer not null unique key) engine=innodb; +show create table t1; Table Create Table -T1 CREATE TABLE `T1` ( - `A` int(11) NOT NULL, - UNIQUE KEY `A` (`A`) +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + UNIQUE KEY `a` (`a`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 -SHOW WARNINGS; +show warnings; Level Code Message -DROP TABLE T1; +drop table t1; set global innodb_force_primary_key = 0; -CREATE TABLE T1(A INTEGER) ENGINE=INNODB; -SHOW WARNINGS; +create table t1(a integer) engine=innodb; +show warnings; Level Code Message -INSERT INTO T1 VALUES (1),(2),(3); +insert into t1 values (1),(2),(3); set global innodb_force_primary_key = 1; -SELECT * FROM T1; -A +select * from t1; +a 1 2 3 -CREATE TABLE T2(A INTEGER) ENGINE=INNODB; +create table t2(a integer) engine=innodb; ERROR 42000: This table type requires a primary key -SHOW WARNINGS; +show warnings; Level Code Message Error 1173 This table type requires a primary key -DROP TABLE T1; +drop table t1; diff --git a/mysql-test/suite/innodb/t/innodb-wl5522-debug-zip.test b/mysql-test/suite/innodb/t/innodb-wl5522-debug-zip.test index 1290b9b5bb7..4b03ac008d2 100644 --- a/mysql-test/suite/innodb/t/innodb-wl5522-debug-zip.test +++ b/mysql-test/suite/innodb/t/innodb-wl5522-debug-zip.test @@ -22,7 +22,7 @@ let MYSQLD_DATADIR =`SELECT @@datadir`; let $innodb_file_per_table = `SELECT @@innodb_file_per_table`; let $innodb_file_format = `SELECT @@innodb_file_format`; let $innodb_strict_mode_orig=`select @@session.innodb_strict_mode`; -let $pathfix=/: '.*test_wl5522.*t1.ibd'/: 'test_wl5522\\t1.ibd'/; +let $pathfix=/: '.*test_wl5522.*t1.ibd'/: 'test_wl5522_t1.ibd'/; SET GLOBAL innodb_file_per_table = 1; SELECT @@innodb_file_per_table; @@ -233,8 +233,7 @@ SET SESSION debug_dbug="-d,ib_import_reset_space_and_lsn_failure"; # Test failure after attempting a tablespace open SET SESSION debug_dbug="+d,ib_import_open_tablespace_failure"; ---replace_regex /file: '.*t1.ibd'/'t1.ibd'/ - +--replace_regex /'.*[\/\\]/'/ --error ER_GET_ERRMSG ALTER TABLE test_wl5522.t1 IMPORT TABLESPACE; @@ -637,8 +636,7 @@ EOF SET SESSION debug_dbug="+d,fil_space_create_failure"; ---replace_regex $pathfix - +--replace_regex /'.*[\/\\]/'/ --error ER_GET_ERRMSG ALTER TABLE test_wl5522.t1 IMPORT TABLESPACE; @@ -669,8 +667,7 @@ EOF SET SESSION debug_dbug="+d,dict_tf_to_fsp_flags_failure"; ---replace_regex $pathfix - +--replace_regex /'.*[\/\\]/'/ --error ER_GET_ERRMSG ALTER TABLE test_wl5522.t1 IMPORT TABLESPACE; diff --git a/mysql-test/suite/innodb/t/innodb_defragment_fill_factor.test b/mysql-test/suite/innodb/t/innodb_defragment_fill_factor.test index 24c23448a30..a46ca124f51 100644 --- a/mysql-test/suite/innodb/t/innodb_defragment_fill_factor.test +++ b/mysql-test/suite/innodb/t/innodb_defragment_fill_factor.test @@ -2,47 +2,62 @@ --source include/big_test.inc --source include/not_valgrind.inc --source include/not_embedded.inc +--source include/have_innodb_16k.inc --disable_warnings DROP TABLE if exists t1; DROP TABLE if exists t2; --enable_warnings + --echo Testing tables with large records # Create table. CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b VARCHAR(256), KEY SECOND(a, b)) ENGINE=INNODB; + # Populate table. -let $i = 1000; ---disable_query_log -while ($i) -{ - eval - INSERT INTO t1 VALUES ($i, REPEAT('A', 256)); - dec $i; -} ---enable_query_log +INSERT INTO t1 VALUES (1, REPEAT('A', 256)); +INSERT INTO t1 (b) SELECT b from t1; +INSERT INTO t1 (b) SELECT b from t1; +INSERT INTO t1 (b) SELECT b from t1; +INSERT INTO t1 (b) SELECT b from t1; +INSERT INTO t1 (b) SELECT b from t1; +INSERT INTO t1 (b) SELECT b from t1; +INSERT INTO t1 (b) SELECT b from t1; +INSERT INTO t1 (b) SELECT b from t1; +INSERT INTO t1 (b) SELECT b from t1; +INSERT INTO t1 (b) SELECT b from t1; + --disable_query_log let $size = 10; while ($size) { let $j = 100 * $size; - eval delete from t1 where a between $j - 20 and $j; + eval delete from t1 where a between $j - 20 and $j + 5; dec $size; } --enable_query_log + +--source include/restart_mysqld.inc optimize table t1; +select sleep(1); + --source include/restart_mysqld.inc select count(*) from t1; + # After deletion & defragmentation, there are 800 records left. Each page can hold about 57 records. We fill the page 90% full, # so there should be less than 16 pages total. --let $primary_before = query_get_value(select count(*) as Value from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'PRIMARY', Value, 1) + select count(*) from t1 force index (second); + # secondary index is slightly bigger than primary index so the number of pages should be similar. --let $second_before = query_get_value(select count(*) as Value from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'second', Value, 1) --echo # A few more insertions on the page should not cause a page split. insert into t1 values (81, REPEAT('A', 256)); insert into t1 values (83, REPEAT('A', 256)); - +insert into t1 values (87, REPEAT('A', 256)); +insert into t1 values (82, REPEAT('A', 256)); +insert into t1 values (86, REPEAT('A', 256)); --let $primary_after = query_get_value(select count(*) as Value from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'PRIMARY', Value, 1) --let $second_after = query_get_value(select count(*) as Value from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'second', Value, 1) @@ -55,14 +70,9 @@ if ($second_before != $second_after) { } --echo # More insertions will cause page splits -insert into t1 values (88, REPEAT('A', 50)); +insert into t1 values (88, REPEAT('A', 256)); insert into t1 values (85, REPEAT('A', 256)); insert into t1 values (84, REPEAT('A', 256)); -insert into t1 values (87, REPEAT('A', 256)); -insert into t1 values (89, REPEAT('A', 256)); -insert into t1 values (82, REPEAT('A', 256)); -insert into t1 values (86, REPEAT('A', 256)); - --let $primary_after = query_get_value(select count(*) as Value from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'PRIMARY', Value, 1) --let $second_after = query_get_value(select count(*) as Value from information_schema.innodb_buffer_page where table_name like '%t1%' and index_name = 'second', Value, 1) @@ -94,6 +104,7 @@ INSERT INTO t2 (b) SELECT b from t2; INSERT INTO t2 (b) SELECT b from t2; INSERT INTO t2 (b) SELECT b from t2; --enable_query_log + --disable_query_log let $size = 40; while ($size) @@ -103,10 +114,16 @@ while ($size) dec $size; } --enable_query_log + +--source include/restart_mysqld.inc optimize table t2; +select sleep(1); + --source include/restart_mysqld.inc select count(*) from t2 force index(second); + --let $second_before = query_get_value(select count(*) as Value from information_schema.innodb_buffer_page where table_name like '%t2%' and index_name = 'second', Value, 1) + --echo The page should have room for about 20 insertions insert into t2 values(1181, REPEAT('A', 16)); insert into t2 values(1191, REPEAT('A', 16)); @@ -125,6 +142,9 @@ insert into t2 values(1197, REPEAT('A', 16)); insert into t2 values(1188, REPEAT('A', 16)); insert into t2 values(1198, REPEAT('A', 16)); insert into t2 values(1189, REPEAT('A', 16)); +insert into t2 values(1199, REPEAT('A', 16)); +insert into t2 values(1190, REPEAT('A', 16)); +insert into t2 values(1180, REPEAT('A', 16)); --let $second_after = query_get_value(select count(*) as Value from information_schema.innodb_buffer_page where table_name like '%t2%' and index_name = 'second', Value, 1) @@ -137,18 +157,10 @@ insert into t2 values(1280, REPEAT('A', 16)); insert into t2 values(1290, REPEAT('A', 16)); insert into t2 values(1281, REPEAT('A', 16)); insert into t2 values(1291, REPEAT('A', 16)); -insert into t2 values(1199, REPEAT('A', 16)); -insert into t2 values(1190, REPEAT('A', 16)); -insert into t2 values(1180, REPEAT('A', 16)); -insert into t2 values(1295, REPEAT('A', 16)); -insert into t2 values(1294, REPEAT('A', 16)); -insert into t2 values(1292, REPEAT('A', 16)); -insert into t2 values(1293, REPEAT('A', 16)); --let $second_after = query_get_value(select count(*) as Value from information_schema.innodb_buffer_page where table_name like '%t2%' and index_name = 'second', Value, 1) - if ($second_before == $second_after) { --echo Too much space are reserved on second index. } -DROP TABLE t2; +DROP TABLE t2; \ No newline at end of file diff --git a/mysql-test/suite/innodb/t/innodb_force_pk.test b/mysql-test/suite/innodb/t/innodb_force_pk.test index 4361a58d2f5..48986ca2fee 100644 --- a/mysql-test/suite/innodb/t/innodb_force_pk.test +++ b/mysql-test/suite/innodb/t/innodb_force_pk.test @@ -3,35 +3,35 @@ let $force_pk=`select @@innodb_force_primary_key`; -- error 1173 -CREATE TABLE T1(A INTEGER) ENGINE=INNODB; -SHOW WARNINGS; +create table t1(a integer) engine=innodb; +show warnings; -- error 1173 -CREATE TABLE T1(A INTEGER UNIQUE KEY) ENGINE=INNODB; -SHOW WARNINGS; +create table t1(a integer unique key) engine=innodb; +show warnings; -- error 1173 -CREATE TABLE T1(A INTEGER NOT NULL, B INTEGER, -UNIQUE KEY(A,B)) ENGINE=INNODB; -SHOW WARNINGS; -CREATE TABLE T1(A INTEGER NOT NULL PRIMARY KEY) ENGINE=INNODB; -SHOW CREATE TABLE T1; -SHOW WARNINGS; -DROP TABLE T1; -CREATE TABLE T1(A INTEGER NOT NULL UNIQUE KEY) ENGINE=INNODB; -SHOW CREATE TABLE T1; -SHOW WARNINGS; -DROP TABLE T1; +create table t1(a integer not null, b integer, +unique key(a,b)) engine=innodb; +show warnings; +create table t1(a integer not null primary key) engine=innodb; +show create table t1; +show warnings; +drop table t1; +create table t1(a integer not null unique key) engine=innodb; +show create table t1; +show warnings; +drop table t1; set global innodb_force_primary_key = 0; -CREATE TABLE T1(A INTEGER) ENGINE=INNODB; -SHOW WARNINGS; -INSERT INTO T1 VALUES (1),(2),(3); +create table t1(a integer) engine=innodb; +show warnings; +insert into t1 values (1),(2),(3); set global innodb_force_primary_key = 1; -SELECT * FROM T1; +select * from t1; -- error 1173 -CREATE TABLE T2(A INTEGER) ENGINE=INNODB; -SHOW WARNINGS; -DROP TABLE T1; +create table t2(a integer) engine=innodb; +show warnings; +drop table t1; --disable_query_log eval set global innodb_force_primary_key=$force_pk; From 0b15557c8fec3de5c3ef3cce2b5ff9340159751f Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Fri, 26 Sep 2014 15:54:35 +0400 Subject: [PATCH 054/153] MDEV-6796: Unable to skip filesort when using implicit extended key Re-work test_if_order_by_key() to work correctly for extended indexes. --- mysql-test/r/order_by_optimizer_innodb.result | 42 ++++++ mysql-test/t/order_by_optimizer_innodb.test | 47 +++++++ sql/field.h | 6 + sql/sql_select.cc | 122 ++++++++---------- 4 files changed, 149 insertions(+), 68 deletions(-) diff --git a/mysql-test/r/order_by_optimizer_innodb.result b/mysql-test/r/order_by_optimizer_innodb.result index 212139a287e..423e43ea5a2 100644 --- a/mysql-test/r/order_by_optimizer_innodb.result +++ b/mysql-test/r/order_by_optimizer_innodb.result @@ -46,3 +46,45 @@ EXPLAIN SELECT * FROM t2 WHERE pk1=9 AND fd5 < 500 ORDER B id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 range PRIMARY,ux_pk1_fd5 ux_pk1_fd5 13 NULL 137 Using where drop table t0,t1, t2; +# +# MDEV-6796: Unable to skip filesort when using implicit extended key +# +CREATE TABLE t1 ( +pk1 int(11) NOT NULL, +pk2 varchar(64) NOT NULL, +col1 varchar(16) DEFAULT NULL, +PRIMARY KEY (pk1,pk2), +KEY key1 (pk1,col1) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE t2 ( +pk1 int(11) NOT NULL, +pk2 varchar(64) NOT NULL, +col1 varchar(16) DEFAULT NULL, +PRIMARY KEY (pk1,pk2), +KEY key1 (pk1,col1,pk2) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +INSERT INTO `t1` VALUES +(12321321,'a8f5f167f44f4964e6c998dee827110c','video'), +(12321321,'d77a17a3659ffa60c54e0ea17b6c6d16','video'), +(12321321,'wwafdsafdsafads','video'), +(12321321,'696aa249f0738e8181957dd57c2d7d0b','video-2014-09-23'), +(12321321,'802f9f29584b486f356693e3aa4ef0af','video=sdsd'), +(12321321,'2f94543ff74aab82e9a058b4e8316d75','video=sdsdsds'), +(12321321,'c1316b9df0d203fd1b9035308de52a0a','video=sdsdsdsdsd'); +insert into t2 select * from t1; +# this must not use filesort: +explain SELECT pk2 +FROM t1 USE INDEX(key1) +WHERE pk1 = 123 +AND col1 = 'video' +ORDER BY pk2 DESC LIMIT 21; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref key1 key1 55 const,const 1 Using where; Using index +# this must not use filesort, either: +explain SELECT pk2 +FROM t2 USE INDEX(key1) +WHERE pk1 = 123 AND col1 = 'video' +ORDER BY pk2 DESC LIMIT 21; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ref key1 key1 55 const,const 1 Using where; Using index +drop table t1, t2; diff --git a/mysql-test/t/order_by_optimizer_innodb.test b/mysql-test/t/order_by_optimizer_innodb.test index d3c71e8772f..de0a0a9abcd 100644 --- a/mysql-test/t/order_by_optimizer_innodb.test +++ b/mysql-test/t/order_by_optimizer_innodb.test @@ -41,3 +41,50 @@ EXPLAIN SELECT * FROM t2 USE INDEX(ux_pk1_fd5) WHERE pk1=9 AND fd5 < 500 ORDER B EXPLAIN SELECT * FROM t2 WHERE pk1=9 AND fd5 < 500 ORDER BY fd5 DESC LIMIT 10; drop table t0,t1, t2; + +--echo # +--echo # MDEV-6796: Unable to skip filesort when using implicit extended key +--echo # + +CREATE TABLE t1 ( + pk1 int(11) NOT NULL, + pk2 varchar(64) NOT NULL, + col1 varchar(16) DEFAULT NULL, + PRIMARY KEY (pk1,pk2), + KEY key1 (pk1,col1) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE t2 ( + pk1 int(11) NOT NULL, + pk2 varchar(64) NOT NULL, + col1 varchar(16) DEFAULT NULL, + PRIMARY KEY (pk1,pk2), + KEY key1 (pk1,col1,pk2) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +INSERT INTO `t1` VALUES +(12321321,'a8f5f167f44f4964e6c998dee827110c','video'), +(12321321,'d77a17a3659ffa60c54e0ea17b6c6d16','video'), +(12321321,'wwafdsafdsafads','video'), +(12321321,'696aa249f0738e8181957dd57c2d7d0b','video-2014-09-23'), +(12321321,'802f9f29584b486f356693e3aa4ef0af','video=sdsd'), +(12321321,'2f94543ff74aab82e9a058b4e8316d75','video=sdsdsds'), +(12321321,'c1316b9df0d203fd1b9035308de52a0a','video=sdsdsdsdsd'); + +insert into t2 select * from t1; + +--echo # this must not use filesort: +explain SELECT pk2 +FROM t1 USE INDEX(key1) +WHERE pk1 = 123 +AND col1 = 'video' +ORDER BY pk2 DESC LIMIT 21; + +--echo # this must not use filesort, either: +explain SELECT pk2 +FROM t2 USE INDEX(key1) +WHERE pk1 = 123 AND col1 = 'video' +ORDER BY pk2 DESC LIMIT 21; + +drop table t1, t2; + diff --git a/sql/field.h b/sql/field.h index b5f332f5edc..fed6084fda2 100644 --- a/sql/field.h +++ b/sql/field.h @@ -281,6 +281,12 @@ public: LEX_STRING comment; /* Field is part of the following keys */ key_map key_start, part_of_key, part_of_key_not_clustered; + + /* + Bitmap of indexes that have records ordered by col1, ... this_field, ... + + For example, INDEX (col(prefix_n)) is not present in col.part_of_sortkey. + */ key_map part_of_sortkey; /* We use three additional unireg types for TIMESTAMP to overcome limitation diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 18d703648a1..cf29abcf101 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -15044,6 +15044,11 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) @retval true can be used @retval false cannot be used */ + +/* + psergey-todo: this returns false for int_column='1234' (here '1234' is a + constant. Need to discuss this with Bar). +*/ static bool test_if_equality_guarantees_uniqueness(Item *l, Item *r) { @@ -19676,12 +19681,21 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx, { KEY_PART_INFO *key_part,*key_part_end; key_part=table->key_info[idx].key_part; - key_part_end=key_part+table->key_info[idx].user_defined_key_parts; + key_part_end=key_part + table->key_info[idx].ext_key_parts; key_part_map const_key_parts=table->const_key_parts[idx]; + uint user_defined_kp= table->key_info[idx].user_defined_key_parts; int reverse=0; uint key_parts; - my_bool on_pk_suffix= FALSE; + bool have_pk_suffix= false; + uint pk= table->s->primary_key; DBUG_ENTER("test_if_order_by_key"); + + if ((table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) && + table->key_info[idx].ext_key_part_map && + pk != MAX_KEY && pk != idx) + { + have_pk_suffix= true; + } for (; order ; order=order->next, const_key_parts>>=1) { @@ -19694,58 +19708,37 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx, */ for (; const_key_parts & 1 ; const_key_parts>>= 1) key_part++; + + /* + This check was in this function historically (although I think it's + better to check it outside of this function): - if (key_part >= key_part_end) + "Test if the primary key parts were all const (i.e. there's one row). + The sorting doesn't matter" + + So, we're checking that + (1) this is an extended key + (2) we've reached its end + */ + key_parts= (key_part - table->key_info[idx].key_part); + if (have_pk_suffix && + reverse == 0 && // all were =const so far + key_parts == table->key_info[idx].ext_key_parts && + table->const_key_parts[pk] == PREV_BITS(uint, + table->key_info[pk]. + user_defined_key_parts)) { - /* - We are at the end of the key. Check if the engine has the primary - key as a suffix to the secondary keys. If it has continue to check - the primary key as a suffix. + key_parts= 0; + reverse= 1; // Key is ok to use + goto ok; + } + + if (key_part == key_part_end) + { + /* + There are some items left in ORDER BY that we don't */ - if (!on_pk_suffix && (table->key_info[idx].ext_key_part_map & 1) && - (table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) && - table->s->primary_key != MAX_KEY && - table->s->primary_key != idx) - { - KEY_PART_INFO *start,*end; - uint pk_part_idx= 0; - on_pk_suffix= TRUE; - start= key_part= table->key_info[table->s->primary_key].key_part; - const_key_parts=table->const_key_parts[table->s->primary_key]; - - /* - Calculate true key_part_end and const_key_parts - (we have to stop as first not continous primary key part) - */ - for (key_part_end= key_part, - end= key_part+table->key_info[table->s->primary_key].user_defined_key_parts; - key_part_end < end; key_part_end++, pk_part_idx++) - { - /* Found hole in the pk_parts; Abort */ - if (!(table->key_info[idx].ext_key_part_map & - (((key_part_map) 1) << pk_part_idx))) - break; - } - - /* Adjust const_key_parts */ - const_key_parts&= (((key_part_map) 1) << pk_part_idx) -1; - - for (; const_key_parts & 1 ; const_key_parts>>= 1) - key_part++; - /* - Test if the primary key parts were all const (i.e. there's one row). - The sorting doesn't matter. - */ - if (key_part == start+table->key_info[table->s->primary_key].user_defined_key_parts && - reverse == 0) - { - key_parts= 0; - reverse= 1; // Key is ok to use - goto ok; - } - } - else - DBUG_RETURN(0); + DBUG_RETURN(0); } if (key_part->field != field || !field->part_of_sortkey.is_set(idx)) @@ -19760,27 +19753,20 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx, if (key_part < key_part_end) key_part++; } - if (on_pk_suffix) - { - uint used_key_parts_secondary= table->key_info[idx].user_defined_key_parts; - uint used_key_parts_pk= - (uint) (key_part - table->key_info[table->s->primary_key].key_part); - key_parts= used_key_parts_pk + used_key_parts_secondary; - if (reverse == -1 && - (!(table->file->index_flags(idx, used_key_parts_secondary - 1, 1) & - HA_READ_PREV) || - !(table->file->index_flags(table->s->primary_key, - used_key_parts_pk - 1, 1) & HA_READ_PREV))) - reverse= 0; // Index can't be used - } - else + key_parts= (uint) (key_part - table->key_info[idx].key_part); + + if (reverse == -1 && + !(table->file->index_flags(idx, user_defined_kp, 1) & HA_READ_PREV)) + reverse= 0; // Index can't be used + + if (have_pk_suffix && reverse == -1) { - key_parts= (uint) (key_part - table->key_info[idx].key_part); - if (reverse == -1 && - !(table->file->index_flags(idx, key_parts-1, 1) & HA_READ_PREV)) + uint pk_parts= table->key_info[pk].user_defined_key_parts; + if (!table->file->index_flags(pk, pk_parts, 1) & HA_READ_PREV) reverse= 0; // Index can't be used } + ok: if (used_key_parts != NULL) *used_key_parts= key_parts; From fc2df3c637d51c4ab32132e2d8f63dbe7e80f056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Tue, 30 Sep 2014 14:50:34 +0300 Subject: [PATCH 055/153] MDEV-6812: Merge Kakao: Add global status variables which tell you the progress of inplace alter table and row log buffer usage - (x 100%, it's 4-digit. 10000 means 100.00%) - Innodb_onlineddl_rowlog_rows Shows how many rows are stored in row log buffer. - Innodb_onlineddl_rowlog_pct_used Shows row log buffer usage in percent ( *100%, it's 4-digit. 10000 means 100.00% ). - Innodb_onlineddl_pct_progress Shows the progress of inplace alter table. It might be not so accurate because inplace alter is highly depend on disk and buffer pool status. But still it is useful and better than nothing. - Add some log for inplace alter table XtraDB/InnoDB will print some message before and after doing some task. --- storage/innobase/handler/ha_innodb.cc | 8 ++ storage/innobase/handler/handler0alter.cc | 10 ++ storage/innobase/include/row0log.h | 4 + storage/innobase/include/row0merge.h | 17 ++- storage/innobase/include/srv0srv.h | 18 ++- storage/innobase/row/row0ftsort.cc | 2 +- storage/innobase/row/row0log.cc | 8 ++ storage/innobase/row/row0merge.cc | 144 ++++++++++++++++++++-- storage/innobase/srv/srv0srv.cc | 5 + storage/xtradb/handler/ha_innodb.cc | 8 ++ storage/xtradb/handler/handler0alter.cc | 10 ++ storage/xtradb/include/row0log.h | 4 + storage/xtradb/include/row0merge.h | 17 ++- storage/xtradb/include/srv0srv.h | 19 ++- storage/xtradb/row/row0ftsort.cc | 2 +- storage/xtradb/row/row0log.cc | 8 ++ storage/xtradb/row/row0merge.cc | 144 ++++++++++++++++++++-- storage/xtradb/srv/srv0srv.cc | 5 + 18 files changed, 408 insertions(+), 25 deletions(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 5e20cbcfc61..2b0223a6c50 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -801,6 +801,14 @@ static SHOW_VAR innodb_status_variables[]= { {"defragment_count", (char*) &export_vars.innodb_defragment_count, SHOW_LONG}, + /* Online alter table status variables */ + {"onlineddl_rowlog_rows", + (char*) &export_vars.innodb_onlineddl_rowlog_rows, SHOW_LONG}, + {"onlineddl_rowlog_pct_used", + (char*) &export_vars.innodb_onlineddl_rowlog_pct_used, SHOW_LONG}, + {"onlineddl_pct_progress", + (char*) &export_vars.innodb_onlineddl_pct_progress, SHOW_LONG}, + {NullS, NullS, SHOW_LONG} }; diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 0b13573abc6..5ba6df883aa 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -3393,6 +3393,11 @@ ha_innobase::prepare_inplace_alter_table( DBUG_ASSERT(ha_alter_info->create_info); DBUG_ASSERT(!srv_read_only_mode); + /* Init online ddl status variables */ + onlineddl_rowlog_rows = 0; + onlineddl_rowlog_pct_used = 0; + onlineddl_pct_progress = 0; + MONITOR_ATOMIC_INC(MONITOR_PENDING_ALTER_TABLE); #ifdef UNIV_DEBUG @@ -4043,6 +4048,11 @@ oom: ctx->thr, prebuilt->table, altered_table); } + /* Init online ddl status variables */ + onlineddl_rowlog_rows = 0; + onlineddl_rowlog_pct_used = 0; + onlineddl_pct_progress = 0; + DEBUG_SYNC_C("inplace_after_index_build"); DBUG_EXECUTE_IF("create_index_fail", diff --git a/storage/innobase/include/row0log.h b/storage/innobase/include/row0log.h index 62715fe8808..f105838eece 100644 --- a/storage/innobase/include/row0log.h +++ b/storage/innobase/include/row0log.h @@ -35,6 +35,10 @@ Created 2011-05-26 Marko Makela #include "trx0types.h" #include "que0types.h" +extern ulint onlineddl_rowlog_rows; +extern ulint onlineddl_rowlog_pct_used; +extern ulint onlineddl_pct_progress; + /******************************************************//** Allocate the row log for an index and flag the index for online creation. diff --git a/storage/innobase/include/row0merge.h b/storage/innobase/include/row0merge.h index 390c0ce038b..31a9ac6f45e 100644 --- a/storage/innobase/include/row0merge.h +++ b/storage/innobase/include/row0merge.h @@ -40,6 +40,18 @@ Created 13/06/2005 Jan Lindstrom #include "lock0types.h" #include "srv0srv.h" +/* Cluster index read task is mandatory */ +#define COST_READ_CLUSTERED_INDEX 1.0 + +/* Basic fixed cost to build all type of index */ +#define COST_BUILD_INDEX_STATIC 0.5 +/* Dynamic cost to build all type of index, dynamic cost will be re-distributed based on page count ratio of each index */ +#define COST_BUILD_INDEX_DYNAMIC 0.5 + +/* Sum of below two must be 1.0 */ +#define PCT_COST_MERGESORT_INDEX 0.4 +#define PCT_COST_INSERT_INDEX 0.6 + // Forward declaration struct ib_sequence_t; @@ -370,7 +382,10 @@ row_merge_sort( merge_file_t* file, /*!< in/out: file containing index entries */ row_merge_block_t* block, /*!< in/out: 3 buffers */ - int* tmpfd) /*!< in/out: temporary file handle */ + int* tmpfd, /*!< in/out: temporary file handle */ + const bool update_progress, /*!< in: update progress status variable or not */ + const float pct_progress, /*!< in: total progress percent until now */ + const float pct_cost) /*!< in: current progress percent */ __attribute__((nonnull)); /*********************************************************************//** Allocate a sort buffer. diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index a4aa3eb4bf3..06d5f61f638 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -903,9 +903,19 @@ struct export_var_t{ ulint innodb_truncated_status_writes; /*!< srv_truncated_status_writes */ ulint innodb_available_undo_logs; /*!< srv_available_undo_logs */ - ulint innodb_defragment_compression_failures; - ulint innodb_defragment_failures; - ulint innodb_defragment_count; + ulint innodb_defragment_compression_failures; /*!< Number of + defragment re-compression + failures */ + + ulint innodb_defragment_failures; /*!< Number of defragment + failures*/ + ulint innodb_defragment_count; /*!< Number of defragment + operations*/ + + ulint innodb_onlineddl_rowlog_rows; /*!< Online alter rows */ + ulint innodb_onlineddl_rowlog_pct_used; /*!< Online alter percentage + of used row log buffer */ + ulint innodb_onlineddl_pct_progress; /*!< Online alter progress */ #ifdef UNIV_DEBUG ulint innodb_purge_trx_id_age; /*!< rw_max_trx_id - purged trx_id */ @@ -917,7 +927,7 @@ struct export_var_t{ by page compression */ ib_int64_t innodb_page_compression_trim_sect512;/*!< Number of 512b TRIM by page compression */ - ib_int64_t innodb_page_compression_trim_sect4096;/*!< Number of 4K byte TRIM + ib_int64_t innodb_page_compression_trim_sect4096;/*!< Number of 4K byte TRIM by page compression */ ib_int64_t innodb_index_pages_written; /*!< Number of index pages written */ diff --git a/storage/innobase/row/row0ftsort.cc b/storage/innobase/row/row0ftsort.cc index de10937a0be..c0c3452e241 100644 --- a/storage/innobase/row/row0ftsort.cc +++ b/storage/innobase/row/row0ftsort.cc @@ -847,7 +847,7 @@ exit: error = row_merge_sort(psort_info->psort_common->trx, psort_info->psort_common->dup, - merge_file[i], block[i], &tmpfd[i]); + merge_file[i], block[i], &tmpfd[i], false, 0.0/* pct_progress */, 0.0/* pct_cost */); if (error != DB_SUCCESS) { close(tmpfd[i]); goto func_exit; diff --git a/storage/innobase/row/row0log.cc b/storage/innobase/row/row0log.cc index 070c4ba7517..b01b481c501 100644 --- a/storage/innobase/row/row0log.cc +++ b/storage/innobase/row/row0log.cc @@ -40,6 +40,10 @@ Created 2011-05-26 Marko Makela #include +ulint onlineddl_rowlog_rows; +ulint onlineddl_rowlog_pct_used; +ulint onlineddl_pct_progress; + /** Table row modification operations during online table rebuild. Delete-marked records are not copied to the rebuilt table. */ enum row_tab_op { @@ -470,6 +474,10 @@ write_failed: log->tail.total += size; UNIV_MEM_INVALID(log->tail.buf, sizeof log->tail.buf); mutex_exit(&log->mutex); + + os_atomic_increment_ulint(&onlineddl_rowlog_rows, 1); + /* 10000 means 100.00%, 4525 means 45.25% */ + onlineddl_rowlog_pct_used = (log->tail.total * 10000) / srv_online_max_size; } #ifdef UNIV_DEBUG diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index d9e0dc709be..ae1da31c6dd 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -23,6 +23,7 @@ New index creation routines using a merge sort Created 12/4/2005 Jan Lindstrom Completed by Sunny Bains and Marko Makela *******************************************************/ +#include #include "row0merge.h" #include "row0ext.h" @@ -1189,7 +1190,8 @@ row_merge_read_clustered_index( AUTO_INCREMENT column, or ULINT_UNDEFINED if none is added */ ib_sequence_t& sequence,/*!< in/out: autoinc sequence */ - row_merge_block_t* block) /*!< in/out: file buffer */ + row_merge_block_t* block, /*!< in/out: file buffer */ + float pct_cost) /*!< in: percent of task weight out of total alter job */ { dict_index_t* clust_index; /* Clustered index */ mem_heap_t* row_heap; /* Heap memory to create @@ -1209,11 +1211,21 @@ row_merge_read_clustered_index( os_event_t fts_parallel_sort_event = NULL; ibool fts_pll_sort = FALSE; ib_int64_t sig_count = 0; + + float curr_progress; + ib_int64_t read_rows = 0; + ib_int64_t table_total_rows; DBUG_ENTER("row_merge_read_clustered_index"); ut_ad((old_table == new_table) == !col_map); ut_ad(!add_cols || col_map); + table_total_rows = dict_table_get_n_rows(old_table); + if(table_total_rows == 0) { + /* We don't know total row count */ + table_total_rows = 1; + } + trx->op_info = "reading clustered index"; #ifdef FTS_INTERNAL_DIAG_PRINT @@ -1711,6 +1723,17 @@ write_buffers: } mem_heap_empty(row_heap); + + /* Increment innodb_onlineddl_pct_progress status variable */ + read_rows++; + if(read_rows % 1000 == 0) { + /* Update progress for each 1000 rows */ + curr_progress = (read_rows >= table_total_rows) ? + pct_cost : + ((pct_cost * read_rows) / table_total_rows); + /* presenting 10.12% as 1012 integer */ + onlineddl_pct_progress = curr_progress * 100; + } } func_exit: @@ -2173,18 +2196,37 @@ row_merge_sort( merge_file_t* file, /*!< in/out: file containing index entries */ row_merge_block_t* block, /*!< in/out: 3 buffers */ - int* tmpfd) /*!< in/out: temporary file handle */ + int* tmpfd, /*!< in/out: temporary file handle + */ + const bool update_progress, + /*!< in: update progress + status variable or not */ + const float pct_progress, + /*!< in: total progress percent + until now */ + const float pct_cost) /*!< in: current progress percent */ { const ulint half = file->offset / 2; ulint num_runs; ulint cur_run = 0; ulint* run_offset; dberr_t error = DB_SUCCESS; + ulint merge_count = 0; + ulint total_merge_sort_count; + float curr_progress = 0; + DBUG_ENTER("row_merge_sort"); /* Record the number of merge runs we need to perform */ num_runs = file->offset; + /* Find the number N which 2^N is greater or equal than num_runs */ + /* N is merge sort running count */ + total_merge_sort_count = ceil(log2f(num_runs)); + if(total_merge_sort_count <= 0) { + total_merge_sort_count=1; + } + /* If num_runs are less than 1, nothing to merge */ if (num_runs <= 1) { DBUG_RETURN(error); @@ -2214,6 +2256,15 @@ row_merge_sort( error = row_merge(trx, dup, file, block, tmpfd, &num_runs, run_offset); + if(update_progress) { + merge_count++; + curr_progress = (merge_count >= total_merge_sort_count) ? + pct_cost : + ((pct_cost * merge_count) / total_merge_sort_count); + /* presenting 10.12% as 1012 integer */; + onlineddl_pct_progress = (pct_progress + curr_progress) * 100; + } + if (error != DB_SUCCESS) { break; } @@ -2283,7 +2334,10 @@ row_merge_insert_index_tuples( dict_index_t* index, /*!< in: index */ const dict_table_t* old_table,/*!< in: old table */ int fd, /*!< in: file descriptor */ - row_merge_block_t* block) /*!< in/out: file buffer */ + row_merge_block_t* block, /*!< in/out: file buffer */ + const ib_int64_t table_total_rows, /*!< in: total rows of old table */ + const float pct_progress, /*!< in: total progress percent until now */ + const float pct_cost) /*!< in: current progress percent */ { const byte* b; mem_heap_t* heap; @@ -2293,6 +2347,8 @@ row_merge_insert_index_tuples( ulint foffs = 0; ulint* offsets; mrec_buf_t* buf; + ib_int64_t inserted_rows = 0; + float curr_progress; DBUG_ENTER("row_merge_insert_index_tuples"); ut_ad(!srv_read_only_mode); @@ -2469,6 +2525,19 @@ row_merge_insert_index_tuples( mem_heap_empty(tuple_heap); mem_heap_empty(ins_heap); + + /* Increment innodb_onlineddl_pct_progress status variable */ + inserted_rows++; + if(inserted_rows % 1000 == 0) { + /* Update progress for each 1000 rows */ + curr_progress = (inserted_rows >= table_total_rows || + table_total_rows <= 0) ? + pct_cost : + ((pct_cost * inserted_rows) / table_total_rows); + + /* presenting 10.12% as 1012 integer */; + onlineddl_pct_progress = (pct_progress + curr_progress) * 100; + } } } @@ -3464,6 +3533,13 @@ row_merge_build_indexes( fts_psort_t* merge_info = NULL; ib_int64_t sig_count = 0; bool fts_psort_initiated = false; + + float total_static_cost = 0; + float total_dynamic_cost = 0; + uint total_index_blocks = 0; + float pct_cost=0; + float pct_progress=0; + DBUG_ENTER("row_merge_build_indexes"); ut_ad(!srv_read_only_mode); @@ -3494,6 +3570,9 @@ row_merge_build_indexes( merge_files[i].fd = -1; } + total_static_cost = COST_BUILD_INDEX_STATIC * n_indexes + COST_READ_CLUSTERED_INDEX; + total_dynamic_cost = COST_BUILD_INDEX_DYNAMIC * n_indexes; + for (i = 0; i < n_indexes; i++) { if (row_merge_file_create(&merge_files[i]) < 0) { error = DB_OUT_OF_MEMORY; @@ -3538,6 +3617,12 @@ row_merge_build_indexes( duplicate keys. */ innobase_rec_reset(table); + sql_print_information("InnoDB: Online DDL : Start"); + sql_print_information("InnoDB: Online DDL : Start reading clustered " + "index of the table and create temporary files"); + + pct_cost = COST_READ_CLUSTERED_INDEX * 100 / (total_static_cost + total_dynamic_cost); + /* Read clustered index of the table and create files for secondary index entries for merge sort */ @@ -3545,10 +3630,18 @@ row_merge_build_indexes( trx, table, old_table, new_table, online, indexes, fts_sort_idx, psort_info, merge_files, key_numbers, n_indexes, add_cols, col_map, - add_autoinc, sequence, block); + add_autoinc, sequence, block, pct_cost); + + pct_progress += pct_cost; + + sql_print_information("InnoDB: Online DDL : End of reading " + "clustered index of the table and create temporary files"); + + for (i = 0; i < n_indexes; i++) { + total_index_blocks += merge_files[i].offset; + } if (error != DB_SUCCESS) { - goto func_exit; } @@ -3630,14 +3723,47 @@ wait_again: row_merge_dup_t dup = { sort_idx, table, col_map, 0}; + pct_cost = (COST_BUILD_INDEX_STATIC + + (total_dynamic_cost * merge_files[i].offset / + total_index_blocks)) / + (total_static_cost + total_dynamic_cost) + * PCT_COST_MERGESORT_INDEX * 100; + + sql_print_information("InnoDB: Online DDL : Start merge-sorting" + " index %s (%lu / %lu), estimated cost : %2.4f", + indexes[i]->name, (i+1), n_indexes, pct_cost); + error = row_merge_sort( trx, &dup, &merge_files[i], - block, &tmpfd); + block, &tmpfd, true, pct_progress, pct_cost); + + pct_progress += pct_cost; + + sql_print_information("InnoDB: Online DDL : End of " + " merge-sorting index %s (%lu / %lu)", + indexes[i]->name, (i+1), n_indexes); if (error == DB_SUCCESS) { + pct_cost = (COST_BUILD_INDEX_STATIC + + (total_dynamic_cost * merge_files[i].offset / + total_index_blocks)) / + (total_static_cost + total_dynamic_cost) * + PCT_COST_INSERT_INDEX * 100; + + sql_print_information("InnoDB: Online DDL : Start " + "building index %s (%lu / %lu), estimated " + "cost : %2.4f", indexes[i]->name, (i+1), + n_indexes, pct_cost); + error = row_merge_insert_index_tuples( trx->id, sort_idx, old_table, - merge_files[i].fd, block); + merge_files[i].fd, block, + merge_files[i].n_rec, pct_progress, pct_cost); + pct_progress += pct_cost; + + sql_print_information("InnoDB: Online DDL : " + "End of building index %s (%lu / %lu)", + indexes[i]->name, (i+1), n_indexes); } } @@ -3654,11 +3780,15 @@ wait_again: ut_ad(sort_idx->online_status == ONLINE_INDEX_COMPLETE); } else { + sql_print_information("InnoDB: Online DDL : Start applying row log"); DEBUG_SYNC_C("row_log_apply_before"); error = row_log_apply(trx, sort_idx, table); DEBUG_SYNC_C("row_log_apply_after"); + sql_print_information("InnoDB: Online DDL : End of applying row log"); } + sql_print_information("InnoDB: Online DDL : Completed"); + if (error != DB_SUCCESS) { trx->error_key_num = key_numbers[i]; goto func_exit; diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index f76056dc71c..0c0075c98f1 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -63,6 +63,7 @@ Created 10/8/1995 Heikki Tuuri #include "dict0stats_bg.h" /* dict_stats_event */ #include "srv0start.h" #include "row0mysql.h" +#include "row0log.h" #include "ha_prototypes.h" #include "trx0i_s.h" #include "os0sync.h" /* for HAVE_ATOMIC_BUILTINS */ @@ -1523,6 +1524,10 @@ srv_export_innodb_status(void) export_vars.innodb_defragment_failures = btr_defragment_failures; export_vars.innodb_defragment_count = btr_defragment_count; + export_vars.innodb_onlineddl_rowlog_rows = onlineddl_rowlog_rows; + export_vars.innodb_onlineddl_rowlog_pct_used = onlineddl_rowlog_pct_used; + export_vars.innodb_onlineddl_pct_progress = onlineddl_pct_progress; + #ifdef UNIV_DEBUG rw_lock_s_lock(&purge_sys->latch); trx_id_t done_trx_no = purge_sys->done.trx_no; diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 2a551be0284..6773dc7c346 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -993,6 +993,14 @@ static SHOW_VAR innodb_status_variables[]= { {"defragment_count", (char*) &export_vars.innodb_defragment_count, SHOW_LONG}, + /* Online alter table status variables */ + {"onlineddl_rowlog_rows", + (char*) &export_vars.innodb_onlineddl_rowlog_rows, SHOW_LONG}, + {"onlineddl_rowlog_pct_used", + (char*) &export_vars.innodb_onlineddl_rowlog_pct_used, SHOW_LONG}, + {"onlineddl_pct_progress", + (char*) &export_vars.innodb_onlineddl_pct_progress, SHOW_LONG}, + {NullS, NullS, SHOW_LONG} }; diff --git a/storage/xtradb/handler/handler0alter.cc b/storage/xtradb/handler/handler0alter.cc index 2cd0500007a..8097fd01e3f 100644 --- a/storage/xtradb/handler/handler0alter.cc +++ b/storage/xtradb/handler/handler0alter.cc @@ -3406,6 +3406,11 @@ ha_innobase::prepare_inplace_alter_table( DBUG_RETURN(HA_ERR_WRONG_COMMAND); } + /* Init online ddl status variables */ + onlineddl_rowlog_rows = 0; + onlineddl_rowlog_pct_used = 0; + onlineddl_pct_progress = 0; + MONITOR_ATOMIC_INC(MONITOR_PENDING_ALTER_TABLE); #ifdef UNIV_DEBUG @@ -4056,6 +4061,11 @@ oom: ctx->thr, prebuilt->table, altered_table); } + /* Init online ddl status variables */ + onlineddl_rowlog_rows = 0; + onlineddl_rowlog_pct_used = 0; + onlineddl_pct_progress = 0; + DEBUG_SYNC_C("inplace_after_index_build"); DBUG_EXECUTE_IF("create_index_fail", diff --git a/storage/xtradb/include/row0log.h b/storage/xtradb/include/row0log.h index 62715fe8808..f105838eece 100644 --- a/storage/xtradb/include/row0log.h +++ b/storage/xtradb/include/row0log.h @@ -35,6 +35,10 @@ Created 2011-05-26 Marko Makela #include "trx0types.h" #include "que0types.h" +extern ulint onlineddl_rowlog_rows; +extern ulint onlineddl_rowlog_pct_used; +extern ulint onlineddl_pct_progress; + /******************************************************//** Allocate the row log for an index and flag the index for online creation. diff --git a/storage/xtradb/include/row0merge.h b/storage/xtradb/include/row0merge.h index 390c0ce038b..31a9ac6f45e 100644 --- a/storage/xtradb/include/row0merge.h +++ b/storage/xtradb/include/row0merge.h @@ -40,6 +40,18 @@ Created 13/06/2005 Jan Lindstrom #include "lock0types.h" #include "srv0srv.h" +/* Cluster index read task is mandatory */ +#define COST_READ_CLUSTERED_INDEX 1.0 + +/* Basic fixed cost to build all type of index */ +#define COST_BUILD_INDEX_STATIC 0.5 +/* Dynamic cost to build all type of index, dynamic cost will be re-distributed based on page count ratio of each index */ +#define COST_BUILD_INDEX_DYNAMIC 0.5 + +/* Sum of below two must be 1.0 */ +#define PCT_COST_MERGESORT_INDEX 0.4 +#define PCT_COST_INSERT_INDEX 0.6 + // Forward declaration struct ib_sequence_t; @@ -370,7 +382,10 @@ row_merge_sort( merge_file_t* file, /*!< in/out: file containing index entries */ row_merge_block_t* block, /*!< in/out: 3 buffers */ - int* tmpfd) /*!< in/out: temporary file handle */ + int* tmpfd, /*!< in/out: temporary file handle */ + const bool update_progress, /*!< in: update progress status variable or not */ + const float pct_progress, /*!< in: total progress percent until now */ + const float pct_cost) /*!< in: current progress percent */ __attribute__((nonnull)); /*********************************************************************//** Allocate a sort buffer. diff --git a/storage/xtradb/include/srv0srv.h b/storage/xtradb/include/srv0srv.h index 48cad8c36c0..aef04d003d5 100644 --- a/storage/xtradb/include/srv0srv.h +++ b/storage/xtradb/include/srv0srv.h @@ -1112,9 +1112,22 @@ struct export_var_t{ ib_int64_t innodb_x_lock_os_waits; ib_int64_t innodb_x_lock_spin_rounds; ib_int64_t innodb_x_lock_spin_waits; - ulint innodb_defragment_compression_failures; - ulint innodb_defragment_failures; - ulint innodb_defragment_count; + + ulint innodb_defragment_compression_failures; /*!< Number of + defragment re-compression + failures */ + + ulint innodb_defragment_failures; /*!< Number of defragment + failures*/ + ulint innodb_defragment_count; /*!< Number of defragment + operations*/ + + ulint innodb_onlineddl_rowlog_rows; /*!< Online alter rows */ + ulint innodb_onlineddl_rowlog_pct_used; /*!< Online alter percentage + of used row log buffer */ + ulint innodb_onlineddl_pct_progress; /*!< Online alter progress + */ + #ifdef UNIV_DEBUG ulint innodb_purge_trx_id_age; /*!< rw_max_trx_id - purged trx_id */ ulint innodb_purge_view_trx_id_age; /*!< rw_max_trx_id diff --git a/storage/xtradb/row/row0ftsort.cc b/storage/xtradb/row/row0ftsort.cc index 4eee03b9533..0ef59addf5c 100644 --- a/storage/xtradb/row/row0ftsort.cc +++ b/storage/xtradb/row/row0ftsort.cc @@ -850,7 +850,7 @@ exit: error = row_merge_sort(psort_info->psort_common->trx, psort_info->psort_common->dup, - merge_file[i], block[i], &tmpfd[i]); + merge_file[i], block[i], &tmpfd[i], false, 0.0/* pct_progress */, 0.0/* pct_cost */); if (error != DB_SUCCESS) { close(tmpfd[i]); goto func_exit; diff --git a/storage/xtradb/row/row0log.cc b/storage/xtradb/row/row0log.cc index 41d22cf07a8..cdbba0ef854 100644 --- a/storage/xtradb/row/row0log.cc +++ b/storage/xtradb/row/row0log.cc @@ -40,6 +40,10 @@ Created 2011-05-26 Marko Makela #include +ulint onlineddl_rowlog_rows; +ulint onlineddl_rowlog_pct_used; +ulint onlineddl_pct_progress; + /** Table row modification operations during online table rebuild. Delete-marked records are not copied to the rebuilt table. */ enum row_tab_op { @@ -471,6 +475,10 @@ write_failed: log->tail.total += size; UNIV_MEM_INVALID(log->tail.buf, sizeof log->tail.buf); mutex_exit(&log->mutex); + + os_atomic_increment_ulint(&onlineddl_rowlog_rows, 1); + /* 10000 means 100.00%, 4525 means 45.25% */ + onlineddl_rowlog_pct_used = (log->tail.total * 10000) / srv_online_max_size; } #ifdef UNIV_DEBUG diff --git a/storage/xtradb/row/row0merge.cc b/storage/xtradb/row/row0merge.cc index 4428de30473..d54aeb91c03 100644 --- a/storage/xtradb/row/row0merge.cc +++ b/storage/xtradb/row/row0merge.cc @@ -23,6 +23,7 @@ New index creation routines using a merge sort Created 12/4/2005 Jan Lindstrom Completed by Sunny Bains and Marko Makela *******************************************************/ +#include #include "row0merge.h" #include "row0ext.h" @@ -1189,7 +1190,8 @@ row_merge_read_clustered_index( AUTO_INCREMENT column, or ULINT_UNDEFINED if none is added */ ib_sequence_t& sequence,/*!< in/out: autoinc sequence */ - row_merge_block_t* block) /*!< in/out: file buffer */ + row_merge_block_t* block, /*!< in/out: file buffer */ + float pct_cost) /*!< in: percent of task weight out of total alter job */ { dict_index_t* clust_index; /* Clustered index */ mem_heap_t* row_heap; /* Heap memory to create @@ -1209,11 +1211,21 @@ row_merge_read_clustered_index( os_event_t fts_parallel_sort_event = NULL; ibool fts_pll_sort = FALSE; ib_int64_t sig_count = 0; + + float curr_progress; + ib_int64_t read_rows = 0; + ib_int64_t table_total_rows; DBUG_ENTER("row_merge_read_clustered_index"); ut_ad((old_table == new_table) == !col_map); ut_ad(!add_cols || col_map); + table_total_rows = dict_table_get_n_rows(old_table); + if(table_total_rows == 0) { + /* We don't know total row count */ + table_total_rows = 1; + } + trx->op_info = "reading clustered index"; #ifdef FTS_INTERNAL_DIAG_PRINT @@ -1717,6 +1729,17 @@ write_buffers: } mem_heap_empty(row_heap); + + /* Increment innodb_onlineddl_pct_progress status variable */ + read_rows++; + if(read_rows % 1000 == 0) { + /* Update progress for each 1000 rows */ + curr_progress = (read_rows >= table_total_rows) ? + pct_cost : + ((pct_cost * read_rows) / table_total_rows); + /* presenting 10.12% as 1012 integer */ + onlineddl_pct_progress = curr_progress * 100; + } } func_exit: @@ -2179,18 +2202,37 @@ row_merge_sort( merge_file_t* file, /*!< in/out: file containing index entries */ row_merge_block_t* block, /*!< in/out: 3 buffers */ - int* tmpfd) /*!< in/out: temporary file handle */ + int* tmpfd, /*!< in/out: temporary file handle + */ + const bool update_progress, + /*!< in: update progress + status variable or not */ + const float pct_progress, + /*!< in: total progress percent + until now */ + const float pct_cost) /*!< in: current progress percent */ { const ulint half = file->offset / 2; ulint num_runs; ulint cur_run = 0; ulint* run_offset; dberr_t error = DB_SUCCESS; + ulint merge_count = 0; + ulint total_merge_sort_count; + float curr_progress = 0; + DBUG_ENTER("row_merge_sort"); /* Record the number of merge runs we need to perform */ num_runs = file->offset; + /* Find the number N which 2^N is greater or equal than num_runs */ + /* N is merge sort running count */ + total_merge_sort_count = ceil(log2f(num_runs)); + if(total_merge_sort_count <= 0) { + total_merge_sort_count=1; + } + /* If num_runs are less than 1, nothing to merge */ if (num_runs <= 1) { DBUG_RETURN(error); @@ -2220,6 +2262,15 @@ row_merge_sort( error = row_merge(trx, dup, file, block, tmpfd, &num_runs, run_offset); + if(update_progress) { + merge_count++; + curr_progress = (merge_count >= total_merge_sort_count) ? + pct_cost : + ((pct_cost * merge_count) / total_merge_sort_count); + /* presenting 10.12% as 1012 integer */; + onlineddl_pct_progress = (pct_progress + curr_progress) * 100; + } + if (error != DB_SUCCESS) { break; } @@ -2289,7 +2340,10 @@ row_merge_insert_index_tuples( dict_index_t* index, /*!< in: index */ const dict_table_t* old_table,/*!< in: old table */ int fd, /*!< in: file descriptor */ - row_merge_block_t* block) /*!< in/out: file buffer */ + row_merge_block_t* block, /*!< in/out: file buffer */ + const ib_int64_t table_total_rows, /*!< in: total rows of old table */ + const float pct_progress, /*!< in: total progress percent until now */ + const float pct_cost) /*!< in: current progress percent */ { const byte* b; mem_heap_t* heap; @@ -2299,6 +2353,8 @@ row_merge_insert_index_tuples( ulint foffs = 0; ulint* offsets; mrec_buf_t* buf; + ib_int64_t inserted_rows = 0; + float curr_progress; DBUG_ENTER("row_merge_insert_index_tuples"); ut_ad(!srv_read_only_mode); @@ -2475,6 +2531,19 @@ row_merge_insert_index_tuples( mem_heap_empty(tuple_heap); mem_heap_empty(ins_heap); + + /* Increment innodb_onlineddl_pct_progress status variable */ + inserted_rows++; + if(inserted_rows % 1000 == 0) { + /* Update progress for each 1000 rows */ + curr_progress = (inserted_rows >= table_total_rows || + table_total_rows <= 0) ? + pct_cost : + ((pct_cost * inserted_rows) / table_total_rows); + + /* presenting 10.12% as 1012 integer */; + onlineddl_pct_progress = (pct_progress + curr_progress) * 100; + } } } @@ -3470,6 +3539,13 @@ row_merge_build_indexes( fts_psort_t* merge_info = NULL; ib_int64_t sig_count = 0; bool fts_psort_initiated = false; + + float total_static_cost = 0; + float total_dynamic_cost = 0; + uint total_index_blocks = 0; + float pct_cost=0; + float pct_progress=0; + DBUG_ENTER("row_merge_build_indexes"); ut_ad(!srv_read_only_mode); @@ -3500,6 +3576,9 @@ row_merge_build_indexes( merge_files[i].fd = -1; } + total_static_cost = COST_BUILD_INDEX_STATIC * n_indexes + COST_READ_CLUSTERED_INDEX; + total_dynamic_cost = COST_BUILD_INDEX_DYNAMIC * n_indexes; + for (i = 0; i < n_indexes; i++) { if (row_merge_file_create(&merge_files[i]) < 0) { error = DB_OUT_OF_MEMORY; @@ -3544,6 +3623,12 @@ row_merge_build_indexes( duplicate keys. */ innobase_rec_reset(table); + sql_print_information("InnoDB: Online DDL : Start"); + sql_print_information("InnoDB: Online DDL : Start reading clustered " + "index of the table and create temporary files"); + + pct_cost = COST_READ_CLUSTERED_INDEX * 100 / (total_static_cost + total_dynamic_cost); + /* Read clustered index of the table and create files for secondary index entries for merge sort */ @@ -3551,10 +3636,18 @@ row_merge_build_indexes( trx, table, old_table, new_table, online, indexes, fts_sort_idx, psort_info, merge_files, key_numbers, n_indexes, add_cols, col_map, - add_autoinc, sequence, block); + add_autoinc, sequence, block, pct_cost); + + pct_progress += pct_cost; + + sql_print_information("InnoDB: Online DDL : End of reading " + "clustered index of the table and create temporary files"); + + for (i = 0; i < n_indexes; i++) { + total_index_blocks += merge_files[i].offset; + } if (error != DB_SUCCESS) { - goto func_exit; } @@ -3636,14 +3729,47 @@ wait_again: row_merge_dup_t dup = { sort_idx, table, col_map, 0}; + pct_cost = (COST_BUILD_INDEX_STATIC + + (total_dynamic_cost * merge_files[i].offset / + total_index_blocks)) / + (total_static_cost + total_dynamic_cost) + * PCT_COST_MERGESORT_INDEX * 100; + + sql_print_information("InnoDB: Online DDL : Start merge-sorting" + " index %s (%lu / %lu), estimated cost : %2.4f", + indexes[i]->name, (i+1), n_indexes, pct_cost); + error = row_merge_sort( trx, &dup, &merge_files[i], - block, &tmpfd); + block, &tmpfd, true, pct_progress, pct_cost); + + pct_progress += pct_cost; + + sql_print_information("InnoDB: Online DDL : End of " + " merge-sorting index %s (%lu / %lu)", + indexes[i]->name, (i+1), n_indexes); if (error == DB_SUCCESS) { + pct_cost = (COST_BUILD_INDEX_STATIC + + (total_dynamic_cost * merge_files[i].offset / + total_index_blocks)) / + (total_static_cost + total_dynamic_cost) * + PCT_COST_INSERT_INDEX * 100; + + sql_print_information("InnoDB: Online DDL : Start " + "building index %s (%lu / %lu), estimated " + "cost : %2.4f", indexes[i]->name, (i+1), + n_indexes, pct_cost); + error = row_merge_insert_index_tuples( trx->id, sort_idx, old_table, - merge_files[i].fd, block); + merge_files[i].fd, block, + merge_files[i].n_rec, pct_progress, pct_cost); + pct_progress += pct_cost; + + sql_print_information("InnoDB: Online DDL : " + "End of building index %s (%lu / %lu)", + indexes[i]->name, (i+1), n_indexes); } } @@ -3660,11 +3786,15 @@ wait_again: ut_ad(sort_idx->online_status == ONLINE_INDEX_COMPLETE); } else { + sql_print_information("InnoDB: Online DDL : Start applying row log"); DEBUG_SYNC_C("row_log_apply_before"); error = row_log_apply(trx, sort_idx, table); DEBUG_SYNC_C("row_log_apply_after"); + sql_print_information("InnoDB: Online DDL : End of applying row log"); } + sql_print_information("InnoDB: Online DDL : Completed"); + if (error != DB_SUCCESS) { trx->error_key_num = key_numbers[i]; goto func_exit; diff --git a/storage/xtradb/srv/srv0srv.cc b/storage/xtradb/srv/srv0srv.cc index 896bb8a3b77..a12a8b197fb 100644 --- a/storage/xtradb/srv/srv0srv.cc +++ b/storage/xtradb/srv/srv0srv.cc @@ -64,6 +64,7 @@ Created 10/8/1995 Heikki Tuuri #include "dict0stats_bg.h" /* dict_stats_event */ #include "srv0start.h" #include "row0mysql.h" +#include "row0log.h" #include "ha_prototypes.h" #include "trx0i_s.h" #include "os0sync.h" /* for HAVE_ATOMIC_BUILTINS */ @@ -1912,6 +1913,10 @@ srv_export_innodb_status(void) export_vars.innodb_defragment_failures = btr_defragment_failures; export_vars.innodb_defragment_count = btr_defragment_count; + export_vars.innodb_onlineddl_rowlog_rows = onlineddl_rowlog_rows; + export_vars.innodb_onlineddl_rowlog_pct_used = onlineddl_rowlog_pct_used; + export_vars.innodb_onlineddl_pct_progress = onlineddl_pct_progress; + #ifdef UNIV_DEBUG rw_lock_s_lock(&purge_sys->latch); trx_id_t done_trx_no = purge_sys->done.trx_no; From 605b48d3e311e783ff60644dd468bbabb9a4a15c Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Tue, 30 Sep 2014 19:22:27 +0400 Subject: [PATCH 056/153] MDEV-6814: Server crashes in calculate_key_len on query with ORDER BY - if test_if_skip_sort_order() decides to switch to using an index, or switch from using ref to using quick select, it should set all members accordingly. --- mysql-test/r/order_by_optimizer_innodb.result | 8 ++++++++ mysql-test/t/order_by_optimizer_innodb.test | 8 ++++++++ sql/sql_select.cc | 1 + 3 files changed, 17 insertions(+) diff --git a/mysql-test/r/order_by_optimizer_innodb.result b/mysql-test/r/order_by_optimizer_innodb.result index 423e43ea5a2..f3167db4b9a 100644 --- a/mysql-test/r/order_by_optimizer_innodb.result +++ b/mysql-test/r/order_by_optimizer_innodb.result @@ -47,6 +47,14 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 range PRIMARY,ux_pk1_fd5 ux_pk1_fd5 13 NULL 137 Using where drop table t0,t1, t2; # +# MDEV-6814: Server crashes in calculate_key_len on query with ORDER BY +# +CREATE TABLE t1 (f1 INT, f2 INT, f3 INT, KEY(f2),KEY(f2,f1)) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1,5,0),(2,6,0); +SELECT * FROM t1 WHERE f1 < 3 AND f2 IS NULL ORDER BY f1; +f1 f2 f3 +DROP TABLE t1; +# # MDEV-6796: Unable to skip filesort when using implicit extended key # CREATE TABLE t1 ( diff --git a/mysql-test/t/order_by_optimizer_innodb.test b/mysql-test/t/order_by_optimizer_innodb.test index de0a0a9abcd..90430d11549 100644 --- a/mysql-test/t/order_by_optimizer_innodb.test +++ b/mysql-test/t/order_by_optimizer_innodb.test @@ -42,6 +42,14 @@ EXPLAIN SELECT * FROM t2 WHERE pk1=9 AND fd5 < 500 ORDER B drop table t0,t1, t2; +--echo # +--echo # MDEV-6814: Server crashes in calculate_key_len on query with ORDER BY +--echo # +CREATE TABLE t1 (f1 INT, f2 INT, f3 INT, KEY(f2),KEY(f2,f1)) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1,5,0),(2,6,0); +SELECT * FROM t1 WHERE f1 < 3 AND f2 IS NULL ORDER BY f1; +DROP TABLE t1; + --echo # --echo # MDEV-6796: Unable to skip filesort when using implicit extended key --echo # diff --git a/sql/sql_select.cc b/sql/sql_select.cc index cf29abcf101..1cf7b851671 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -20177,6 +20177,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, tab->ref.key= -1; tab->ref.key_parts= 0; tab->use_quick= 1; + best_key= new_ref_key; /* We don't restore select->cond as we want to use the original condition as index condition pushdown is not From fe0ff580009a5d5bdb853224568a7eaaf147f060 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 4 Sep 2014 21:37:10 +0200 Subject: [PATCH 057/153] compiler warnings --- include/wsrep.h | 2 +- mysys/thr_lock.c | 3 --- sql/event_data_objects.h | 2 +- sql/event_parse_data.h | 2 +- sql/sql_class.cc | 2 +- sql/sql_select.cc | 3 +-- sql/wsrep_thd.cc | 2 ++ storage/maria/ma_checkpoint.c | 2 +- 8 files changed, 8 insertions(+), 10 deletions(-) diff --git a/include/wsrep.h b/include/wsrep.h index c261d9c4b5f..9e0f052b340 100644 --- a/include/wsrep.h +++ b/include/wsrep.h @@ -23,7 +23,7 @@ #if !defined(EMBEDDED_LIBRARY) #define WSREP_FORMAT(my_format) \ ((wsrep_forced_binlog_format != BINLOG_FORMAT_UNSPEC) ? \ - wsrep_forced_binlog_format : my_format) + ((enum enum_binlog_format)wsrep_forced_binlog_format) : my_format) #else #define WSREP_FORMAT(my_format) my_format #endif /* && !EMBEDDED_LIBRARY */ diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index acc7d718546..cd30c30afea 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -862,7 +862,6 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) { wsrep_lock_inserted= TRUE; } - wsrep_read_wait: #endif wait_queue= &lock->read_wait; @@ -1011,8 +1010,6 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) { wsrep_lock_inserted= TRUE; } - wsrep_write_wait: - #endif wait_queue= &lock->write_wait; diff --git a/sql/event_data_objects.h b/sql/event_data_objects.h index 2483c564dff..8113fcb0e2e 100644 --- a/sql/event_data_objects.h +++ b/sql/event_data_objects.h @@ -85,7 +85,7 @@ class Event_queue_element : public Event_basic public: int on_completion; int status; - longlong originator; + uint32 originator; my_time_t last_executed; my_time_t execute_at; diff --git a/sql/event_parse_data.h b/sql/event_parse_data.h index faf42db623a..3ca7fcaab72 100644 --- a/sql/event_parse_data.h +++ b/sql/event_parse_data.h @@ -57,7 +57,7 @@ public: int on_completion; int status; bool status_changed; - longlong originator; + uint32 originator; /* do_not_create will be set if STARTS time is in the past and on_completion == ON_COMPLETION_DROP. diff --git a/sql/sql_class.cc b/sql/sql_class.cc index db2638254ec..919361b4b30 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -895,11 +895,11 @@ THD::THD(bool is_applier) wsrep_applier(is_applier), wsrep_applier_closing(false), wsrep_client_thread(false), + wsrep_apply_toi(false), wsrep_po_handle(WSREP_PO_INITIALIZER), wsrep_po_cnt(0), // wsrep_po_in_trans(false), wsrep_apply_format(0), - wsrep_apply_toi(false), #endif m_parser_state(NULL), #if defined(ENABLED_DEBUG_SYNC) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 8a7cb9cdafa..e46498c0dc9 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -22463,8 +22463,7 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab) } if (join_tab->select) { - Item *cond_copy; - UNINIT_VAR(cond_copy); // used when pre_idx_push_select_cond!=NULL + Item *UNINIT_VAR(cond_copy); if (join_tab->select->pre_idx_push_select_cond) cond_copy= cond->copy_andor_structure(thd); if (join_tab->select->cond) diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc index fabced2d11a..0779535d7fb 100644 --- a/sql/wsrep_thd.cc +++ b/sql/wsrep_thd.cc @@ -90,6 +90,7 @@ void wsrep_client_rollback(THD *thd) #define NUMBER_OF_FIELDS_TO_IDENTIFY_WORKER 2 //#include "rpl_info_factory.h" +#if 0 static Relay_log_info* wsrep_relay_log_init(const char* log_fname) { @@ -110,6 +111,7 @@ static Relay_log_info* wsrep_relay_log_init(const char* log_fname) return rli; } +#endif class Master_info; diff --git a/storage/maria/ma_checkpoint.c b/storage/maria/ma_checkpoint.c index e4adf5fbccd..4ed4e813cc9 100644 --- a/storage/maria/ma_checkpoint.c +++ b/storage/maria/ma_checkpoint.c @@ -230,7 +230,7 @@ static int really_execute_checkpoint(void) sizeof(checkpoint_start_log_horizon_char); for (i= 0; i < (sizeof(record_pieces)/sizeof(record_pieces[0])); i++) { - log_array[TRANSLOG_INTERNAL_PARTS + 1 + i].str= record_pieces[i].str; + log_array[TRANSLOG_INTERNAL_PARTS + 1 + i].str= (uchar*)record_pieces[i].str; log_array[TRANSLOG_INTERNAL_PARTS + 1 + i].length= record_pieces[i].length; total_rec_length+= (translog_size_t) record_pieces[i].length; } From 74a552d5dc74fb54bc9256887cd957a3754bb70c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 5 Sep 2014 16:08:58 +0200 Subject: [PATCH 058/153] cleanup: remove table->status from some engines from engines that we don't need to merge from a third-party repository on a regular basis --- sql/ha_partition.cc | 3 --- storage/archive/ha_archive.cc | 2 -- storage/connect/ha_connect.cc | 3 --- storage/federated/ha_federated.cc | 7 ------- storage/federatedx/ha_federatedx.cc | 8 -------- storage/heap/ha_heap.cc | 9 --------- storage/maria/ha_maria.cc | 11 ----------- storage/myisammrg/ha_myisammrg.cc | 10 ---------- storage/oqgraph/ha_oqgraph.cc | 5 ----- 9 files changed, 58 deletions(-) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 23af3825756..15cbb03978e 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -4953,7 +4953,6 @@ int ha_partition::rnd_next(uchar *buf) end: m_part_spec.start_part= NO_CURRENT_PART_ID; end_dont_reset_start_part: - table->status= STATUS_NOT_FOUND; DBUG_RETURN(result); } @@ -5857,7 +5856,6 @@ int ha_partition::partition_scan_set_up(uchar * buf, bool idx_read_flag) key not found. */ DBUG_PRINT("info", ("scan with no partition to scan")); - table->status= STATUS_NOT_FOUND; DBUG_RETURN(HA_ERR_END_OF_FILE); } if (m_part_spec.start_part == m_part_spec.end_part) @@ -5882,7 +5880,6 @@ int ha_partition::partition_scan_set_up(uchar * buf, bool idx_read_flag) if (start_part == MY_BIT_NONE) { DBUG_PRINT("info", ("scan with no partition to scan")); - table->status= STATUS_NOT_FOUND; DBUG_RETURN(HA_ERR_END_OF_FILE); } if (start_part > m_part_spec.start_part) diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc index 6c308e7eef1..6a866491d7c 100644 --- a/storage/archive/ha_archive.cc +++ b/storage/archive/ha_archive.cc @@ -1376,8 +1376,6 @@ int ha_archive::rnd_next(uchar *buf) current_position= aztell(&archive); rc= get_row(&archive, buf); - table->status=rc ? STATUS_NOT_FOUND: 0; - end: DBUG_RETURN(rc); } diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index ff15b27ca50..a6cd67b5f97 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -2527,7 +2527,6 @@ int ha_connect::ReadIndexed(uchar *buf, OPVAL op, const uchar *key, uint key_len if (xtrace > 1) htrc("ReadIndexed: op=%d rc=%d\n", op, rc); - table->status= (rc == RC_OK) ? 0 : STATUS_NOT_FOUND; return rc; } // end of ReadIndexed @@ -2638,7 +2637,6 @@ int ha_connect::index_first(uchar *buf) else if (indexing < 0) rc= HA_ERR_INTERNAL_ERROR; else if (CntRewindTable(xp->g, tdbp)) { - table->status= STATUS_NOT_FOUND; rc= HA_ERR_INTERNAL_ERROR; } else rc= rnd_next(buf); @@ -2833,7 +2831,6 @@ int ha_connect::rnd_next(uchar *buf) xp->fnd= xp->nfd= 0; } // endif nrd - table->status= (!rc) ? 0 : STATUS_NOT_FOUND; DBUG_RETURN(rc); } // end of rnd_next diff --git a/storage/federated/ha_federated.cc b/storage/federated/ha_federated.cc index 4608aedd129..11687c63374 100644 --- a/storage/federated/ha_federated.cc +++ b/storage/federated/ha_federated.cc @@ -2388,9 +2388,7 @@ int ha_federated::index_read_idx(uchar *buf, uint index, const uchar *key, RESULT 0 ok In this case *result will contain the result set - table->status == 0 # error In this case *result will contain 0 - table->status == STATUS_NOT_FOUND */ int ha_federated::index_read_idx_with_result_set(uchar *buf, uint index, @@ -2444,13 +2442,11 @@ int ha_federated::index_read_idx_with_result_set(uchar *buf, uint index, mysql_free_result(*result); results.elements--; *result= 0; - table->status= STATUS_NOT_FOUND; DBUG_RETURN(retval); } DBUG_RETURN(0); error: - table->status= STATUS_NOT_FOUND; my_error(retval, MYF(0), error_buffer); DBUG_RETURN(retval); } @@ -2523,7 +2519,6 @@ int ha_federated::read_range_first(const key_range *start_key, DBUG_RETURN(retval); error: - table->status= STATUS_NOT_FOUND; DBUG_RETURN(retval); } @@ -2684,8 +2679,6 @@ int ha_federated::read_next(uchar *buf, MYSQL_RES *result) MYSQL_ROW row; DBUG_ENTER("ha_federated::read_next"); - table->status= STATUS_NOT_FOUND; // For easier return - /* Save current data cursor position. */ current_position= result->data_cursor; diff --git a/storage/federatedx/ha_federatedx.cc b/storage/federatedx/ha_federatedx.cc index 8d41ca2d1b3..86d470bdfc9 100644 --- a/storage/federatedx/ha_federatedx.cc +++ b/storage/federatedx/ha_federatedx.cc @@ -2554,9 +2554,7 @@ int ha_federatedx::index_read_idx(uchar *buf, uint index, const uchar *key, RESULT 0 ok In this case *result will contain the result set - table->status == 0 # error In this case *result will contain 0 - table->status == STATUS_NOT_FOUND */ int ha_federatedx::index_read_idx_with_result_set(uchar *buf, uint index, @@ -2613,11 +2611,9 @@ int ha_federatedx::index_read_idx_with_result_set(uchar *buf, uint index, insert_dynamic(&results, (uchar*) result); *result= 0; - table->status= STATUS_NOT_FOUND; DBUG_RETURN(retval); error: - table->status= STATUS_NOT_FOUND; my_error(retval, MYF(0), error_buffer); DBUG_RETURN(retval); } @@ -2698,7 +2694,6 @@ int ha_federatedx::read_range_first(const key_range *start_key, DBUG_RETURN(retval); error: - table->status= STATUS_NOT_FOUND; DBUG_RETURN(retval); } @@ -2903,8 +2898,6 @@ int ha_federatedx::read_next(uchar *buf, FEDERATEDX_IO_RESULT *result) FEDERATEDX_IO_ROW *row; DBUG_ENTER("ha_federatedx::read_next"); - table->status= STATUS_NOT_FOUND; // For easier return - if ((retval= txn->acquire(share, TRUE, &io))) DBUG_RETURN(retval); @@ -2989,7 +2982,6 @@ int ha_federatedx::rnd_pos(uchar *buf, uchar *pos) DBUG_RETURN(retval); error: - table->status= STATUS_NOT_FOUND; DBUG_RETURN(retval); } diff --git a/storage/heap/ha_heap.cc b/storage/heap/ha_heap.cc index 5631d60a10a..28f306b3e5c 100644 --- a/storage/heap/ha_heap.cc +++ b/storage/heap/ha_heap.cc @@ -290,7 +290,6 @@ int ha_heap::index_read_map(uchar *buf, const uchar *key, { DBUG_ASSERT(inited==INDEX); int error = heap_rkey(file,buf,active_index, key, keypart_map, find_flag); - table->status = error ? STATUS_NOT_FOUND : 0; return error; } @@ -300,7 +299,6 @@ int ha_heap::index_read_last_map(uchar *buf, const uchar *key, DBUG_ASSERT(inited==INDEX); int error= heap_rkey(file, buf, active_index, key, keypart_map, HA_READ_PREFIX_LAST); - table->status= error ? STATUS_NOT_FOUND : 0; return error; } @@ -309,7 +307,6 @@ int ha_heap::index_read_idx_map(uchar *buf, uint index, const uchar *key, enum ha_rkey_function find_flag) { int error = heap_rkey(file, buf, index, key, keypart_map, find_flag); - table->status = error ? STATUS_NOT_FOUND : 0; return error; } @@ -317,7 +314,6 @@ int ha_heap::index_next(uchar * buf) { DBUG_ASSERT(inited==INDEX); int error=heap_rnext(file,buf); - table->status=error ? STATUS_NOT_FOUND: 0; return error; } @@ -325,7 +321,6 @@ int ha_heap::index_prev(uchar * buf) { DBUG_ASSERT(inited==INDEX); int error=heap_rprev(file,buf); - table->status=error ? STATUS_NOT_FOUND: 0; return error; } @@ -333,7 +328,6 @@ int ha_heap::index_first(uchar * buf) { DBUG_ASSERT(inited==INDEX); int error=heap_rfirst(file, buf, active_index); - table->status=error ? STATUS_NOT_FOUND: 0; return error; } @@ -341,7 +335,6 @@ int ha_heap::index_last(uchar * buf) { DBUG_ASSERT(inited==INDEX); int error=heap_rlast(file, buf, active_index); - table->status=error ? STATUS_NOT_FOUND: 0; return error; } @@ -353,7 +346,6 @@ int ha_heap::rnd_init(bool scan) int ha_heap::rnd_next(uchar *buf) { int error=heap_scan(file, buf); - table->status=error ? STATUS_NOT_FOUND: 0; return error; } @@ -363,7 +355,6 @@ int ha_heap::rnd_pos(uchar * buf, uchar *pos) HEAP_PTR heap_position; memcpy(&heap_position, pos, sizeof(HEAP_PTR)); error=heap_rrnd(file, buf, heap_position); - table->status=error ? STATUS_NOT_FOUND: 0; return error; } diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index de901ba3b7b..713a31b2ddf 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -2287,7 +2287,6 @@ int ha_maria::index_read_map(uchar * buf, const uchar * key, { DBUG_ASSERT(inited == INDEX); int error= maria_rkey(file, buf, active_index, key, keypart_map, find_flag); - table->status= error ? STATUS_NOT_FOUND : 0; return error; } @@ -2305,7 +2304,6 @@ int ha_maria::index_read_idx_map(uchar * buf, uint index, const uchar * key, error= maria_rkey(file, buf, index, key, keypart_map, find_flag); ma_set_index_cond_func(file, NULL, 0); - table->status= error ? STATUS_NOT_FOUND : 0; return error; } @@ -2317,7 +2315,6 @@ int ha_maria::index_read_last_map(uchar * buf, const uchar * key, DBUG_ASSERT(inited == INDEX); int error= maria_rkey(file, buf, active_index, key, keypart_map, HA_READ_PREFIX_LAST); - table->status= error ? STATUS_NOT_FOUND : 0; DBUG_RETURN(error); } @@ -2326,7 +2323,6 @@ int ha_maria::index_next(uchar * buf) { DBUG_ASSERT(inited == INDEX); int error= maria_rnext(file, buf, active_index); - table->status= error ? STATUS_NOT_FOUND : 0; return error; } @@ -2335,7 +2331,6 @@ int ha_maria::index_prev(uchar * buf) { DBUG_ASSERT(inited == INDEX); int error= maria_rprev(file, buf, active_index); - table->status= error ? STATUS_NOT_FOUND : 0; return error; } @@ -2344,7 +2339,6 @@ int ha_maria::index_first(uchar * buf) { DBUG_ASSERT(inited == INDEX); int error= maria_rfirst(file, buf, active_index); - table->status= error ? STATUS_NOT_FOUND : 0; return error; } @@ -2353,7 +2347,6 @@ int ha_maria::index_last(uchar * buf) { DBUG_ASSERT(inited == INDEX); int error= maria_rlast(file, buf, active_index); - table->status= error ? STATUS_NOT_FOUND : 0; return error; } @@ -2372,7 +2365,6 @@ int ha_maria::index_next_same(uchar * buf, { error= maria_rnext_same(file,buf); } while (error == HA_ERR_RECORD_DELETED); - table->status= error ? STATUS_NOT_FOUND : 0; return error; } @@ -2416,7 +2408,6 @@ int ha_maria::rnd_end() int ha_maria::rnd_next(uchar *buf) { int error= maria_scan(file, buf); - table->status= error ? STATUS_NOT_FOUND : 0; return error; } @@ -2439,7 +2430,6 @@ int ha_maria::restart_rnd_next(uchar *buf) int ha_maria::rnd_pos(uchar *buf, uchar *pos) { int error= maria_rrnd(file, buf, my_get_ptr(pos, ref_length)); - table->status= error ? STATUS_NOT_FOUND : 0; return error; } @@ -3189,7 +3179,6 @@ int ha_maria::ft_read(uchar * buf) error= ft_handler->please->read_next(ft_handler, (char*) buf); - table->status= error ? STATUS_NOT_FOUND : 0; return error; } diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc index 191ccd5ed89..3c151818457 100644 --- a/storage/myisammrg/ha_myisammrg.cc +++ b/storage/myisammrg/ha_myisammrg.cc @@ -1121,7 +1121,6 @@ int ha_myisammrg::index_read_map(uchar * buf, const uchar * key, { DBUG_ASSERT(this->file->children_attached); int error=myrg_rkey(file,buf,active_index, key, keypart_map, find_flag); - table->status=error ? STATUS_NOT_FOUND: 0; return error; } @@ -1131,7 +1130,6 @@ int ha_myisammrg::index_read_idx_map(uchar * buf, uint index, const uchar * key, { DBUG_ASSERT(this->file->children_attached); int error=myrg_rkey(file,buf,index, key, keypart_map, find_flag); - table->status=error ? STATUS_NOT_FOUND: 0; return error; } @@ -1141,7 +1139,6 @@ int ha_myisammrg::index_read_last_map(uchar *buf, const uchar *key, DBUG_ASSERT(this->file->children_attached); int error=myrg_rkey(file,buf,active_index, key, keypart_map, HA_READ_PREFIX_LAST); - table->status=error ? STATUS_NOT_FOUND: 0; return error; } @@ -1149,7 +1146,6 @@ int ha_myisammrg::index_next(uchar * buf) { DBUG_ASSERT(this->file->children_attached); int error=myrg_rnext(file,buf,active_index); - table->status=error ? STATUS_NOT_FOUND: 0; return error; } @@ -1157,7 +1153,6 @@ int ha_myisammrg::index_prev(uchar * buf) { DBUG_ASSERT(this->file->children_attached); int error=myrg_rprev(file,buf, active_index); - table->status=error ? STATUS_NOT_FOUND: 0; return error; } @@ -1165,7 +1160,6 @@ int ha_myisammrg::index_first(uchar * buf) { DBUG_ASSERT(this->file->children_attached); int error=myrg_rfirst(file, buf, active_index); - table->status=error ? STATUS_NOT_FOUND: 0; return error; } @@ -1173,7 +1167,6 @@ int ha_myisammrg::index_last(uchar * buf) { DBUG_ASSERT(this->file->children_attached); int error=myrg_rlast(file, buf, active_index); - table->status=error ? STATUS_NOT_FOUND: 0; return error; } @@ -1187,7 +1180,6 @@ int ha_myisammrg::index_next_same(uchar * buf, { error= myrg_rnext_same(file,buf); } while (error == HA_ERR_RECORD_DELETED); - table->status=error ? STATUS_NOT_FOUND: 0; return error; } @@ -1203,7 +1195,6 @@ int ha_myisammrg::rnd_next(uchar *buf) { DBUG_ASSERT(this->file->children_attached); int error=myrg_rrnd(file, buf, HA_OFFSET_ERROR); - table->status=error ? STATUS_NOT_FOUND: 0; return error; } @@ -1212,7 +1203,6 @@ int ha_myisammrg::rnd_pos(uchar * buf, uchar *pos) { DBUG_ASSERT(this->file->children_attached); int error=myrg_rrnd(file, buf, my_get_ptr(pos,ref_length)); - table->status=error ? STATUS_NOT_FOUND: 0; return error; } diff --git a/storage/oqgraph/ha_oqgraph.cc b/storage/oqgraph/ha_oqgraph.cc index 085fd3d73a0..6294b0dc35b 100644 --- a/storage/oqgraph/ha_oqgraph.cc +++ b/storage/oqgraph/ha_oqgraph.cc @@ -822,7 +822,6 @@ int ha_oqgraph::index_next_same(byte *buf, const byte *key, uint key_len) DBUG_ASSERT(inited==INDEX); if (!(res= graph->fetch_row(row))) res= fill_record(buf, row); - table->status= res ? STATUS_NOT_FOUND : 0; return error_code(res); } @@ -914,7 +913,6 @@ int ha_oqgraph::index_read_idx(byte * buf, uint index, const byte * key, if (!parse_latch_string_to_legacy_int(latchFieldValue, latch)) { // Invalid, so warn & fail push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WRONG_ARGUMENTS, ER(ER_WRONG_ARGUMENTS), "OQGRAPH latch"); - table->status = STATUS_NOT_FOUND; if (ptrdiff) /* fixes debug build assert - should be a tidier way to do this */ { field[0]->move_field_offset(-ptrdiff); @@ -970,7 +968,6 @@ int ha_oqgraph::index_read_idx(byte * buf, uint index, const byte * key, if (!res && !(res= graph->fetch_row(row))) { res= fill_record(buf, row); } - table->status = res ? STATUS_NOT_FOUND : 0; return error_code(res); } @@ -1075,7 +1072,6 @@ int ha_oqgraph::rnd_next(byte *buf) if (!(res= graph->fetch_row(row))) res= fill_record(buf, row); - table->status= res ? STATUS_NOT_FOUND: 0; return error_code(res); } @@ -1085,7 +1081,6 @@ int ha_oqgraph::rnd_pos(byte * buf, byte *pos) open_query::row row; if (!(res= graph->fetch_row(row, pos))) res= fill_record(buf, row); - table->status=res ? STATUS_NOT_FOUND: 0; return error_code(res); } From 88cebbdf6dd02113e8ccadd0424b1713d8b6aeb2 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 11 Sep 2014 10:08:48 +0200 Subject: [PATCH 059/153] cleanup: remove libedit, move readline to extra/ --- cmake/readline.cmake | 4 +- cmd-line-utils/libedit/CMakeLists.txt | 191 -- cmd-line-utils/libedit/README | 50 - cmd-line-utils/libedit/chared.c | 739 ------ cmd-line-utils/libedit/chared.h | 171 -- cmd-line-utils/libedit/chartype.c | 361 --- cmd-line-utils/libedit/chartype.h | 252 -- cmd-line-utils/libedit/common.c | 921 ------- cmd-line-utils/libedit/config.h | 5 - cmd-line-utils/libedit/el.c | 636 ----- cmd-line-utils/libedit/el.h | 166 -- cmd-line-utils/libedit/el_terminal.h | 125 - cmd-line-utils/libedit/eln.c | 364 --- cmd-line-utils/libedit/emacs.c | 507 ---- cmd-line-utils/libedit/filecomplete.c | 612 ----- cmd-line-utils/libedit/filecomplete.h | 44 - cmd-line-utils/libedit/hist.c | 222 -- cmd-line-utils/libedit/hist.h | 87 - cmd-line-utils/libedit/histedit.h | 315 --- cmd-line-utils/libedit/history.c | 1102 -------- cmd-line-utils/libedit/historyn.c | 5 - cmd-line-utils/libedit/keymacro.c | 677 ----- cmd-line-utils/libedit/keymacro.h | 76 - cmd-line-utils/libedit/makelist.sh | 264 -- cmd-line-utils/libedit/map.c | 1420 ---------- cmd-line-utils/libedit/map.h | 77 - cmd-line-utils/libedit/np/fgetln.c | 108 - cmd-line-utils/libedit/np/strlcat.c | 85 - cmd-line-utils/libedit/np/strlcpy.c | 81 - cmd-line-utils/libedit/np/unvis.c | 560 ---- cmd-line-utils/libedit/np/vis.c | 582 ----- cmd-line-utils/libedit/np/vis.h | 114 - cmd-line-utils/libedit/np/wcsdup.c | 43 - cmd-line-utils/libedit/parse.c | 284 -- cmd-line-utils/libedit/parse.h | 48 - cmd-line-utils/libedit/prompt.c | 198 -- cmd-line-utils/libedit/prompt.h | 60 - cmd-line-utils/libedit/read.c | 722 ------ cmd-line-utils/libedit/read.h | 50 - cmd-line-utils/libedit/readline.c | 2294 ----------------- cmd-line-utils/libedit/readline/readline.h | 221 -- cmd-line-utils/libedit/refresh.c | 1182 --------- cmd-line-utils/libedit/refresh.h | 59 - cmd-line-utils/libedit/search.c | 640 ----- cmd-line-utils/libedit/search.h | 66 - cmd-line-utils/libedit/sig.c | 199 -- cmd-line-utils/libedit/sig.h | 72 - cmd-line-utils/libedit/sys.h | 187 -- cmd-line-utils/libedit/terminal.c | 1677 ------------ cmd-line-utils/libedit/tokenizer.c | 449 ---- cmd-line-utils/libedit/tokenizern.c | 5 - cmd-line-utils/libedit/tty.c | 1353 ---------- cmd-line-utils/libedit/tty.h | 481 ---- cmd-line-utils/libedit/vi.c | 1173 --------- .../readline/CMakeLists.txt | 2 +- {cmd-line-utils => extra}/readline/COPYING | 0 {cmd-line-utils => extra}/readline/INSTALL | 0 {cmd-line-utils => extra}/readline/README | 0 .../readline/ansi_stdlib.h | 0 {cmd-line-utils => extra}/readline/bind.c | 0 {cmd-line-utils => extra}/readline/callback.c | 0 {cmd-line-utils => extra}/readline/chardefs.h | 0 {cmd-line-utils => extra}/readline/compat.c | 0 {cmd-line-utils => extra}/readline/complete.c | 0 .../readline/config_readline.h | 0 .../readline/configure.in | 0 {cmd-line-utils => extra}/readline/display.c | 0 .../readline/emacs_keymap.c | 0 {cmd-line-utils => extra}/readline/funmap.c | 0 .../readline/histexpand.c | 0 {cmd-line-utils => extra}/readline/histfile.c | 0 {cmd-line-utils => extra}/readline/histlib.h | 0 {cmd-line-utils => extra}/readline/history.c | 0 {cmd-line-utils => extra}/readline/history.h | 0 .../readline/histsearch.c | 0 {cmd-line-utils => extra}/readline/input.c | 0 {cmd-line-utils => extra}/readline/isearch.c | 0 {cmd-line-utils => extra}/readline/keymaps.c | 0 {cmd-line-utils => extra}/readline/keymaps.h | 0 {cmd-line-utils => extra}/readline/kill.c | 0 {cmd-line-utils => extra}/readline/macro.c | 0 {cmd-line-utils => extra}/readline/mbutil.c | 0 {cmd-line-utils => extra}/readline/misc.c | 0 {cmd-line-utils => extra}/readline/nls.c | 0 {cmd-line-utils => extra}/readline/parens.c | 0 {cmd-line-utils => extra}/readline/posixdir.h | 0 {cmd-line-utils => extra}/readline/posixjmp.h | 0 .../readline/posixstat.h | 0 {cmd-line-utils => extra}/readline/readline.c | 0 {cmd-line-utils => extra}/readline/readline.h | 0 {cmd-line-utils => extra}/readline/rlconf.h | 0 {cmd-line-utils => extra}/readline/rldefs.h | 0 {cmd-line-utils => extra}/readline/rlmbutil.h | 0 .../readline/rlprivate.h | 0 {cmd-line-utils => extra}/readline/rlshell.h | 0 {cmd-line-utils => extra}/readline/rlstdc.h | 0 {cmd-line-utils => extra}/readline/rltty.c | 0 {cmd-line-utils => extra}/readline/rltty.h | 0 .../readline/rltypedefs.h | 0 .../readline/rlwinsize.h | 0 .../readline/savestring.c | 0 {cmd-line-utils => extra}/readline/search.c | 0 {cmd-line-utils => extra}/readline/shell.c | 0 {cmd-line-utils => extra}/readline/signals.c | 0 {cmd-line-utils => extra}/readline/tcap.h | 0 {cmd-line-utils => extra}/readline/terminal.c | 0 {cmd-line-utils => extra}/readline/text.c | 0 {cmd-line-utils => extra}/readline/tilde.c | 0 {cmd-line-utils => extra}/readline/tilde.h | 0 {cmd-line-utils => extra}/readline/undo.c | 0 {cmd-line-utils => extra}/readline/util.c | 0 .../readline/vi_keymap.c | 0 {cmd-line-utils => extra}/readline/vi_mode.c | 0 {cmd-line-utils => extra}/readline/xmalloc.c | 0 {cmd-line-utils => extra}/readline/xmalloc.h | 0 115 files changed, 3 insertions(+), 22385 deletions(-) delete mode 100644 cmd-line-utils/libedit/CMakeLists.txt delete mode 100644 cmd-line-utils/libedit/README delete mode 100644 cmd-line-utils/libedit/chared.c delete mode 100644 cmd-line-utils/libedit/chared.h delete mode 100644 cmd-line-utils/libedit/chartype.c delete mode 100644 cmd-line-utils/libedit/chartype.h delete mode 100644 cmd-line-utils/libedit/common.c delete mode 100644 cmd-line-utils/libedit/config.h delete mode 100644 cmd-line-utils/libedit/el.c delete mode 100644 cmd-line-utils/libedit/el.h delete mode 100644 cmd-line-utils/libedit/el_terminal.h delete mode 100644 cmd-line-utils/libedit/eln.c delete mode 100644 cmd-line-utils/libedit/emacs.c delete mode 100644 cmd-line-utils/libedit/filecomplete.c delete mode 100644 cmd-line-utils/libedit/filecomplete.h delete mode 100644 cmd-line-utils/libedit/hist.c delete mode 100644 cmd-line-utils/libedit/hist.h delete mode 100644 cmd-line-utils/libedit/histedit.h delete mode 100644 cmd-line-utils/libedit/history.c delete mode 100644 cmd-line-utils/libedit/historyn.c delete mode 100644 cmd-line-utils/libedit/keymacro.c delete mode 100644 cmd-line-utils/libedit/keymacro.h delete mode 100644 cmd-line-utils/libedit/makelist.sh delete mode 100644 cmd-line-utils/libedit/map.c delete mode 100644 cmd-line-utils/libedit/map.h delete mode 100644 cmd-line-utils/libedit/np/fgetln.c delete mode 100644 cmd-line-utils/libedit/np/strlcat.c delete mode 100644 cmd-line-utils/libedit/np/strlcpy.c delete mode 100644 cmd-line-utils/libedit/np/unvis.c delete mode 100644 cmd-line-utils/libedit/np/vis.c delete mode 100644 cmd-line-utils/libedit/np/vis.h delete mode 100644 cmd-line-utils/libedit/np/wcsdup.c delete mode 100644 cmd-line-utils/libedit/parse.c delete mode 100644 cmd-line-utils/libedit/parse.h delete mode 100644 cmd-line-utils/libedit/prompt.c delete mode 100644 cmd-line-utils/libedit/prompt.h delete mode 100644 cmd-line-utils/libedit/read.c delete mode 100644 cmd-line-utils/libedit/read.h delete mode 100644 cmd-line-utils/libedit/readline.c delete mode 100644 cmd-line-utils/libedit/readline/readline.h delete mode 100644 cmd-line-utils/libedit/refresh.c delete mode 100644 cmd-line-utils/libedit/refresh.h delete mode 100644 cmd-line-utils/libedit/search.c delete mode 100644 cmd-line-utils/libedit/search.h delete mode 100644 cmd-line-utils/libedit/sig.c delete mode 100644 cmd-line-utils/libedit/sig.h delete mode 100644 cmd-line-utils/libedit/sys.h delete mode 100644 cmd-line-utils/libedit/terminal.c delete mode 100644 cmd-line-utils/libedit/tokenizer.c delete mode 100644 cmd-line-utils/libedit/tokenizern.c delete mode 100644 cmd-line-utils/libedit/tty.c delete mode 100644 cmd-line-utils/libedit/tty.h delete mode 100644 cmd-line-utils/libedit/vi.c rename {cmd-line-utils => extra}/readline/CMakeLists.txt (96%) rename {cmd-line-utils => extra}/readline/COPYING (100%) rename {cmd-line-utils => extra}/readline/INSTALL (100%) rename {cmd-line-utils => extra}/readline/README (100%) rename {cmd-line-utils => extra}/readline/ansi_stdlib.h (100%) rename {cmd-line-utils => extra}/readline/bind.c (100%) rename {cmd-line-utils => extra}/readline/callback.c (100%) rename {cmd-line-utils => extra}/readline/chardefs.h (100%) rename {cmd-line-utils => extra}/readline/compat.c (100%) rename {cmd-line-utils => extra}/readline/complete.c (100%) rename {cmd-line-utils => extra}/readline/config_readline.h (100%) rename {cmd-line-utils => extra}/readline/configure.in (100%) rename {cmd-line-utils => extra}/readline/display.c (100%) rename {cmd-line-utils => extra}/readline/emacs_keymap.c (100%) rename {cmd-line-utils => extra}/readline/funmap.c (100%) rename {cmd-line-utils => extra}/readline/histexpand.c (100%) rename {cmd-line-utils => extra}/readline/histfile.c (100%) rename {cmd-line-utils => extra}/readline/histlib.h (100%) rename {cmd-line-utils => extra}/readline/history.c (100%) rename {cmd-line-utils => extra}/readline/history.h (100%) rename {cmd-line-utils => extra}/readline/histsearch.c (100%) rename {cmd-line-utils => extra}/readline/input.c (100%) rename {cmd-line-utils => extra}/readline/isearch.c (100%) rename {cmd-line-utils => extra}/readline/keymaps.c (100%) rename {cmd-line-utils => extra}/readline/keymaps.h (100%) rename {cmd-line-utils => extra}/readline/kill.c (100%) rename {cmd-line-utils => extra}/readline/macro.c (100%) rename {cmd-line-utils => extra}/readline/mbutil.c (100%) rename {cmd-line-utils => extra}/readline/misc.c (100%) rename {cmd-line-utils => extra}/readline/nls.c (100%) rename {cmd-line-utils => extra}/readline/parens.c (100%) rename {cmd-line-utils => extra}/readline/posixdir.h (100%) rename {cmd-line-utils => extra}/readline/posixjmp.h (100%) rename {cmd-line-utils => extra}/readline/posixstat.h (100%) rename {cmd-line-utils => extra}/readline/readline.c (100%) rename {cmd-line-utils => extra}/readline/readline.h (100%) rename {cmd-line-utils => extra}/readline/rlconf.h (100%) rename {cmd-line-utils => extra}/readline/rldefs.h (100%) rename {cmd-line-utils => extra}/readline/rlmbutil.h (100%) rename {cmd-line-utils => extra}/readline/rlprivate.h (100%) rename {cmd-line-utils => extra}/readline/rlshell.h (100%) rename {cmd-line-utils => extra}/readline/rlstdc.h (100%) rename {cmd-line-utils => extra}/readline/rltty.c (100%) rename {cmd-line-utils => extra}/readline/rltty.h (100%) rename {cmd-line-utils => extra}/readline/rltypedefs.h (100%) rename {cmd-line-utils => extra}/readline/rlwinsize.h (100%) rename {cmd-line-utils => extra}/readline/savestring.c (100%) rename {cmd-line-utils => extra}/readline/search.c (100%) rename {cmd-line-utils => extra}/readline/shell.c (100%) rename {cmd-line-utils => extra}/readline/signals.c (100%) rename {cmd-line-utils => extra}/readline/tcap.h (100%) rename {cmd-line-utils => extra}/readline/terminal.c (100%) rename {cmd-line-utils => extra}/readline/text.c (100%) rename {cmd-line-utils => extra}/readline/tilde.c (100%) rename {cmd-line-utils => extra}/readline/tilde.h (100%) rename {cmd-line-utils => extra}/readline/undo.c (100%) rename {cmd-line-utils => extra}/readline/util.c (100%) rename {cmd-line-utils => extra}/readline/vi_keymap.c (100%) rename {cmd-line-utils => extra}/readline/vi_mode.c (100%) rename {cmd-line-utils => extra}/readline/xmalloc.c (100%) rename {cmd-line-utils => extra}/readline/xmalloc.h (100%) diff --git a/cmake/readline.cmake b/cmake/readline.cmake index c99557683a6..ad6a7382e2a 100644 --- a/cmake/readline.cmake +++ b/cmake/readline.cmake @@ -116,9 +116,9 @@ ENDMACRO() MACRO (MYSQL_USE_BUNDLED_READLINE) SET(USE_NEW_READLINE_INTERFACE 1) SET(HAVE_HIST_ENTRY 0 CACHE INTERNAL "" FORCE) - SET(READLINE_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/cmd-line-utils) + SET(READLINE_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/extra) SET(READLINE_LIBRARY readline) - ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/cmd-line-utils/readline) + ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/extra/readline) ENDMACRO() MACRO (MYSQL_FIND_SYSTEM_READLINE) diff --git a/cmd-line-utils/libedit/CMakeLists.txt b/cmd-line-utils/libedit/CMakeLists.txt deleted file mode 100644 index 1f9aa29fb4a..00000000000 --- a/cmd-line-utils/libedit/CMakeLists.txt +++ /dev/null @@ -1,191 +0,0 @@ -# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ) -INCLUDE(CheckIncludeFile) -include(CheckFunctionExists) -CHECK_INCLUDE_FILES(term.h HAVE_TERM_H) - -SET(CMAKE_REQUIRED_LIBRARIES ${CURSES_LIBRARY}) -CHECK_CXX_SOURCE_COMPILES(" -#include -int main() -{ - tgoto(0,0,0); - return 0; -}" HAVE_DECL_TGOTO) -IF(NOT HAVE_DECL_TGOTO) - # On Solaris 11, term.h is broken, curses.h is also required. - CHECK_CXX_SOURCE_COMPILES(" - #include - #include - int main() - { - tgoto(0,0,0); - return 0; - }" HAVE_DECL_TGOTO2) - IF(HAVE_DECL_TGOTO2) - SET(HAVE_DECL_TGOTO 1 CACHE INTERNAL "" FORCE) - ENDIF() -ENDIF() - -SET(CMAKE_REQUIRED_LIBRARIES) - - - -IF(CMAKE_SYSTEM_NAME STREQUAL "SunOS") - #On Solaris, default awk is next to unusable while the xpg4 one is ok. - IF(EXISTS /usr/xpg4/bin/awk) - SET(AWK_EXECUTABLE /usr/xpg4/bin/awk) - ENDIF() -ELSEIF(CMAKE_SYSTEM_NAME STREQUAL "OS400") - #Workaround for cases, where /usr/bin/gawk is not executable - IF(EXISTS /QOpenSys/usr/bin/awk) - SET(AWK_EXECUTABLE /QOpenSys/usr/bin/awk) - ENDIF() -ENDIF() - -IF(NOT AWK_EXECUTABLE) - FIND_PROGRAM(AWK_EXECUTABLE NAMES gawk awk DOC "path to the awk executable") -ENDIF() - -MARK_AS_ADVANCED(AWK_EXECUTABLE) -SET(AWK ${AWK_EXECUTABLE}) -CONFIGURE_FILE(makelist.sh ${CMAKE_CURRENT_BINARY_DIR}/makelist @ONLY) - -include(CheckIncludeFile) - -CHECK_INCLUDE_FILE(vis.h HAVE_VIS_H) -IF(HAVE_VIS_H) - CHECK_FUNCTION_EXISTS(strvis HAVE_STRVIS) - IF(NOT HAVE_STRVIS) - SET(HAVE_VIS_H FALSE CACHE INTERNAL "" FORCE) - ENDIF() -ENDIF() - -CHECK_FUNCTION_EXISTS(strvis HAVE_STRVIS) -IF(NOT HAVE_STRVIS) - SET(LIBEDIT_EXTRA_SOURCES ${LIBEDIT_EXTRA_SOURCES} np/vis.c) -ENDIF() - -CHECK_FUNCTION_EXISTS(strunvis HAVE_STRUNVIS) -IF(NOT HAVE_STRUNVIS) - SET(LIBEDIT_EXTRA_SOURCES ${LIBEDIT_EXTRA_SOURCES} np/unvis.c) -ENDIF() - -CHECK_FUNCTION_EXISTS(strlcpy HAVE_STRLCPY) -IF(NOT HAVE_STRLCPY) - SET(LIBEDIT_EXTRA_SOURCES ${LIBEDIT_EXTRA_SOURCES} np/strlcpy.c) -ENDIF() - -CHECK_FUNCTION_EXISTS(strlcat HAVE_STRLCAT) -IF(NOT HAVE_STRLCAT) - SET(LIBEDIT_EXTRA_SOURCES ${LIBEDIT_EXTRA_SOURCES} np/strlcat.c) -ENDIF() - -CHECK_FUNCTION_EXISTS(fgetln HAVE_FGETLN) -IF(NOT HAVE_FGETLN) - SET(LIBEDIT_EXTRA_SOURCES ${LIBEDIT_EXTRA_SOURCES} np/fgetln.c) -ENDIF() - -CHECK_FUNCTION_EXISTS(fgetln HAVE_WCSDUP) -IF(NOT HAVE_WCSDUP) - SET(LIBEDIT_EXTRA_SOURCES ${LIBEDIT_EXTRA_SOURCES} np/wcsdup.c) -ENDIF() - -# Generate headers -FOREACH(SRCBASENAME vi emacs common) - SET(SRC ${CMAKE_CURRENT_SOURCE_DIR}/${SRCBASENAME}.c) - SET(HDR ${CMAKE_CURRENT_BINARY_DIR}/${SRCBASENAME}.h) - - ADD_CUSTOM_COMMAND( - OUTPUT ${HDR} - COMMAND sh ./makelist -h ${SRC} > ${HDR} - DEPENDS ${SRC}) - - SET(AHDR ${AHDR} ${HDR}) - SET(ASRC ${ASRC} ${SRC}) -ENDFOREACH() - -# Generate source files -ADD_CUSTOM_COMMAND( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/help.c - COMMAND sh ./makelist -bc ${ASRC} > help.c - DEPENDS ${ASRC} -) - -ADD_CUSTOM_COMMAND( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/help.h - COMMAND sh ./makelist -bh ${ASRC} > help.h - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS ${ASRC} -) - -ADD_CUSTOM_COMMAND( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/fcns.h - COMMAND sh ./makelist -fh ${AHDR} > fcns.h - VERBATIM - DEPENDS ${AHDR} -) - -ADD_CUSTOM_COMMAND( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/fcns.c - COMMAND sh ./makelist -fc ${AHDR} > fcns.c - VERBATIM - DEPENDS ${AHDR} -) - - -INCLUDE_DIRECTORIES( -${CMAKE_SOURCE_DIR}/include -${CMAKE_CURRENT_BINARY_DIR} -${CURSES_INCLUDE_PATH} -) - -SET(LIBEDIT_SOURCES - chared.c - chartype.c - el.c - eln.c - history.c - historyn.c - map.c - prompt.c - readline.c - search.c - tokenizer.c - tokenizern.c - vi.c - common.c - emacs.c - hist.c - keymacro.c - parse.c - read.c - refresh.c - sig.c - terminal.c - tty.c - filecomplete.c - ${CMAKE_CURRENT_BINARY_DIR}/help.c - ${CMAKE_CURRENT_BINARY_DIR}/help.h - ${CMAKE_CURRENT_BINARY_DIR}/fcns.c - ${CMAKE_CURRENT_BINARY_DIR}/fcns.h - ${AHDR} - ${LIBEDIT_EXTRA_SOURCES} -) -ADD_LIBRARY(edit STATIC ${LIBEDIT_SOURCES}) -TARGET_LINK_LIBRARIES(edit ${CURSES_LIBRARY}) - diff --git a/cmd-line-utils/libedit/README b/cmd-line-utils/libedit/README deleted file mode 100644 index c4bc1554b03..00000000000 --- a/cmd-line-utils/libedit/README +++ /dev/null @@ -1,50 +0,0 @@ -An approximate method to merge from upstream is: - - # Fetch latest from upstream (we also include some compat stuff) - $ CVS_RSH=ssh; export CVS_RSH - $ CVSROOT="anoncvs@anoncvs.netbsd.org:/cvsroot" - $ cvs co -d libedit -P src/lib/libedit - $ mkdir libedit/np - $ for f in src/common/lib/libc/string/strlcat.c \ - > src/common/lib/libc/string/strlcpy.c \ - > src/include/vis.h \ - > src/lib/libc/gen/unvis.c \ - > src/lib/libc/gen/vis.c \ - > src/tools/compat/fgetln.c - > do - > cvs co -P ${f} - > mv ${f} libedit/np - > done - $ rm -rf src - $ cd libedit - - # Remove files we don't need/use - $ rm -rf CVS TEST Makefile shlib_version *.[0-9] - $ (cd readline; rm -rf CVS Makefile) - - # Rename files to match our naming - $ mv makelist makelist.sh - $ mv terminal.h el_terminal.h - - # Remove NetBSD-specific bits - $ for file in $(find . -type f) - > do - > cp ${file} ${file}.orig - > sed -e 's/#include "terminal.h"/#include "el_terminal.h"/g' \ - > -e 's/sig_handler/el_sig_handler/g' \ - > -e 's/isprint/el_isprint/g' \ - > -e '/^__RCSID/d' \ - > ${file}.orig >${file} - > rm ${file}.orig - > done - -then merge remaining bits by hand. All MySQL-specific changes should be -marked with XXXMYSQL to make them easier to identify and merge. To generate -a 'clean' diff against upstream you can use the above commands but use - - cvs co -D "2011/10/23 17:37:55" [..] - -to fetch the baseline of most recent merge. - -Please feed any fixes to Jonathan Perkin who will -endeavour to merge them upstream and keep diffs minimal. diff --git a/cmd-line-utils/libedit/chared.c b/cmd-line-utils/libedit/chared.c deleted file mode 100644 index 647a5afe439..00000000000 --- a/cmd-line-utils/libedit/chared.c +++ /dev/null @@ -1,739 +0,0 @@ -/* $NetBSD: chared.c,v 1.36 2011/10/23 17:37:55 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)chared.c 8.1 (Berkeley) 6/4/93"; -#else -#endif -#endif /* not lint && not SCCSID */ - -/* - * chared.c: Character editor utilities - */ -#include -#include "el.h" - -private void ch__clearmacro (EditLine *); - -/* value to leave unused in line buffer */ -#define EL_LEAVE 2 - -/* cv_undo(): - * Handle state for the vi undo command - */ -protected void -cv_undo(EditLine *el) -{ - c_undo_t *vu = &el->el_chared.c_undo; - c_redo_t *r = &el->el_chared.c_redo; - size_t size; - - /* Save entire line for undo */ - size = (size_t)(el->el_line.lastchar - el->el_line.buffer); - vu->len = (ssize_t)size; - vu->cursor = (int)(el->el_line.cursor - el->el_line.buffer); - (void)memcpy(vu->buf, el->el_line.buffer, size * sizeof(*vu->buf)); - - /* save command info for redo */ - r->count = el->el_state.doingarg ? el->el_state.argument : 0; - r->action = el->el_chared.c_vcmd.action; - r->pos = r->buf; - r->cmd = el->el_state.thiscmd; - r->ch = el->el_state.thisch; -} - -/* cv_yank(): - * Save yank/delete data for paste - */ -protected void -cv_yank(EditLine *el, const Char *ptr, int size) -{ - c_kill_t *k = &el->el_chared.c_kill; - - (void)memcpy(k->buf, ptr, (size_t)size * sizeof(*k->buf)); - k->last = k->buf + size; -} - - -/* c_insert(): - * Insert num characters - */ -protected void -c_insert(EditLine *el, int num) -{ - Char *cp; - - if (el->el_line.lastchar + num >= el->el_line.limit) { - if (!ch_enlargebufs(el, (size_t)num)) - return; /* can't go past end of buffer */ - } - - if (el->el_line.cursor < el->el_line.lastchar) { - /* if I must move chars */ - for (cp = el->el_line.lastchar; cp >= el->el_line.cursor; cp--) - cp[num] = *cp; - } - el->el_line.lastchar += num; -} - - -/* c_delafter(): - * Delete num characters after the cursor - */ -protected void -c_delafter(EditLine *el, int num) -{ - - if (el->el_line.cursor + num > el->el_line.lastchar) - num = (int)(el->el_line.lastchar - el->el_line.cursor); - - if (el->el_map.current != el->el_map.emacs) { - cv_undo(el); - cv_yank(el, el->el_line.cursor, num); - } - - if (num > 0) { - Char *cp; - - for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++) - *cp = cp[num]; - - el->el_line.lastchar -= num; - } -} - - -/* c_delafter1(): - * Delete the character after the cursor, do not yank - */ -protected void -c_delafter1(EditLine *el) -{ - Char *cp; - - for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++) - *cp = cp[1]; - - el->el_line.lastchar--; -} - - -/* c_delbefore(): - * Delete num characters before the cursor - */ -protected void -c_delbefore(EditLine *el, int num) -{ - - if (el->el_line.cursor - num < el->el_line.buffer) - num = (int)(el->el_line.cursor - el->el_line.buffer); - - if (el->el_map.current != el->el_map.emacs) { - cv_undo(el); - cv_yank(el, el->el_line.cursor - num, num); - } - - if (num > 0) { - Char *cp; - - for (cp = el->el_line.cursor - num; - cp <= el->el_line.lastchar; - cp++) - *cp = cp[num]; - - el->el_line.lastchar -= num; - } -} - - -/* c_delbefore1(): - * Delete the character before the cursor, do not yank - */ -protected void -c_delbefore1(EditLine *el) -{ - Char *cp; - - for (cp = el->el_line.cursor - 1; cp <= el->el_line.lastchar; cp++) - *cp = cp[1]; - - el->el_line.lastchar--; -} - - -/* ce__isword(): - * Return if p is part of a word according to emacs - */ -protected int -ce__isword(Int p) -{ - return Isalnum(p) || Strchr(STR("*?_-.[]~="), p) != NULL; -} - - -/* cv__isword(): - * Return if p is part of a word according to vi - */ -protected int -cv__isword(Int p) -{ - if (Isalnum(p) || p == '_') - return 1; - if (Isgraph(p)) - return 2; - return 0; -} - - -/* cv__isWord(): - * Return if p is part of a big word according to vi - */ -protected int -cv__isWord(Int p) -{ - return !Isspace(p); -} - - -/* c__prev_word(): - * Find the previous word - */ -protected Char * -c__prev_word(Char *p, Char *low, int n, int (*wtest)(Int)) -{ - p--; - - while (n--) { - while ((p >= low) && !(*wtest)(*p)) - p--; - while ((p >= low) && (*wtest)(*p)) - p--; - } - - /* cp now points to one character before the word */ - p++; - if (p < low) - p = low; - /* cp now points where we want it */ - return p; -} - - -/* c__next_word(): - * Find the next word - */ -protected Char * -c__next_word(Char *p, Char *high, int n, int (*wtest)(Int)) -{ - while (n--) { - while ((p < high) && !(*wtest)(*p)) - p++; - while ((p < high) && (*wtest)(*p)) - p++; - } - if (p > high) - p = high; - /* p now points where we want it */ - return p; -} - -/* cv_next_word(): - * Find the next word vi style - */ -protected Char * -cv_next_word(EditLine *el, Char *p, Char *high, int n, int (*wtest)(Int)) -{ - int test; - - while (n--) { - test = (*wtest)(*p); - while ((p < high) && (*wtest)(*p) == test) - p++; - /* - * vi historically deletes with cw only the word preserving the - * trailing whitespace! This is not what 'w' does.. - */ - if (n || el->el_chared.c_vcmd.action != (DELETE|INSERT)) - while ((p < high) && Isspace(*p)) - p++; - } - - /* p now points where we want it */ - if (p > high) - return high; - else - return p; -} - - -/* cv_prev_word(): - * Find the previous word vi style - */ -protected Char * -cv_prev_word(Char *p, Char *low, int n, int (*wtest)(Int)) -{ - int test; - - p--; - while (n--) { - while ((p > low) && Isspace(*p)) - p--; - test = (*wtest)(*p); - while ((p >= low) && (*wtest)(*p) == test) - p--; - } - p++; - - /* p now points where we want it */ - if (p < low) - return low; - else - return p; -} - - -/* cv_delfini(): - * Finish vi delete action - */ -protected void -cv_delfini(EditLine *el) -{ - int size; - int action = el->el_chared.c_vcmd.action; - - if (action & INSERT) - el->el_map.current = el->el_map.key; - - if (el->el_chared.c_vcmd.pos == 0) - /* sanity */ - return; - - size = (int)(el->el_line.cursor - el->el_chared.c_vcmd.pos); - if (size == 0) - size = 1; - el->el_line.cursor = el->el_chared.c_vcmd.pos; - if (action & YANK) { - if (size > 0) - cv_yank(el, el->el_line.cursor, size); - else - cv_yank(el, el->el_line.cursor + size, -size); - } else { - if (size > 0) { - c_delafter(el, size); - re_refresh_cursor(el); - } else { - c_delbefore(el, -size); - el->el_line.cursor += size; - } - } - el->el_chared.c_vcmd.action = NOP; -} - - -/* cv__endword(): - * Go to the end of this word according to vi - */ -protected Char * -cv__endword(Char *p, Char *high, int n, int (*wtest)(Int)) -{ - int test; - - p++; - - while (n--) { - while ((p < high) && Isspace(*p)) - p++; - - test = (*wtest)(*p); - while ((p < high) && (*wtest)(*p) == test) - p++; - } - p--; - return p; -} - -/* ch_init(): - * Initialize the character editor - */ -protected int -ch_init(EditLine *el) -{ - c_macro_t *ma = &el->el_chared.c_macro; - - el->el_line.buffer = el_malloc(EL_BUFSIZ * - sizeof(*el->el_line.buffer)); - if (el->el_line.buffer == NULL) - return -1; - - (void) memset(el->el_line.buffer, 0, EL_BUFSIZ * - sizeof(*el->el_line.buffer)); - el->el_line.cursor = el->el_line.buffer; - el->el_line.lastchar = el->el_line.buffer; - el->el_line.limit = &el->el_line.buffer[EL_BUFSIZ - EL_LEAVE]; - - el->el_chared.c_undo.buf = el_malloc(EL_BUFSIZ * - sizeof(*el->el_chared.c_undo.buf)); - if (el->el_chared.c_undo.buf == NULL) - return -1; - (void) memset(el->el_chared.c_undo.buf, 0, EL_BUFSIZ * - sizeof(*el->el_chared.c_undo.buf)); - el->el_chared.c_undo.len = -1; - el->el_chared.c_undo.cursor = 0; - el->el_chared.c_redo.buf = el_malloc(EL_BUFSIZ * - sizeof(*el->el_chared.c_redo.buf)); - if (el->el_chared.c_redo.buf == NULL) - return -1; - el->el_chared.c_redo.pos = el->el_chared.c_redo.buf; - el->el_chared.c_redo.lim = el->el_chared.c_redo.buf + EL_BUFSIZ; - el->el_chared.c_redo.cmd = ED_UNASSIGNED; - - el->el_chared.c_vcmd.action = NOP; - el->el_chared.c_vcmd.pos = el->el_line.buffer; - - el->el_chared.c_kill.buf = el_malloc(EL_BUFSIZ * - sizeof(*el->el_chared.c_kill.buf)); - if (el->el_chared.c_kill.buf == NULL) - return -1; - (void) memset(el->el_chared.c_kill.buf, 0, EL_BUFSIZ * - sizeof(*el->el_chared.c_kill.buf)); - el->el_chared.c_kill.mark = el->el_line.buffer; - el->el_chared.c_kill.last = el->el_chared.c_kill.buf; - el->el_chared.c_resizefun = NULL; - el->el_chared.c_resizearg = NULL; - - el->el_map.current = el->el_map.key; - - el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */ - el->el_state.doingarg = 0; - el->el_state.metanext = 0; - el->el_state.argument = 1; - el->el_state.lastcmd = ED_UNASSIGNED; - - ma->level = -1; - ma->offset = 0; - ma->macro = el_malloc(EL_MAXMACRO * sizeof(*ma->macro)); - if (ma->macro == NULL) - return -1; - return 0; -} - -/* ch_reset(): - * Reset the character editor - */ -protected void -ch_reset(EditLine *el, int mclear) -{ - el->el_line.cursor = el->el_line.buffer; - el->el_line.lastchar = el->el_line.buffer; - - el->el_chared.c_undo.len = -1; - el->el_chared.c_undo.cursor = 0; - - el->el_chared.c_vcmd.action = NOP; - el->el_chared.c_vcmd.pos = el->el_line.buffer; - - el->el_chared.c_kill.mark = el->el_line.buffer; - - el->el_map.current = el->el_map.key; - - el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */ - el->el_state.doingarg = 0; - el->el_state.metanext = 0; - el->el_state.argument = 1; - el->el_state.lastcmd = ED_UNASSIGNED; - - el->el_history.eventno = 0; - - if (mclear) - ch__clearmacro(el); -} - -private void -ch__clearmacro(EditLine *el) -{ - c_macro_t *ma = &el->el_chared.c_macro; - while (ma->level >= 0) - el_free(ma->macro[ma->level--]); -} - -/* ch_enlargebufs(): - * Enlarge line buffer to be able to hold twice as much characters. - * Returns 1 if successful, 0 if not. - */ -protected int -ch_enlargebufs(EditLine *el, size_t addlen) -{ - size_t sz, newsz; - Char *newbuffer, *oldbuf, *oldkbuf; - - sz = (size_t)(el->el_line.limit - el->el_line.buffer + EL_LEAVE); - newsz = sz * 2; - /* - * If newly required length is longer than current buffer, we need - * to make the buffer big enough to hold both old and new stuff. - */ - if (addlen > sz) { - while(newsz - sz < addlen) - newsz *= 2; - } - - /* - * Reallocate line buffer. - */ - newbuffer = el_realloc(el->el_line.buffer, newsz * sizeof(*newbuffer)); - if (!newbuffer) - return 0; - - /* zero the newly added memory, leave old data in */ - (void) memset(&newbuffer[sz], 0, (newsz - sz) * sizeof(*newbuffer)); - - oldbuf = el->el_line.buffer; - - el->el_line.buffer = newbuffer; - el->el_line.cursor = newbuffer + (el->el_line.cursor - oldbuf); - el->el_line.lastchar = newbuffer + (el->el_line.lastchar - oldbuf); - /* don't set new size until all buffers are enlarged */ - el->el_line.limit = &newbuffer[sz - EL_LEAVE]; - - /* - * Reallocate kill buffer. - */ - newbuffer = el_realloc(el->el_chared.c_kill.buf, newsz * - sizeof(*newbuffer)); - if (!newbuffer) - return 0; - - /* zero the newly added memory, leave old data in */ - (void) memset(&newbuffer[sz], 0, (newsz - sz) * sizeof(*newbuffer)); - - oldkbuf = el->el_chared.c_kill.buf; - - el->el_chared.c_kill.buf = newbuffer; - el->el_chared.c_kill.last = newbuffer + - (el->el_chared.c_kill.last - oldkbuf); - el->el_chared.c_kill.mark = el->el_line.buffer + - (el->el_chared.c_kill.mark - oldbuf); - - /* - * Reallocate undo buffer. - */ - newbuffer = el_realloc(el->el_chared.c_undo.buf, - newsz * sizeof(*newbuffer)); - if (!newbuffer) - return 0; - - /* zero the newly added memory, leave old data in */ - (void) memset(&newbuffer[sz], 0, (newsz - sz) * sizeof(*newbuffer)); - el->el_chared.c_undo.buf = newbuffer; - - newbuffer = el_realloc(el->el_chared.c_redo.buf, - newsz * sizeof(*newbuffer)); - if (!newbuffer) - return 0; - el->el_chared.c_redo.pos = newbuffer + - (el->el_chared.c_redo.pos - el->el_chared.c_redo.buf); - el->el_chared.c_redo.lim = newbuffer + - (el->el_chared.c_redo.lim - el->el_chared.c_redo.buf); - el->el_chared.c_redo.buf = newbuffer; - - if (!hist_enlargebuf(el, sz, newsz)) - return 0; - - /* Safe to set enlarged buffer size */ - el->el_line.limit = &el->el_line.buffer[newsz - EL_LEAVE]; - if (el->el_chared.c_resizefun) - (*el->el_chared.c_resizefun)(el, el->el_chared.c_resizearg); - return 1; -} - -/* ch_end(): - * Free the data structures used by the editor - */ -protected void -ch_end(EditLine *el) -{ - el_free(el->el_line.buffer); - el->el_line.buffer = NULL; - el->el_line.limit = NULL; - el_free(el->el_chared.c_undo.buf); - el->el_chared.c_undo.buf = NULL; - el_free(el->el_chared.c_redo.buf); - el->el_chared.c_redo.buf = NULL; - el->el_chared.c_redo.pos = NULL; - el->el_chared.c_redo.lim = NULL; - el->el_chared.c_redo.cmd = ED_UNASSIGNED; - el_free(el->el_chared.c_kill.buf); - el->el_chared.c_kill.buf = NULL; - ch_reset(el, 1); - el_free(el->el_chared.c_macro.macro); - el->el_chared.c_macro.macro = NULL; -} - - -/* el_insertstr(): - * Insert string at cursorI - */ -public int -FUN(el,insertstr)(EditLine *el, const Char *s) -{ - size_t len; - - if ((len = Strlen(s)) == 0) - return -1; - if (el->el_line.lastchar + len >= el->el_line.limit) { - if (!ch_enlargebufs(el, len)) - return -1; - } - - c_insert(el, (int)len); - while (*s) - *el->el_line.cursor++ = *s++; - return 0; -} - - -/* el_deletestr(): - * Delete num characters before the cursor - */ -public void -el_deletestr(EditLine *el, int n) -{ - if (n <= 0) - return; - - if (el->el_line.cursor < &el->el_line.buffer[n]) - return; - - c_delbefore(el, n); /* delete before dot */ - el->el_line.cursor -= n; - if (el->el_line.cursor < el->el_line.buffer) - el->el_line.cursor = el->el_line.buffer; -} - -/* c_gets(): - * Get a string - */ -protected int -c_gets(EditLine *el, Char *buf, const Char *prompt) -{ - Char ch; - ssize_t len; - Char *cp = el->el_line.buffer; - - if (prompt) { - len = (ssize_t)Strlen(prompt); - (void)memcpy(cp, prompt, (size_t)len * sizeof(*cp)); - cp += len; - } - len = 0; - - for (;;) { - el->el_line.cursor = cp; - *cp = ' '; - el->el_line.lastchar = cp + 1; - re_refresh(el); - - if (FUN(el,getc)(el, &ch) != 1) { - ed_end_of_file(el, 0); - len = -1; - break; - } - - switch (ch) { - - case 0010: /* Delete and backspace */ - case 0177: - if (len == 0) { - len = -1; - break; - } - cp--; - continue; - - case 0033: /* ESC */ - case '\r': /* Newline */ - case '\n': - buf[len] = ch; - break; - - default: - if (len >= (ssize_t)(EL_BUFSIZ - 16)) - terminal_beep(el); - else { - buf[len++] = ch; - *cp++ = ch; - } - continue; - } - break; - } - - el->el_line.buffer[0] = '\0'; - el->el_line.lastchar = el->el_line.buffer; - el->el_line.cursor = el->el_line.buffer; - return (int)len; -} - - -/* c_hpos(): - * Return the current horizontal position of the cursor - */ -protected int -c_hpos(EditLine *el) -{ - Char *ptr; - - /* - * Find how many characters till the beginning of this line. - */ - if (el->el_line.cursor == el->el_line.buffer) - return 0; - else { - for (ptr = el->el_line.cursor - 1; - ptr >= el->el_line.buffer && *ptr != '\n'; - ptr--) - continue; - return (int)(el->el_line.cursor - ptr - 1); - } -} - -protected int -ch_resizefun(EditLine *el, el_zfunc_t f, void *a) -{ - el->el_chared.c_resizefun = f; - el->el_chared.c_resizearg = a; - return 0; -} diff --git a/cmd-line-utils/libedit/chared.h b/cmd-line-utils/libedit/chared.h deleted file mode 100644 index 176475ac8f0..00000000000 --- a/cmd-line-utils/libedit/chared.h +++ /dev/null @@ -1,171 +0,0 @@ -/* $NetBSD: chared.h,v 1.21 2010/08/28 15:44:59 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)chared.h 8.1 (Berkeley) 6/4/93 - */ - -/* - * el.chared.h: Character editor interface - */ -#ifndef _h_el_chared -#define _h_el_chared - -#include -#include - -#include "histedit.h" - -#define EL_MAXMACRO 10 - -/* - * This is an issue of basic "vi" look-and-feel. Defining VI_MOVE works - * like real vi: i.e. the transition from command<->insert modes moves - * the cursor. - * - * On the other hand we really don't want to move the cursor, because - * all the editing commands don't include the character under the cursor. - * Probably the best fix is to make all the editing commands aware of - * this fact. - */ -#define VI_MOVE - - -typedef struct c_macro_t { - int level; - int offset; - Char **macro; -} c_macro_t; - -/* - * Undo information for vi - no undo in emacs (yet) - */ -typedef struct c_undo_t { - ssize_t len; /* length of saved line */ - int cursor; /* position of saved cursor */ - Char *buf; /* full saved text */ -} c_undo_t; - -/* redo for vi */ -typedef struct c_redo_t { - Char *buf; /* redo insert key sequence */ - Char *pos; - Char *lim; - el_action_t cmd; /* command to redo */ - Char ch; /* char that invoked it */ - int count; - int action; /* from cv_action() */ -} c_redo_t; - -/* - * Current action information for vi - */ -typedef struct c_vcmd_t { - int action; - Char *pos; -} c_vcmd_t; - -/* - * Kill buffer for emacs - */ -typedef struct c_kill_t { - Char *buf; - Char *last; - Char *mark; -} c_kill_t; - -typedef void (*el_zfunc_t)(EditLine *, void *); - -/* - * Note that we use both data structures because the user can bind - * commands from both editors! - */ -typedef struct el_chared_t { - c_undo_t c_undo; - c_kill_t c_kill; - c_redo_t c_redo; - c_vcmd_t c_vcmd; - c_macro_t c_macro; - el_zfunc_t c_resizefun; - void * c_resizearg; -} el_chared_t; - - -#define STRQQ "\"\"" - -#define isglob(a) (strchr("*[]?", (a)) != NULL) - -#define NOP 0x00 -#define DELETE 0x01 -#define INSERT 0x02 -#define YANK 0x04 - -#define CHAR_FWD (+1) -#define CHAR_BACK (-1) - -#define MODE_INSERT 0 -#define MODE_REPLACE 1 -#define MODE_REPLACE_1 2 - -#include "common.h" -#include "vi.h" -#include "emacs.h" -#include "search.h" -#include "fcns.h" - - -protected int cv__isword(Int); -protected int cv__isWord(Int); -protected void cv_delfini(EditLine *); -protected Char *cv__endword(Char *, Char *, int, int (*)(Int)); -protected int ce__isword(Int); -protected void cv_undo(EditLine *); -protected void cv_yank(EditLine *, const Char *, int); -protected Char *cv_next_word(EditLine*, Char *, Char *, int, int (*)(Int)); -protected Char *cv_prev_word(Char *, Char *, int, int (*)(Int)); -protected Char *c__next_word(Char *, Char *, int, int (*)(Int)); -protected Char *c__prev_word(Char *, Char *, int, int (*)(Int)); -protected void c_insert(EditLine *, int); -protected void c_delbefore(EditLine *, int); -protected void c_delbefore1(EditLine *); -protected void c_delafter(EditLine *, int); -protected void c_delafter1(EditLine *); -protected int c_gets(EditLine *, Char *, const Char *); -protected int c_hpos(EditLine *); - -protected int ch_init(EditLine *); -protected void ch_reset(EditLine *, int); -protected int ch_resizefun(EditLine *, el_zfunc_t, void *); -protected int ch_enlargebufs(EditLine *, size_t); -protected void ch_end(EditLine *); - -#endif /* _h_el_chared */ diff --git a/cmd-line-utils/libedit/chartype.c b/cmd-line-utils/libedit/chartype.c deleted file mode 100644 index b70aebeec46..00000000000 --- a/cmd-line-utils/libedit/chartype.c +++ /dev/null @@ -1,361 +0,0 @@ -/* $NetBSD: chartype.c,v 1.10 2011/08/16 16:25:15 christos Exp $ */ - -/*- - * Copyright (c) 2009 The NetBSD Foundation, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * chartype.c: character classification and meta information - */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#endif /* not lint && not SCCSID */ -#include "el.h" -#include - -#define CT_BUFSIZ ((size_t)1024) - -#ifdef WIDECHAR -protected void -ct_conv_buff_resize(ct_buffer_t *conv, size_t mincsize, size_t minwsize) -{ - void *p; - if (mincsize > conv->csize) { - conv->csize = mincsize; - p = el_realloc(conv->cbuff, conv->csize * sizeof(*conv->cbuff)); - if (p == NULL) { - conv->csize = 0; - el_free(conv->cbuff); - conv->cbuff = NULL; - } else - conv->cbuff = p; - } - - if (minwsize > conv->wsize) { - conv->wsize = minwsize; - p = el_realloc(conv->wbuff, conv->wsize * sizeof(*conv->wbuff)); - if (p == NULL) { - conv->wsize = 0; - el_free(conv->wbuff); - conv->wbuff = NULL; - } else - conv->wbuff = p; - } -} - - -public char * -ct_encode_string(const Char *s, ct_buffer_t *conv) -{ - char *dst; - ssize_t used = 0; - mbstate_t state; - - memset(&state, 0, sizeof(mbstate_t)); - - if (!s) - return NULL; - if (!conv->cbuff) - ct_conv_buff_resize(conv, CT_BUFSIZ, (size_t)0); - if (!conv->cbuff) - return NULL; - - dst = conv->cbuff; - while (*s) { - used = (ssize_t)(conv->csize - (size_t)(dst - conv->cbuff)); - if (used < 5) { - used = dst - conv->cbuff; - ct_conv_buff_resize(conv, conv->csize + CT_BUFSIZ, - (size_t)0); - if (!conv->cbuff) - return NULL; - dst = conv->cbuff + used; - } - used = ct_encode_char(dst, (size_t)5, *s, &state); - if (used == -1) /* failed to encode, need more buffer space */ - abort(); - ++s; - dst += used; - } - *dst = '\0'; - return conv->cbuff; -} - -public Char * -ct_decode_string(const char *s, ct_buffer_t *conv) -{ - size_t len = 0; - - if (!s) - return NULL; - if (!conv->wbuff) - ct_conv_buff_resize(conv, (size_t)0, CT_BUFSIZ); - if (!conv->wbuff) - return NULL; - - len = ct_mbstowcs(NULL, s, (size_t)0); - if (len == (size_t)-1) - return NULL; - if (len > conv->wsize) - ct_conv_buff_resize(conv, (size_t)0, len + 1); - if (!conv->wbuff) - return NULL; - ct_mbstowcs(conv->wbuff, s, conv->wsize); - return conv->wbuff; -} - - -protected Char ** -ct_decode_argv(int argc, const char *argv[], ct_buffer_t *conv) -{ - size_t bufspace; - int i; - Char *p; - Char **wargv; - ssize_t bytes; - mbstate_t state; - - /* Make sure we have enough space in the conversion buffer to store all - * the argv strings. */ - for (i = 0, bufspace = 0; i < argc; ++i) - bufspace += argv[i] ? strlen(argv[i]) + 1 : 0; - ct_conv_buff_resize(conv, (size_t)0, bufspace); - if (!conv->wsize) - return NULL; - - wargv = el_malloc((size_t)argc * sizeof(*wargv)); - - for (i = 0, p = conv->wbuff; i < argc; ++i) { - if (!argv[i]) { /* don't pass null pointers to mbsrtowcs */ - wargv[i] = NULL; - continue; - } else { - wargv[i] = p; - memset(&state, 0, sizeof(mbstate_t)); - bytes = (ssize_t)mbsrtowcs(p, argv + i, bufspace, &state); - } - if (bytes == -1) { - el_free(wargv); - return NULL; - } else - bytes++; /* include '\0' in the count */ - bufspace -= (size_t)bytes; - p += bytes; - } - - return wargv; -} - - -protected size_t -ct_enc_width(Char c) -{ - /* UTF-8 encoding specific values */ - if (c < 0x80) - return 1; - else if (c < 0x0800) - return 2; - else if (c < 0x10000) - return 3; - else if (c < 0x110000) - return 4; - else - return 0; /* not a valid codepoint */ -} - -protected ssize_t -ct_encode_char(char *dst, size_t len, Char c, mbstate_t *state) -{ - ssize_t l = 0; - - if (len < ct_enc_width(c)) - return -1; - - l = wcrtomb(dst, c, state); - - if (l < 0) { - memset (state, 0, sizeof (mbstate_t)); - l = 0; - } - return l; -} -#endif - -protected const Char * -ct_visual_string(const Char *s) -{ - static Char *buff = NULL; - static size_t buffsize = 0; - void *p; - Char *dst; - ssize_t used = 0; - - if (!s) - return NULL; - if (!buff) { - buffsize = CT_BUFSIZ; - buff = el_malloc(buffsize * sizeof(*buff)); - } - dst = buff; - while (*s) { - used = ct_visual_char(dst, buffsize - (size_t)(dst - buff), *s); - if (used == -1) { /* failed to encode, need more buffer space */ - used = dst - buff; - buffsize += CT_BUFSIZ; - p = el_realloc(buff, buffsize * sizeof(*buff)); - if (p == NULL) - goto out; - buff = p; - dst = buff + used; - /* don't increment s here - we want to retry it! */ - } - else - ++s; - dst += used; - } - if (dst >= (buff + buffsize)) { /* sigh */ - buffsize += 1; - p = el_realloc(buff, buffsize * sizeof(*buff)); - if (p == NULL) - goto out; - buff = p; - dst = buff + buffsize - 1; - } - *dst = 0; - return buff; -out: - el_free(buff); - buffsize = 0; - return NULL; -} - - -protected int -ct_visual_width(Char c) -{ - int t = ct_chr_class(c); - switch (t) { - case CHTYPE_ASCIICTL: - return 2; /* ^@ ^? etc. */ - case CHTYPE_TAB: - return 1; /* Hmm, this really need to be handled outside! */ - case CHTYPE_NL: - return 0; /* Should this be 1 instead? */ -#ifdef WIDECHAR - case CHTYPE_PRINT: - return wcwidth(c); - case CHTYPE_NONPRINT: - if (c > 0xffff) /* prefer standard 4-byte display over 5-byte */ - return 8; /* \U+12345 */ - else - return 7; /* \U+1234 */ -#else - case CHTYPE_PRINT: - return 1; - case CHTYPE_NONPRINT: - return 4; /* \123 */ -#endif - default: - return 0; /* should not happen */ - } -} - - -protected ssize_t -ct_visual_char(Char *dst, size_t len, Char c) -{ - int t = ct_chr_class(c); - switch (t) { - case CHTYPE_TAB: - case CHTYPE_NL: - case CHTYPE_ASCIICTL: - if (len < 2) - return -1; /* insufficient space */ - *dst++ = '^'; - if (c == '\177') - *dst = '?'; /* DEL -> ^? */ - else - *dst = c | 0100; /* uncontrolify it */ - return 2; - case CHTYPE_PRINT: - if (len < 1) - return -1; /* insufficient space */ - *dst = c; - return 1; - case CHTYPE_NONPRINT: - /* we only use single-width glyphs for display, - * so this is right */ - if ((ssize_t)len < ct_visual_width(c)) - return -1; /* insufficient space */ -#ifdef WIDECHAR - *dst++ = '\\'; - *dst++ = 'U'; - *dst++ = '+'; -#define tohexdigit(v) "0123456789ABCDEF"[v] - if (c > 0xffff) /* prefer standard 4-byte display over 5-byte */ - *dst++ = tohexdigit(((unsigned int) c >> 16) & 0xf); - *dst++ = tohexdigit(((unsigned int) c >> 12) & 0xf); - *dst++ = tohexdigit(((unsigned int) c >> 8) & 0xf); - *dst++ = tohexdigit(((unsigned int) c >> 4) & 0xf); - *dst = tohexdigit(((unsigned int) c ) & 0xf); - return c > 0xffff ? 8 : 7; -#else - *dst++ = '\\'; -#define tooctaldigit(v) ((v) + '0') - *dst++ = tooctaldigit(((unsigned int) c >> 6) & 0x7); - *dst++ = tooctaldigit(((unsigned int) c >> 3) & 0x7); - *dst++ = tooctaldigit(((unsigned int) c ) & 0x7); -#endif - /*FALLTHROUGH*/ - /* these two should be handled outside this function */ - default: /* we should never hit the default */ - return 0; - } -} - - - - -protected int -ct_chr_class(Char c) -{ - if (c == '\t') - return CHTYPE_TAB; - else if (c == '\n') - return CHTYPE_NL; - else if (IsASCII(c) && Iscntrl(c)) - return CHTYPE_ASCIICTL; - else if (Isprint(c)) - return CHTYPE_PRINT; - else - return CHTYPE_NONPRINT; -} diff --git a/cmd-line-utils/libedit/chartype.h b/cmd-line-utils/libedit/chartype.h deleted file mode 100644 index 576abe13ad5..00000000000 --- a/cmd-line-utils/libedit/chartype.h +++ /dev/null @@ -1,252 +0,0 @@ -/* $NetBSD: chartype.h,v 1.8 2011/07/29 23:44:44 christos Exp $ */ - -/*- - * Copyright (c) 2009 The NetBSD Foundation, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _h_chartype_f -#define _h_chartype_f - - - -#ifdef WIDECHAR - -/* Ideally we should also test the value of the define to see if it - * supports non-BMP code points without requiring UTF-16, but nothing - * seems to actually advertise this properly, despite Unicode 3.1 having - * been around since 2001... */ - -/* XXXMYSQL : Added FreeBSD & AIX to bypass this check. - TODO : Verify if FreeBSD & AIX stores ISO 10646 in wchar_t. */ -#if !defined(__NetBSD__) && !defined(__sun) \ - && !(defined(__APPLE__) && defined(__MACH__)) \ - && !defined(__FreeBSD__) && !defined(_AIX) && !defined(__OpenBSD__) -#ifndef __STDC_ISO_10646__ -/* In many places it is assumed that the first 127 code points are ASCII - * compatible, so ensure wchar_t indeed does ISO 10646 and not some other - * funky encoding that could break us in weird and wonderful ways. */ - #error wchar_t must store ISO 10646 characters -#endif -#endif - -/* Oh for a with char32_t and __STDC_UTF_32__ in it... - * ref: ISO/IEC DTR 19769 - */ -#if WCHAR_MAX < INT32_MAX -#warning Build environment does not support non-BMP characters -#endif - -#ifndef HAVE_WCSDUP -wchar_t *wcsdup(const wchar_t *s); -#endif - -#define ct_wctomb wctomb -#define ct_wctomb_reset wctomb(0,0) -#define ct_wcstombs wcstombs -#define ct_mbstowcs mbstowcs - -#define Char wchar_t -#define Int wint_t -#define FUN(prefix,rest) prefix ## _w ## rest -#define FUNW(type) type ## _w -#define TYPE(type) type ## W -#define FSTR "%ls" -#define STR(x) L ## x -#define UC(c) c -#define Isalpha(x) iswalpha(x) -#define Isalnum(x) iswalnum(x) -#define Isgraph(x) iswgraph(x) -#define Isspace(x) iswspace(x) -#define Isdigit(x) iswdigit(x) -#define Iscntrl(x) iswcntrl(x) -#define Isprint(x) iswprint(x) - -#define Isupper(x) iswupper(x) -#define Islower(x) iswlower(x) -#define Toupper(x) towupper(x) -#define Tolower(x) towlower(x) - -#define IsASCII(x) (x < 0x100) - -#define Strlen(x) wcslen(x) -#define Strchr(s,c) wcschr(s,c) -#define Strrchr(s,c) wcsrchr(s,c) -#define Strstr(s,v) wcsstr(s,v) -#define Strdup(x) wcsdup(x) -#define Strcpy(d,s) wcscpy(d,s) -#define Strncpy(d,s,n) wcsncpy(d,s,n) -#define Strncat(d,s,n) wcsncat(d,s,n) - -#define Strcmp(s,v) wcscmp(s,v) -#define Strncmp(s,v,n) wcsncmp(s,v,n) -#define Strcspn(s,r) wcscspn(s,r) - -#define Strtol(p,e,b) wcstol(p,e,b) - -#define Width(c) wcwidth(c) - -#else /* NARROW */ - -#define ct_mbtowc error -#define ct_mbtowc_reset -#define ct_wctomb error -#define ct_wctomb_reset -#define ct_wcstombs(a, b, c) (strncpy(a, b, c), strlen(a)) -#define ct_mbstowcs(a, b, c) (strncpy(a, b, c), strlen(a)) - -#define Char char -#define Int int -#define FUN(prefix,rest) prefix ## _ ## rest -#define FUNW(type) type -#define TYPE(type) type -#define FSTR "%s" -#define STR(x) x -#define UC(c) (unsigned char)(c) - -#define Isalpha(x) isalpha((unsigned char)x) -#define Isalnum(x) isalnum((unsigned char)x) -#define Isgraph(x) isgraph((unsigned char)x) -#define Isspace(x) isspace((unsigned char)x) -#define Isdigit(x) isdigit((unsigned char)x) -#define Iscntrl(x) iscntrl((unsigned char)x) -#define Isprint(x) isprint((unsigned char)x) - -#define Isupper(x) isupper((unsigned char)x) -#define Islower(x) islower((unsigned char)x) -#define Toupper(x) toupper((unsigned char)x) -#define Tolower(x) tolower((unsigned char)x) - -#define IsASCII(x) isascii((unsigned char)x) - -#define Strlen(x) strlen(x) -#define Strchr(s,c) strchr(s,c) -#define Strrchr(s,c) strrchr(s,c) -#define Strstr(s,v) strstr(s,v) -#define Strdup(x) strdup(x) -#define Strcpy(d,s) strcpy(d,s) -#define Strncpy(d,s,n) strncpy(d,s,n) -#define Strncat(d,s,n) strncat(d,s,n) - -#define Strcmp(s,v) strcmp(s,v) -#define Strncmp(s,v,n) strncmp(s,v,n) -#define Strcspn(s,r) strcspn(s,r) - -#define Strtol(p,e,b) strtol(p,e,b) - -#define Width(c) 1 - -#endif - - -#ifdef WIDECHAR -/* - * Conversion buffer - */ -typedef struct ct_buffer_t { - char *cbuff; - size_t csize; - Char *wbuff; - size_t wsize; -} ct_buffer_t; - -#define ct_encode_string __ct_encode_string -/* Encode a wide-character string and return the UTF-8 encoded result. */ -public char *ct_encode_string(const Char *, ct_buffer_t *); - -#define ct_decode_string __ct_decode_string -/* Decode a (multi)?byte string and return the wide-character string result. */ -public Char *ct_decode_string(const char *, ct_buffer_t *); - -/* Decode a (multi)?byte argv string array. - * The pointer returned must be free()d when done. */ -protected Char **ct_decode_argv(int, const char *[], ct_buffer_t *); - -/* Resizes the conversion buffer(s) if needed. */ -protected void ct_conv_buff_resize(ct_buffer_t *, size_t, size_t); -protected ssize_t ct_encode_char(char *, size_t, Char, mbstate_t *); -protected size_t ct_enc_width(Char); - -#define ct_free_argv(s) el_free(s) - -#else -#define ct_encode_string(s, b) (s) -#define ct_decode_string(s, b) (s) -#define ct_decode_argv(l, s, b) (s) -#define ct_conv_buff_resize(b, os, ns) -#define ct_encode_char(d, l, s, ps) (*d = s, 1) -#define ct_free_argv(s) -#endif - -#ifndef NARROWCHAR -/* Encode a characted into the destination buffer, provided there is sufficent - * buffer space available. Returns the number of bytes used up (zero if the - * character cannot be encoded, -1 if there was not enough space available). */ - -/* The maximum buffer size to hold the most unwieldly visual representation, - * in this case \U+nnnnn. */ -#define VISUAL_WIDTH_MAX ((size_t)8) - -/* The terminal is thought of in terms of X columns by Y lines. In the cases - * where a wide character takes up more than one column, the adjacent - * occupied column entries will contain this faux character. */ -#define MB_FILL_CHAR ((Char)-1) - -/* Visual width of character c, taking into account ^? , \0177 and \U+nnnnn - * style visual expansions. */ -protected int ct_visual_width(Char); - -/* Turn the given character into the appropriate visual format, matching - * the width given by ct_visual_width(). Returns the number of characters used - * up, or -1 if insufficient space. Buffer length is in count of Char's. */ -protected ssize_t ct_visual_char(Char *, size_t, Char); - -/* Convert the given string into visual format, using the ct_visual_char() - * function. Uses a static buffer, so not threadsafe. */ -protected const Char *ct_visual_string(const Char *); - - -/* printable character, use ct_visual_width() to find out display width */ -#define CHTYPE_PRINT ( 0) -/* control character found inside the ASCII portion of the charset */ -#define CHTYPE_ASCIICTL (-1) -/* a \t */ -#define CHTYPE_TAB (-2) -/* a \n */ -#define CHTYPE_NL (-3) -/* non-printable character */ -#define CHTYPE_NONPRINT (-4) -/* classification of character c, as one of the above defines */ -protected int ct_chr_class(Char c); -#endif - - -#endif /* _chartype_f */ diff --git a/cmd-line-utils/libedit/common.c b/cmd-line-utils/libedit/common.c deleted file mode 100644 index c0512061e6f..00000000000 --- a/cmd-line-utils/libedit/common.c +++ /dev/null @@ -1,921 +0,0 @@ -/* $NetBSD: common.c,v 1.28 2011/07/29 20:58:07 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)common.c 8.1 (Berkeley) 6/4/93"; -#else -#endif -#endif /* not lint && not SCCSID */ - -/* - * common.c: Common Editor functions - */ -#include "el.h" - -/* ed_end_of_file(): - * Indicate end of file - * [^D] - */ -protected el_action_t -/*ARGSUSED*/ -ed_end_of_file(EditLine *el, Int c __attribute__((__unused__))) -{ - - re_goto_bottom(el); - *el->el_line.lastchar = '\0'; - return CC_EOF; -} - - -/* ed_insert(): - * Add character to the line - * Insert a character [bound to all insert keys] - */ -protected el_action_t -ed_insert(EditLine *el, Int c) -{ - int count = el->el_state.argument; - - if (c == '\0') - return CC_ERROR; - - if (el->el_line.lastchar + el->el_state.argument >= - el->el_line.limit) { - /* end of buffer space, try to allocate more */ - if (!ch_enlargebufs(el, (size_t) count)) - return CC_ERROR; /* error allocating more */ - } - - if (count == 1) { - if (el->el_state.inputmode == MODE_INSERT - || el->el_line.cursor >= el->el_line.lastchar) - c_insert(el, 1); - - *el->el_line.cursor++ = c; - re_fastaddc(el); /* fast refresh for one char. */ - } else { - if (el->el_state.inputmode != MODE_REPLACE_1) - c_insert(el, el->el_state.argument); - - while (count-- && el->el_line.cursor < el->el_line.lastchar) - *el->el_line.cursor++ = c; - re_refresh(el); - } - - if (el->el_state.inputmode == MODE_REPLACE_1) - return vi_command_mode(el, 0); - - return CC_NORM; -} - - -/* ed_delete_prev_word(): - * Delete from beginning of current word to cursor - * [M-^?] [^W] - */ -protected el_action_t -/*ARGSUSED*/ -ed_delete_prev_word(EditLine *el, Int c __attribute__((__unused__))) -{ - Char *cp, *p, *kp; - - if (el->el_line.cursor == el->el_line.buffer) - return CC_ERROR; - - cp = c__prev_word(el->el_line.cursor, el->el_line.buffer, - el->el_state.argument, ce__isword); - - for (p = cp, kp = el->el_chared.c_kill.buf; p < el->el_line.cursor; p++) - *kp++ = *p; - el->el_chared.c_kill.last = kp; - - c_delbefore(el, (int)(el->el_line.cursor - cp));/* delete before dot */ - el->el_line.cursor = cp; - if (el->el_line.cursor < el->el_line.buffer) - el->el_line.cursor = el->el_line.buffer; /* bounds check */ - return CC_REFRESH; -} - - -/* ed_delete_next_char(): - * Delete character under cursor - * [^D] [x] - */ -protected el_action_t -/*ARGSUSED*/ -ed_delete_next_char(EditLine *el, Int c __attribute__((__unused__))) -{ -#ifdef DEBUG_EDIT -#define EL el->el_line - (void) fprintf(el->el_errlfile, - "\nD(b: %x(%s) c: %x(%s) last: %x(%s) limit: %x(%s)\n", - EL.buffer, EL.buffer, EL.cursor, EL.cursor, EL.lastchar, - EL.lastchar, EL.limit, EL.limit); -#endif - if (el->el_line.cursor == el->el_line.lastchar) { - /* if I'm at the end */ - if (el->el_map.type == MAP_VI) { - if (el->el_line.cursor == el->el_line.buffer) { - /* if I'm also at the beginning */ -#ifdef KSHVI - return CC_ERROR; -#else - /* then do an EOF */ - terminal_writec(el, c); - return CC_EOF; -#endif - } else { -#ifdef KSHVI - el->el_line.cursor--; -#else - return CC_ERROR; -#endif - } - } else { - if (el->el_line.cursor != el->el_line.buffer) - el->el_line.cursor--; - else - return CC_ERROR; - } - } - c_delafter(el, el->el_state.argument); /* delete after dot */ - if (el->el_line.cursor >= el->el_line.lastchar && - el->el_line.cursor > el->el_line.buffer) - /* bounds check */ - el->el_line.cursor = el->el_line.lastchar - 1; - return CC_REFRESH; -} - - -/* ed_kill_line(): - * Cut to the end of line - * [^K] [^K] - */ -protected el_action_t -/*ARGSUSED*/ -ed_kill_line(EditLine *el, Int c __attribute__((__unused__))) -{ - Char *kp, *cp; - - cp = el->el_line.cursor; - kp = el->el_chared.c_kill.buf; - while (cp < el->el_line.lastchar) - *kp++ = *cp++; /* copy it */ - el->el_chared.c_kill.last = kp; - /* zap! -- delete to end */ - el->el_line.lastchar = el->el_line.cursor; - return CC_REFRESH; -} - - -/* ed_move_to_end(): - * Move cursor to the end of line - * [^E] [^E] - */ -protected el_action_t -/*ARGSUSED*/ -ed_move_to_end(EditLine *el, Int c __attribute__((__unused__))) -{ - - el->el_line.cursor = el->el_line.lastchar; - if (el->el_map.type == MAP_VI) { - if (el->el_chared.c_vcmd.action != NOP) { - cv_delfini(el); - return CC_REFRESH; - } -#ifdef VI_MOVE - el->el_line.cursor--; -#endif - } - return CC_CURSOR; -} - - -/* ed_move_to_beg(): - * Move cursor to the beginning of line - * [^A] [^A] - */ -protected el_action_t -/*ARGSUSED*/ -ed_move_to_beg(EditLine *el, Int c __attribute__((__unused__))) -{ - - el->el_line.cursor = el->el_line.buffer; - - if (el->el_map.type == MAP_VI) { - /* We want FIRST non space character */ - while (Isspace(*el->el_line.cursor)) - el->el_line.cursor++; - if (el->el_chared.c_vcmd.action != NOP) { - cv_delfini(el); - return CC_REFRESH; - } - } - return CC_CURSOR; -} - - -/* ed_transpose_chars(): - * Exchange the character to the left of the cursor with the one under it - * [^T] [^T] - */ -protected el_action_t -ed_transpose_chars(EditLine *el, Int c) -{ - - if (el->el_line.cursor < el->el_line.lastchar) { - if (el->el_line.lastchar <= &el->el_line.buffer[1]) - return CC_ERROR; - else - el->el_line.cursor++; - } - if (el->el_line.cursor > &el->el_line.buffer[1]) { - /* must have at least two chars entered */ - c = el->el_line.cursor[-2]; - el->el_line.cursor[-2] = el->el_line.cursor[-1]; - el->el_line.cursor[-1] = c; - return CC_REFRESH; - } else - return CC_ERROR; -} - - -/* ed_next_char(): - * Move to the right one character - * [^F] [^F] - */ -protected el_action_t -/*ARGSUSED*/ -ed_next_char(EditLine *el, Int c __attribute__((__unused__))) -{ - Char *lim = el->el_line.lastchar; - - if (el->el_line.cursor >= lim || - (el->el_line.cursor == lim - 1 && - el->el_map.type == MAP_VI && - el->el_chared.c_vcmd.action == NOP)) - return CC_ERROR; - - el->el_line.cursor += el->el_state.argument; - if (el->el_line.cursor > lim) - el->el_line.cursor = lim; - - if (el->el_map.type == MAP_VI) - if (el->el_chared.c_vcmd.action != NOP) { - cv_delfini(el); - return CC_REFRESH; - } - return CC_CURSOR; -} - - -/* ed_prev_word(): - * Move to the beginning of the current word - * [M-b] [b] - */ -protected el_action_t -/*ARGSUSED*/ -ed_prev_word(EditLine *el, Int c __attribute__((__unused__))) -{ - - if (el->el_line.cursor == el->el_line.buffer) - return CC_ERROR; - - el->el_line.cursor = c__prev_word(el->el_line.cursor, - el->el_line.buffer, - el->el_state.argument, - ce__isword); - - if (el->el_map.type == MAP_VI) - if (el->el_chared.c_vcmd.action != NOP) { - cv_delfini(el); - return CC_REFRESH; - } - return CC_CURSOR; -} - - -/* ed_prev_char(): - * Move to the left one character - * [^B] [^B] - */ -protected el_action_t -/*ARGSUSED*/ -ed_prev_char(EditLine *el, Int c __attribute__((__unused__))) -{ - - if (el->el_line.cursor > el->el_line.buffer) { - el->el_line.cursor -= el->el_state.argument; - if (el->el_line.cursor < el->el_line.buffer) - el->el_line.cursor = el->el_line.buffer; - - if (el->el_map.type == MAP_VI) - if (el->el_chared.c_vcmd.action != NOP) { - cv_delfini(el); - return CC_REFRESH; - } - return CC_CURSOR; - } else - return CC_ERROR; -} - - -/* ed_quoted_insert(): - * Add the next character typed verbatim - * [^V] [^V] - */ -protected el_action_t -ed_quoted_insert(EditLine *el, Int c) -{ - int num; - Char tc; - - tty_quotemode(el); - num = FUN(el,getc)(el, &tc); - c = tc; - tty_noquotemode(el); - if (num == 1) - return ed_insert(el, c); - else - return ed_end_of_file(el, 0); -} - - -/* ed_digit(): - * Adds to argument or enters a digit - */ -protected el_action_t -ed_digit(EditLine *el, Int c) -{ - - if (!Isdigit(c)) - return CC_ERROR; - - if (el->el_state.doingarg) { - /* if doing an arg, add this in... */ - if (el->el_state.lastcmd == EM_UNIVERSAL_ARGUMENT) - el->el_state.argument = c - '0'; - else { - if (el->el_state.argument > 1000000) - return CC_ERROR; - el->el_state.argument = - (el->el_state.argument * 10) + (c - '0'); - } - return CC_ARGHACK; - } - - return ed_insert(el, c); -} - - -/* ed_argument_digit(): - * Digit that starts argument - * For ESC-n - */ -protected el_action_t -ed_argument_digit(EditLine *el, Int c) -{ - - if (!Isdigit(c)) - return CC_ERROR; - - if (el->el_state.doingarg) { - if (el->el_state.argument > 1000000) - return CC_ERROR; - el->el_state.argument = (el->el_state.argument * 10) + - (c - '0'); - } else { /* else starting an argument */ - el->el_state.argument = c - '0'; - el->el_state.doingarg = 1; - } - return CC_ARGHACK; -} - - -/* ed_unassigned(): - * Indicates unbound character - * Bound to keys that are not assigned - */ -protected el_action_t -/*ARGSUSED*/ -ed_unassigned(EditLine *el __attribute__((__unused__)), - Int c __attribute__((__unused__))) -{ - - return CC_ERROR; -} - - -/** - ** TTY key handling. - **/ - -/* ed_tty_sigint(): - * Tty interrupt character - * [^C] - */ -protected el_action_t -/*ARGSUSED*/ -ed_tty_sigint(EditLine *el __attribute__((__unused__)), - Int c __attribute__((__unused__))) -{ - - return CC_NORM; -} - - -/* ed_tty_dsusp(): - * Tty delayed suspend character - * [^Y] - */ -protected el_action_t -/*ARGSUSED*/ -ed_tty_dsusp(EditLine *el __attribute__((__unused__)), - Int c __attribute__((__unused__))) -{ - - return CC_NORM; -} - - -/* ed_tty_flush_output(): - * Tty flush output characters - * [^O] - */ -protected el_action_t -/*ARGSUSED*/ -ed_tty_flush_output(EditLine *el __attribute__((__unused__)), - Int c __attribute__((__unused__))) -{ - - return CC_NORM; -} - - -/* ed_tty_sigquit(): - * Tty quit character - * [^\] - */ -protected el_action_t -/*ARGSUSED*/ -ed_tty_sigquit(EditLine *el __attribute__((__unused__)), - Int c __attribute__((__unused__))) -{ - - return CC_NORM; -} - - -/* ed_tty_sigtstp(): - * Tty suspend character - * [^Z] - */ -protected el_action_t -/*ARGSUSED*/ -ed_tty_sigtstp(EditLine *el __attribute__((__unused__)), - Int c __attribute__((__unused__))) -{ - - return CC_NORM; -} - - -/* ed_tty_stop_output(): - * Tty disallow output characters - * [^S] - */ -protected el_action_t -/*ARGSUSED*/ -ed_tty_stop_output(EditLine *el __attribute__((__unused__)), - Int c __attribute__((__unused__))) -{ - - return CC_NORM; -} - - -/* ed_tty_start_output(): - * Tty allow output characters - * [^Q] - */ -protected el_action_t -/*ARGSUSED*/ -ed_tty_start_output(EditLine *el __attribute__((__unused__)), - Int c __attribute__((__unused__))) -{ - - return CC_NORM; -} - - -/* ed_newline(): - * Execute command - * [^J] - */ -protected el_action_t -/*ARGSUSED*/ -ed_newline(EditLine *el, Int c __attribute__((__unused__))) -{ - - re_goto_bottom(el); - *el->el_line.lastchar++ = '\n'; - *el->el_line.lastchar = '\0'; - return CC_NEWLINE; -} - - -/* ed_delete_prev_char(): - * Delete the character to the left of the cursor - * [^?] - */ -protected el_action_t -/*ARGSUSED*/ -ed_delete_prev_char(EditLine *el, Int c __attribute__((__unused__))) -{ - - if (el->el_line.cursor <= el->el_line.buffer) - return CC_ERROR; - - c_delbefore(el, el->el_state.argument); - el->el_line.cursor -= el->el_state.argument; - if (el->el_line.cursor < el->el_line.buffer) - el->el_line.cursor = el->el_line.buffer; - return CC_REFRESH; -} - - -/* ed_clear_screen(): - * Clear screen leaving current line at the top - * [^L] - */ -protected el_action_t -/*ARGSUSED*/ -ed_clear_screen(EditLine *el, Int c __attribute__((__unused__))) -{ - - terminal_clear_screen(el); /* clear the whole real screen */ - re_clear_display(el); /* reset everything */ - return CC_REFRESH; -} - - -/* ed_redisplay(): - * Redisplay everything - * ^R - */ -protected el_action_t -/*ARGSUSED*/ -ed_redisplay(EditLine *el __attribute__((__unused__)), - Int c __attribute__((__unused__))) -{ - - return CC_REDISPLAY; -} - - -/* ed_start_over(): - * Erase current line and start from scratch - * [^G] - */ -protected el_action_t -/*ARGSUSED*/ -ed_start_over(EditLine *el, Int c __attribute__((__unused__))) -{ - - ch_reset(el, 0); - return CC_REFRESH; -} - - -/* ed_sequence_lead_in(): - * First character in a bound sequence - * Placeholder for external keys - */ -protected el_action_t -/*ARGSUSED*/ -ed_sequence_lead_in(EditLine *el __attribute__((__unused__)), - Int c __attribute__((__unused__))) -{ - - return CC_NORM; -} - - -/* ed_prev_history(): - * Move to the previous history line - * [^P] [k] - */ -protected el_action_t -/*ARGSUSED*/ -ed_prev_history(EditLine *el, Int c __attribute__((__unused__))) -{ - char beep = 0; - int sv_event = el->el_history.eventno; - - el->el_chared.c_undo.len = -1; - *el->el_line.lastchar = '\0'; /* just in case */ - - if (el->el_history.eventno == 0) { /* save the current buffer - * away */ - (void) Strncpy(el->el_history.buf, el->el_line.buffer, - EL_BUFSIZ); - el->el_history.last = el->el_history.buf + - (el->el_line.lastchar - el->el_line.buffer); - } - el->el_history.eventno += el->el_state.argument; - - if (hist_get(el) == CC_ERROR) { - if (el->el_map.type == MAP_VI) { - el->el_history.eventno = sv_event; - - } - beep = 1; - /* el->el_history.eventno was fixed by first call */ - (void) hist_get(el); - } - if (beep) - return CC_REFRESH_BEEP; - return CC_REFRESH; -} - - -/* ed_next_history(): - * Move to the next history line - * [^N] [j] - */ -protected el_action_t -/*ARGSUSED*/ -ed_next_history(EditLine *el, Int c __attribute__((__unused__))) -{ - el_action_t beep = CC_REFRESH, rval; - - el->el_chared.c_undo.len = -1; - *el->el_line.lastchar = '\0'; /* just in case */ - - el->el_history.eventno -= el->el_state.argument; - - if (el->el_history.eventno < 0) { - el->el_history.eventno = 0; - beep = CC_REFRESH_BEEP; - } - rval = hist_get(el); - if (rval == CC_REFRESH) - return beep; - return rval; - -} - - -/* ed_search_prev_history(): - * Search previous in history for a line matching the current - * next search history [M-P] [K] - */ -protected el_action_t -/*ARGSUSED*/ -ed_search_prev_history(EditLine *el, Int c __attribute__((__unused__))) -{ - const Char *hp; - int h; - bool_t found = 0; - - el->el_chared.c_vcmd.action = NOP; - el->el_chared.c_undo.len = -1; - *el->el_line.lastchar = '\0'; /* just in case */ - if (el->el_history.eventno < 0) { -#ifdef DEBUG_EDIT - (void) fprintf(el->el_errfile, - "e_prev_search_hist(): eventno < 0;\n"); -#endif - el->el_history.eventno = 0; - return CC_ERROR; - } - if (el->el_history.eventno == 0) { - (void) Strncpy(el->el_history.buf, el->el_line.buffer, - EL_BUFSIZ); - el->el_history.last = el->el_history.buf + - (el->el_line.lastchar - el->el_line.buffer); - } - if (el->el_history.ref == NULL) - return CC_ERROR; - - hp = HIST_FIRST(el); - if (hp == NULL) - return CC_ERROR; - - c_setpat(el); /* Set search pattern !! */ - - for (h = 1; h <= el->el_history.eventno; h++) - hp = HIST_NEXT(el); - - while (hp != NULL) { -#ifdef SDEBUG - (void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp); -#endif - if ((Strncmp(hp, el->el_line.buffer, (size_t) - (el->el_line.lastchar - el->el_line.buffer)) || - hp[el->el_line.lastchar - el->el_line.buffer]) && - c_hmatch(el, hp)) { - found++; - break; - } - h++; - hp = HIST_NEXT(el); - } - - if (!found) { -#ifdef SDEBUG - (void) fprintf(el->el_errfile, "not found\n"); -#endif - return CC_ERROR; - } - el->el_history.eventno = h; - - return hist_get(el); -} - - -/* ed_search_next_history(): - * Search next in history for a line matching the current - * [M-N] [J] - */ -protected el_action_t -/*ARGSUSED*/ -ed_search_next_history(EditLine *el, Int c __attribute__((__unused__))) -{ - const Char *hp; - int h; - bool_t found = 0; - - el->el_chared.c_vcmd.action = NOP; - el->el_chared.c_undo.len = -1; - *el->el_line.lastchar = '\0'; /* just in case */ - - if (el->el_history.eventno == 0) - return CC_ERROR; - - if (el->el_history.ref == NULL) - return CC_ERROR; - - hp = HIST_FIRST(el); - if (hp == NULL) - return CC_ERROR; - - c_setpat(el); /* Set search pattern !! */ - - for (h = 1; h < el->el_history.eventno && hp; h++) { -#ifdef SDEBUG - (void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp); -#endif - if ((Strncmp(hp, el->el_line.buffer, (size_t) - (el->el_line.lastchar - el->el_line.buffer)) || - hp[el->el_line.lastchar - el->el_line.buffer]) && - c_hmatch(el, hp)) - found = h; - hp = HIST_NEXT(el); - } - - if (!found) { /* is it the current history number? */ - if (!c_hmatch(el, el->el_history.buf)) { -#ifdef SDEBUG - (void) fprintf(el->el_errfile, "not found\n"); -#endif - return CC_ERROR; - } - } - el->el_history.eventno = found; - - return hist_get(el); -} - - -/* ed_prev_line(): - * Move up one line - * Could be [k] [^p] - */ -protected el_action_t -/*ARGSUSED*/ -ed_prev_line(EditLine *el, Int c __attribute__((__unused__))) -{ - Char *ptr; - int nchars = c_hpos(el); - - /* - * Move to the line requested - */ - if (*(ptr = el->el_line.cursor) == '\n') - ptr--; - - for (; ptr >= el->el_line.buffer; ptr--) - if (*ptr == '\n' && --el->el_state.argument <= 0) - break; - - if (el->el_state.argument > 0) - return CC_ERROR; - - /* - * Move to the beginning of the line - */ - for (ptr--; ptr >= el->el_line.buffer && *ptr != '\n'; ptr--) - continue; - - /* - * Move to the character requested - */ - for (ptr++; - nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n'; - ptr++) - continue; - - el->el_line.cursor = ptr; - return CC_CURSOR; -} - - -/* ed_next_line(): - * Move down one line - * Could be [j] [^n] - */ -protected el_action_t -/*ARGSUSED*/ -ed_next_line(EditLine *el, Int c __attribute__((__unused__))) -{ - Char *ptr; - int nchars = c_hpos(el); - - /* - * Move to the line requested - */ - for (ptr = el->el_line.cursor; ptr < el->el_line.lastchar; ptr++) - if (*ptr == '\n' && --el->el_state.argument <= 0) - break; - - if (el->el_state.argument > 0) - return CC_ERROR; - - /* - * Move to the character requested - */ - for (ptr++; - nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n'; - ptr++) - continue; - - el->el_line.cursor = ptr; - return CC_CURSOR; -} - - -/* ed_command(): - * Editline extended command - * [M-X] [:] - */ -protected el_action_t -/*ARGSUSED*/ -ed_command(EditLine *el, Int c __attribute__((__unused__))) -{ - Char tmpbuf[EL_BUFSIZ]; - int tmplen; - - tmplen = c_gets(el, tmpbuf, STR("\n: ")); - terminal__putc(el, '\n'); - - if (tmplen < 0 || (tmpbuf[tmplen] = 0, parse_line(el, tmpbuf)) == -1) - terminal_beep(el); - - el->el_map.current = el->el_map.key; - re_clear_display(el); - return CC_REFRESH; -} diff --git a/cmd-line-utils/libedit/config.h b/cmd-line-utils/libedit/config.h deleted file mode 100644 index c06d5e28a0a..00000000000 --- a/cmd-line-utils/libedit/config.h +++ /dev/null @@ -1,5 +0,0 @@ -#include "my_config.h" -#include "sys.h" -#ifndef NARROW_WRAPPER -#define WIDECHAR -#endif diff --git a/cmd-line-utils/libedit/el.c b/cmd-line-utils/libedit/el.c deleted file mode 100644 index c7f4f81ec93..00000000000 --- a/cmd-line-utils/libedit/el.c +++ /dev/null @@ -1,636 +0,0 @@ -/* $NetBSD: el.c,v 1.68 2011/07/29 15:16:33 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)el.c 8.2 (Berkeley) 1/3/94"; -#else -#endif -#endif /* not lint && not SCCSID */ - -/* - * el.c: EditLine interface functions - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include "el.h" - -/* el_init(): - * Initialize editline and set default parameters. - */ -public EditLine * -el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr) -{ - EditLine *el = el_malloc(sizeof(*el)); - - if (el == NULL) - return NULL; - - memset(el, 0, sizeof(EditLine)); - - el->el_infile = fin; - el->el_outfile = fout; - el->el_errfile = ferr; - - el->el_infd = fileno(fin); - el->el_outfd = fileno(fout); - el->el_errfd = fileno(ferr); - - el->el_prog = Strdup(ct_decode_string(prog, &el->el_scratch)); - if (el->el_prog == NULL) { - el_free(el); - return NULL; - } - - /* - * Initialize all the modules. Order is important!!! - */ - el->el_flags = 0; -#ifdef WIDECHAR - setlocale(LC_CTYPE, NULL); - if (MB_CUR_MAX > 1) - el->el_flags |= CHARSET_IS_MULTIBYTE; -#endif - - if (terminal_init(el) == -1) { - el_free(el->el_prog); - el_free(el); - return NULL; - } - (void) keymacro_init(el); - (void) map_init(el); - if (tty_init(el) == -1) - el->el_flags |= NO_TTY; - (void) ch_init(el); - (void) search_init(el); - (void) hist_init(el); - (void) prompt_init(el); - (void) sig_init(el); - (void) read_init(el); - - return el; -} - - -/* el_end(): - * Clean up. - */ -public void -el_end(EditLine *el) -{ - - if (el == NULL) - return; - - el_reset(el); - - terminal_end(el); - keymacro_end(el); - map_end(el); - tty_end(el); - ch_end(el); - search_end(el); - hist_end(el); - prompt_end(el); - sig_end(el); - - el_free(el->el_prog); -#ifdef WIDECHAR - el_free(el->el_scratch.cbuff); - el_free(el->el_scratch.wbuff); - el_free(el->el_lgcyconv.cbuff); - el_free(el->el_lgcyconv.wbuff); -#endif - el_free(el); -} - - -/* el_reset(): - * Reset the tty and the parser - */ -public void -el_reset(EditLine *el) -{ - - tty_cookedmode(el); - ch_reset(el, 0); /* XXX: Do we want that? */ -} - - -/* el_set(): - * set the editline parameters - */ -public int -FUN(el,set)(EditLine *el, int op, ...) -{ - va_list ap; - int rv = 0; - - if (el == NULL) - return -1; - va_start(ap, op); - - switch (op) { - case EL_PROMPT: - case EL_RPROMPT: { - el_pfunc_t p = va_arg(ap, el_pfunc_t); - - rv = prompt_set(el, p, 0, op, 1); - break; - } - - case EL_RESIZE: { - el_zfunc_t p = va_arg(ap, el_zfunc_t); - void *arg = va_arg(ap, void *); - rv = ch_resizefun(el, p, arg); - break; - } - - case EL_PROMPT_ESC: - case EL_RPROMPT_ESC: { - el_pfunc_t p = va_arg(ap, el_pfunc_t); - int c = va_arg(ap, int); - - rv = prompt_set(el, p, c, op, 1); - break; - } - - case EL_TERMINAL: - rv = terminal_set(el, va_arg(ap, char *)); - break; - - case EL_EDITOR: - rv = map_set_editor(el, va_arg(ap, Char *)); - break; - - case EL_SIGNAL: - if (va_arg(ap, int)) - el->el_flags |= HANDLE_SIGNALS; - else - el->el_flags &= ~HANDLE_SIGNALS; - break; - - case EL_BIND: - case EL_TELLTC: - case EL_SETTC: - case EL_ECHOTC: - case EL_SETTY: - { - const Char *argv[20]; - int i; - - for (i = 1; i < 20; i++) - if ((argv[i] = va_arg(ap, Char *)) == NULL) - break; - - switch (op) { - case EL_BIND: - argv[0] = STR("bind"); - rv = map_bind(el, i, argv); - break; - - case EL_TELLTC: - argv[0] = STR("telltc"); - rv = terminal_telltc(el, i, argv); - break; - - case EL_SETTC: - argv[0] = STR("settc"); - rv = terminal_settc(el, i, argv); - break; - - case EL_ECHOTC: - argv[0] = STR("echotc"); - rv = terminal_echotc(el, i, argv); - break; - - case EL_SETTY: - argv[0] = STR("setty"); - rv = tty_stty(el, i, argv); - break; - - default: - rv = -1; - EL_ABORT((el->el_errfile, "Bad op %d\n", op)); - break; - } - break; - } - - case EL_ADDFN: - { - Char *name = va_arg(ap, Char *); - Char *help = va_arg(ap, Char *); - el_func_t func = va_arg(ap, el_func_t); - - rv = map_addfunc(el, name, help, func); - break; - } - - case EL_HIST: - { - hist_fun_t func = va_arg(ap, hist_fun_t); - void *ptr = va_arg(ap, void *); - - rv = hist_set(el, func, ptr); - if (!(el->el_flags & CHARSET_IS_MULTIBYTE)) - el->el_flags &= ~NARROW_HISTORY; - break; - } - - case EL_EDITMODE: - if (va_arg(ap, int)) - el->el_flags &= ~EDIT_DISABLED; - else - el->el_flags |= EDIT_DISABLED; - rv = 0; - break; - - case EL_GETCFN: - { - el_rfunc_t rc = va_arg(ap, el_rfunc_t); - rv = el_read_setfn(el, rc); - el->el_flags &= ~NARROW_READ; - break; - } - - case EL_CLIENTDATA: - el->el_data = va_arg(ap, void *); - break; - - case EL_UNBUFFERED: - rv = va_arg(ap, int); - if (rv && !(el->el_flags & UNBUFFERED)) { - el->el_flags |= UNBUFFERED; - read_prepare(el); - } else if (!rv && (el->el_flags & UNBUFFERED)) { - el->el_flags &= ~UNBUFFERED; - read_finish(el); - } - rv = 0; - break; - - case EL_PREP_TERM: - rv = va_arg(ap, int); - if (rv) - (void) tty_rawmode(el); - else - (void) tty_cookedmode(el); - rv = 0; - break; - - case EL_SETFP: - { - FILE *fp; - int what; - - what = va_arg(ap, int); - fp = va_arg(ap, FILE *); - - rv = 0; - switch (what) { - case 0: - el->el_infile = fp; - el->el_infd = fileno(fp); - break; - case 1: - el->el_outfile = fp; - el->el_outfd = fileno(fp); - break; - case 2: - el->el_errfile = fp; - el->el_errfd = fileno(fp); - break; - default: - rv = -1; - break; - } - break; - } - - case EL_REFRESH: - re_clear_display(el); - re_refresh(el); - terminal__flush(el); - break; - - default: - rv = -1; - break; - } - - va_end(ap); - return rv; -} - - -/* el_get(): - * retrieve the editline parameters - */ -public int -FUN(el,get)(EditLine *el, int op, ...) -{ - va_list ap; - int rv; - - if (el == NULL) - return -1; - - va_start(ap, op); - - switch (op) { - case EL_PROMPT: - case EL_RPROMPT: { - el_pfunc_t *p = va_arg(ap, el_pfunc_t *); - rv = prompt_get(el, p, 0, op); - break; - } - case EL_PROMPT_ESC: - case EL_RPROMPT_ESC: { - el_pfunc_t *p = va_arg(ap, el_pfunc_t *); - Char *c = va_arg(ap, Char *); - - rv = prompt_get(el, p, c, op); - break; - } - - case EL_EDITOR: - rv = map_get_editor(el, va_arg(ap, const Char **)); - break; - - case EL_SIGNAL: - *va_arg(ap, int *) = (el->el_flags & HANDLE_SIGNALS); - rv = 0; - break; - - case EL_EDITMODE: - *va_arg(ap, int *) = !(el->el_flags & EDIT_DISABLED); - rv = 0; - break; - - case EL_TERMINAL: - terminal_get(el, va_arg(ap, const char **)); - rv = 0; - break; - - case EL_GETTC: - { - static char name[] = "gettc"; - char *argv[20]; - int i; - - for (i = 1; i < (int)(sizeof(argv) / sizeof(argv[0])); i++) - if ((argv[i] = va_arg(ap, char *)) == NULL) - break; - - switch (op) { - case EL_GETTC: - argv[0] = name; - rv = terminal_gettc(el, i, argv); - break; - - default: - rv = -1; - EL_ABORT((el->el_errfile, "Bad op %d\n", op)); - break; - } - break; - } - - case EL_GETCFN: - *va_arg(ap, el_rfunc_t *) = el_read_getfn(el); - rv = 0; - break; - - case EL_CLIENTDATA: - *va_arg(ap, void **) = el->el_data; - rv = 0; - break; - - case EL_UNBUFFERED: - *va_arg(ap, int *) = (!(el->el_flags & UNBUFFERED)); - rv = 0; - break; - - case EL_GETFP: - { - int what; - FILE **fpp; - - what = va_arg(ap, int); - fpp = va_arg(ap, FILE **); - rv = 0; - switch (what) { - case 0: - *fpp = el->el_infile; - break; - case 1: - *fpp = el->el_outfile; - break; - case 2: - *fpp = el->el_errfile; - break; - default: - rv = -1; - break; - } - break; - } - default: - rv = -1; - break; - } - va_end(ap); - - return rv; -} - - -/* el_line(): - * Return editing info - */ -public const TYPE(LineInfo) * -FUN(el,line)(EditLine *el) -{ - - return (const TYPE(LineInfo) *)(void *)&el->el_line; -} - - -/* el_source(): - * Source a file - */ -public int -el_source(EditLine *el, const char *fname) -{ - FILE *fp; - size_t len; - char *ptr; - char *path = NULL; - const Char *dptr; - int error = 0; - - fp = NULL; - if (fname == NULL) { -/* XXXMYSQL: Bug#49967 */ -#if defined(HAVE_GETUID) && defined(HAVE_GETEUID) && \ - defined(HAVE_GETGID) && defined(HAVE_GETEGID) -#define HAVE_IDENTITY_FUNCS 1 -#endif - -#if (defined(HAVE_ISSETUGID) || defined(HAVE_IDENTITY_FUNCS)) - static const char elpath[] = "/.editrc"; - size_t plen = sizeof(elpath); -/* XXXMYSQL: Portability fix (for which platforms?) */ -#ifdef HAVE_ISSETUGID - if (issetugid()) - return -1; -#elif defined(HAVE_IDENTITY_FUNCS) - if (getuid() != geteuid() || getgid() != getegid()) - return (-1); -#endif - if ((ptr = getenv("HOME")) == NULL) - return -1; - plen += strlen(ptr); - if ((path = el_malloc(plen * sizeof(*path))) == NULL) - return -1; - (void)snprintf(path, plen, "%s%s", ptr, elpath); - fname = path; -#else - /* - * If issetugid() or the above mentioned get[e][u|g]id() - * functions are missing, always return an error, in order - * to keep from inadvertently opening up the user to a - * security hole. - */ - return -1; -#endif - } - if (fp == NULL) - fp = fopen(fname, "r"); - if (fp == NULL) { - el_free(path); - return -1; - } - - while ((ptr = fgetln(fp, &len)) != NULL) { - if (*ptr == '\n') - continue; /* Empty line. */ - dptr = ct_decode_string(ptr, &el->el_scratch); - if (!dptr) - continue; - if (len > 0 && dptr[len - 1] == '\n') - --len; - - /* loop until first non-space char or EOL */ - while (*dptr != '\0' && Isspace(*dptr)) - dptr++; - if (*dptr == '#') - continue; /* ignore, this is a comment line */ - if ((error = parse_line(el, dptr)) == -1) - break; - } - - el_free(path); - (void) fclose(fp); - return error; -} - - -/* el_resize(): - * Called from program when terminal is resized - */ -public void -el_resize(EditLine *el) -{ - int lins, cols; - sigset_t oset, nset; - - (void) sigemptyset(&nset); - (void) sigaddset(&nset, SIGWINCH); - (void) sigprocmask(SIG_BLOCK, &nset, &oset); - - /* get the correct window size */ - if (terminal_get_size(el, &lins, &cols)) - terminal_change_size(el, lins, cols); - - (void) sigprocmask(SIG_SETMASK, &oset, NULL); -} - - -/* el_beep(): - * Called from the program to beep - */ -public void -el_beep(EditLine *el) -{ - - terminal_beep(el); -} - - -/* el_editmode() - * Set the state of EDIT_DISABLED from the `edit' command. - */ -protected int -/*ARGSUSED*/ -el_editmode(EditLine *el, int argc, const Char **argv) -{ - const Char *how; - - if (argv == NULL || argc != 2 || argv[1] == NULL) - return -1; - - how = argv[1]; - if (Strcmp(how, STR("on")) == 0) { - el->el_flags &= ~EDIT_DISABLED; - tty_rawmode(el); - } else if (Strcmp(how, STR("off")) == 0) { - tty_cookedmode(el); - el->el_flags |= EDIT_DISABLED; - } - else { - (void) fprintf(el->el_errfile, "edit: Bad value `" FSTR "'.\n", - how); - return -1; - } - return 0; -} diff --git a/cmd-line-utils/libedit/el.h b/cmd-line-utils/libedit/el.h deleted file mode 100644 index 403a44aa806..00000000000 --- a/cmd-line-utils/libedit/el.h +++ /dev/null @@ -1,166 +0,0 @@ -/* $NetBSD: el.h,v 1.25 2011/07/29 23:44:44 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)el.h 8.1 (Berkeley) 6/4/93 - */ - -/* - * el.h: Internal structures. - */ -#ifndef _h_el -#define _h_el -/* - * Local defaults - */ -#define KSHVI -#define VIDEFAULT -#define ANCHOR - -#include "histedit.h" -#include "chartype.h" -#include -#include - -#define EL_BUFSIZ ((size_t)4096) /* Maximum line size */ - -#define HANDLE_SIGNALS 0x01 -#define NO_TTY 0x02 -#define EDIT_DISABLED 0x04 -#define UNBUFFERED 0x08 -#define CHARSET_IS_MULTIBYTE 0x10 -#define IGNORE_EXTCHARS 0x20 /* Ignore characters read > 0xff */ -#define NARROW_HISTORY 0x40 -#define NARROW_READ 0x80 - -typedef int bool_t; /* True or not */ - -typedef unsigned char el_action_t; /* Index to command array */ - -typedef struct coord_t { /* Position on the screen */ - int h; - int v; -} coord_t; - -typedef struct el_line_t { - Char *buffer; /* Input line */ - Char *cursor; /* Cursor position */ - Char *lastchar; /* Last character */ - const Char *limit; /* Max position */ -} el_line_t; - -/* - * Editor state - */ -typedef struct el_state_t { - int inputmode; /* What mode are we in? */ - int doingarg; /* Are we getting an argument? */ - int argument; /* Numeric argument */ - int metanext; /* Is the next char a meta char */ - el_action_t lastcmd; /* Previous command */ - el_action_t thiscmd; /* this command */ - Char thisch; /* char that generated it */ -} el_state_t; - -/* - * Until we come up with something better... - */ -#define el_malloc(a) malloc(a) -#define el_realloc(a,b) realloc(a, b) -#define el_free(a) free(a) - -#include "tty.h" -#include "prompt.h" -#include "keymacro.h" -#include "el_terminal.h" -#include "refresh.h" -#include "chared.h" -#include "common.h" -#include "search.h" -#include "hist.h" -#include "map.h" -#include "parse.h" -#include "sig.h" -#include "help.h" -#include "read.h" - -struct editline { - Char *el_prog; /* the program name */ - FILE *el_infile; /* Stdio stuff */ - FILE *el_outfile; /* Stdio stuff */ - FILE *el_errfile; /* Stdio stuff */ - int el_infd; /* Input file descriptor */ - int el_outfd; /* Output file descriptor */ - int el_errfd; /* Error file descriptor */ - int el_flags; /* Various flags. */ - int el_errno; /* Local copy of errno */ - coord_t el_cursor; /* Cursor location */ - Char **el_display; /* Real screen image = what is there */ - Char **el_vdisplay; /* Virtual screen image = what we see */ - void *el_data; /* Client data */ - el_line_t el_line; /* The current line information */ - el_state_t el_state; /* Current editor state */ - el_terminal_t el_terminal; /* Terminal dependent stuff */ - el_tty_t el_tty; /* Tty dependent stuff */ - el_refresh_t el_refresh; /* Refresh stuff */ - el_prompt_t el_prompt; /* Prompt stuff */ - el_prompt_t el_rprompt; /* Prompt stuff */ - el_chared_t el_chared; /* Characted editor stuff */ - el_map_t el_map; /* Key mapping stuff */ - el_keymacro_t el_keymacro; /* Key binding stuff */ - el_history_t el_history; /* History stuff */ - el_search_t el_search; /* Search stuff */ - el_signal_t el_signal; /* Signal handling stuff */ - el_read_t el_read; /* Character reading stuff */ -#ifdef WIDECHAR - ct_buffer_t el_scratch; /* Scratch conversion buffer */ - ct_buffer_t el_lgcyconv; /* Buffer for legacy wrappers */ - LineInfo el_lgcylinfo; /* Legacy LineInfo buffer */ -#endif -}; - -protected int el_editmode(EditLine *, int, const Char **); - -/* XXXMYSQL: Bug#23097 mysql can't insert korean on mysql prompt. */ -#define el_isprint(x) ((unsigned char) (x) < 0x80 ? isprint(x) : 1) - -#ifdef DEBUG -#define EL_ABORT(a) do { \ - fprintf(el->el_errfile, "%s, %d: ", \ - __FILE__, __LINE__); \ - fprintf a; \ - abort(); \ - } while( /*CONSTCOND*/0); -#else -#define EL_ABORT(a) abort() -#endif -#endif /* _h_el */ diff --git a/cmd-line-utils/libedit/el_terminal.h b/cmd-line-utils/libedit/el_terminal.h deleted file mode 100644 index 807c651783e..00000000000 --- a/cmd-line-utils/libedit/el_terminal.h +++ /dev/null @@ -1,125 +0,0 @@ -/* $NetBSD: terminal.h,v 1.3 2011/07/29 23:44:45 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)term.h 8.1 (Berkeley) 6/4/93 - */ - -/* - * el.term.h: Termcap header - */ -#ifndef _h_el_terminal -#define _h_el_terminal - -#include "histedit.h" - -typedef struct { /* Symbolic function key bindings */ - const Char *name; /* name of the key */ - int key; /* Index in termcap table */ - keymacro_value_t fun; /* Function bound to it */ - int type; /* Type of function */ -} funckey_t; - -typedef struct { - const char *t_name; /* the terminal name */ - coord_t t_size; /* # lines and cols */ - int t_flags; -#define TERM_CAN_INSERT 0x001 /* Has insert cap */ -#define TERM_CAN_DELETE 0x002 /* Has delete cap */ -#define TERM_CAN_CEOL 0x004 /* Has CEOL cap */ -#define TERM_CAN_TAB 0x008 /* Can use tabs */ -#define TERM_CAN_ME 0x010 /* Can turn all attrs. */ -#define TERM_CAN_UP 0x020 /* Can move up */ -#define TERM_HAS_META 0x040 /* Has a meta key */ -#define TERM_HAS_AUTO_MARGINS 0x080 /* Has auto margins */ -#define TERM_HAS_MAGIC_MARGINS 0x100 /* Has magic margins */ - char *t_buf; /* Termcap buffer */ - size_t t_loc; /* location used */ - char **t_str; /* termcap strings */ - int *t_val; /* termcap values */ - char *t_cap; /* Termcap buffer */ - funckey_t *t_fkey; /* Array of keys */ -} el_terminal_t; - -/* - * fKey indexes - */ -#define A_K_DN 0 -#define A_K_UP 1 -#define A_K_LT 2 -#define A_K_RT 3 -#define A_K_HO 4 -#define A_K_EN 5 -#define A_K_NKEYS 6 - -protected void terminal_move_to_line(EditLine *, int); -protected void terminal_move_to_char(EditLine *, int); -protected void terminal_clear_EOL(EditLine *, int); -protected void terminal_overwrite(EditLine *, const Char *, size_t); -protected void terminal_insertwrite(EditLine *, Char *, int); -protected void terminal_deletechars(EditLine *, int); -protected void terminal_clear_screen(EditLine *); -protected void terminal_beep(EditLine *); -protected int terminal_change_size(EditLine *, int, int); -protected int terminal_get_size(EditLine *, int *, int *); -protected int terminal_init(EditLine *); -protected void terminal_bind_arrow(EditLine *); -protected void terminal_print_arrow(EditLine *, const Char *); -protected int terminal_clear_arrow(EditLine *, const Char *); -protected int terminal_set_arrow(EditLine *, const Char *, keymacro_value_t *, int); -protected void terminal_end(EditLine *); -protected void terminal_get(EditLine *, const char **); -protected int terminal_set(EditLine *, const char *); -protected int terminal_settc(EditLine *, int, const Char **); -protected int terminal_gettc(EditLine *, int, char **); -protected int terminal_telltc(EditLine *, int, const Char **); -protected int terminal_echotc(EditLine *, int, const Char **); -protected void terminal_writec(EditLine *, Int); -protected int terminal__putc(EditLine *, Int); -protected void terminal__flush(EditLine *); - -/* - * Easy access macros - */ -#define EL_FLAGS (el)->el_terminal.t_flags - -#define EL_CAN_INSERT (EL_FLAGS & TERM_CAN_INSERT) -#define EL_CAN_DELETE (EL_FLAGS & TERM_CAN_DELETE) -#define EL_CAN_CEOL (EL_FLAGS & TERM_CAN_CEOL) -#define EL_CAN_TAB (EL_FLAGS & TERM_CAN_TAB) -#define EL_CAN_ME (EL_FLAGS & TERM_CAN_ME) -#define EL_CAN_UP (EL_FLAGS & TERM_CAN_UP) -#define EL_HAS_META (EL_FLAGS & TERM_HAS_META) -#define EL_HAS_AUTO_MARGINS (EL_FLAGS & TERM_HAS_AUTO_MARGINS) -#define EL_HAS_MAGIC_MARGINS (EL_FLAGS & TERM_HAS_MAGIC_MARGINS) - -#endif /* _h_el_terminal */ diff --git a/cmd-line-utils/libedit/eln.c b/cmd-line-utils/libedit/eln.c deleted file mode 100644 index f996367115a..00000000000 --- a/cmd-line-utils/libedit/eln.c +++ /dev/null @@ -1,364 +0,0 @@ -/* $NetBSD: eln.c,v 1.13 2011/08/16 16:25:15 christos Exp $ */ - -/*- - * Copyright (c) 2009 The NetBSD Foundation, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#endif /* not lint && not SCCSID */ - -#include "histedit.h" -#include "el.h" -#include "read.h" -#include -#include -#include - -public int -el_getc(EditLine *el, char *cp) -{ - int num_read; - wchar_t wc = 0; - - num_read = el_wgetc (el, &wc); - - if (num_read > 0) - *cp = (char)wc; - return num_read; -} - - -public void -el_push(EditLine *el, const char *str) -{ - /* Using multibyte->wide string decoding works fine under single-byte - * character sets too, and Does The Right Thing. */ - el_wpush(el, ct_decode_string(str, &el->el_lgcyconv)); -} - - -public const char * -el_gets(EditLine *el, int *nread) -{ - const wchar_t *tmp; - - tmp = el_wgets(el, nread); - return ct_encode_string(tmp, &el->el_lgcyconv); -} - - -public int -el_parse(EditLine *el, int argc, const char *argv[]) -{ - int ret; - const wchar_t **wargv; - - wargv = (const wchar_t **) - ct_decode_argv(argc, argv, &el->el_lgcyconv); - if (!wargv) - return -1; - ret = el_wparse(el, argc, wargv); - ct_free_argv(wargv); - - return ret; -} - - -public int -el_set(EditLine *el, int op, ...) -{ - va_list ap; - int ret; - - if (!el) - return -1; - va_start(ap, op); - - switch (op) { - case EL_PROMPT: /* el_pfunc_t */ - case EL_RPROMPT: { - el_pfunc_t p = va_arg(ap, el_pfunc_t); - ret = prompt_set(el, p, 0, op, 0); - break; - } - - case EL_RESIZE: { - el_zfunc_t p = va_arg(ap, el_zfunc_t); - void *arg = va_arg(ap, void *); - ret = ch_resizefun(el, p, arg); - break; - } - - case EL_TERMINAL: /* const char * */ - ret = el_wset(el, op, va_arg(ap, char *)); - break; - - case EL_EDITOR: /* const wchar_t * */ - ret = el_wset(el, op, ct_decode_string(va_arg(ap, char *), - &el->el_lgcyconv)); - break; - - case EL_SIGNAL: /* int */ - case EL_EDITMODE: - case EL_UNBUFFERED: - case EL_PREP_TERM: - ret = el_wset(el, op, va_arg(ap, int)); - break; - - case EL_BIND: /* const char * list -> const wchar_t * list */ - case EL_TELLTC: - case EL_SETTC: - case EL_ECHOTC: - case EL_SETTY: { - const char *argv[20]; - int i; - const wchar_t **wargv; - for (i = 1; i < (int)__arraycount(argv); ++i) - if ((argv[i] = va_arg(ap, char *)) == NULL) - break; - argv[0] = NULL; - wargv = (const wchar_t **) - ct_decode_argv(i, argv, &el->el_lgcyconv); - if (!wargv) { - ret = -1; - goto out; - } - /* - * AFAIK we can't portably pass through our new wargv to - * el_wset(), so we have to reimplement the body of - * el_wset() for these ops. - */ - switch (op) { - case EL_BIND: - wargv[0] = STR("bind"); - ret = map_bind(el, i, wargv); - break; - case EL_TELLTC: - wargv[0] = STR("telltc"); - ret = terminal_telltc(el, i, wargv); - break; - case EL_SETTC: - wargv[0] = STR("settc"); - ret = terminal_settc(el, i, wargv); - break; - case EL_ECHOTC: - wargv[0] = STR("echotc"); - ret = terminal_echotc(el, i, wargv); - break; - case EL_SETTY: - wargv[0] = STR("setty"); - ret = tty_stty(el, i, wargv); - break; - default: - ret = -1; - } - ct_free_argv(wargv); - break; - } - - /* XXX: do we need to change el_func_t too? */ - case EL_ADDFN: { /* const char *, const char *, el_func_t */ - const char *args[2]; - el_func_t func; - wchar_t **wargv; - - args[0] = va_arg(ap, const char *); - args[1] = va_arg(ap, const char *); - func = va_arg(ap, el_func_t); - - wargv = ct_decode_argv(2, args, &el->el_lgcyconv); - if (!wargv) { - ret = -1; - goto out; - } - /* XXX: The two strdups leak. */ - ret = map_addfunc(el, Strdup(wargv[0]), Strdup(wargv[1]), - func); - ct_free_argv(wargv); - break; - } - case EL_HIST: { /* hist_fun_t, const char * */ - hist_fun_t fun = va_arg(ap, hist_fun_t); - void *ptr = va_arg(ap, void *); - ret = hist_set(el, fun, ptr); - el->el_flags |= NARROW_HISTORY; - break; - } - /* XXX: do we need to change el_rfunc_t? */ - case EL_GETCFN: /* el_rfunc_t */ - ret = el_wset(el, op, va_arg(ap, el_rfunc_t)); - el->el_flags |= NARROW_READ; - break; - case EL_CLIENTDATA: /* void * */ - ret = el_wset(el, op, va_arg(ap, void *)); - break; - case EL_SETFP: { /* int, FILE * */ - int what = va_arg(ap, int); - FILE *fp = va_arg(ap, FILE *); - ret = el_wset(el, op, what, fp); - break; - } - case EL_PROMPT_ESC: /* el_pfunc_t, char */ - case EL_RPROMPT_ESC: { - el_pfunc_t p = va_arg(ap, el_pfunc_t); - char c = (char)va_arg(ap, int); - ret = prompt_set(el, p, c, op, 0); - break; - } - default: - ret = -1; - break; - } - -out: - va_end(ap); - return ret; -} - - -public int -el_get(EditLine *el, int op, ...) -{ - va_list ap; - int ret; - - if (!el) - return -1; - - va_start(ap, op); - - switch (op) { - case EL_PROMPT: /* el_pfunc_t * */ - case EL_RPROMPT: { - el_pfunc_t *p = va_arg(ap, el_pfunc_t *); - ret = prompt_get(el, p, 0, op); - break; - } - - case EL_PROMPT_ESC: /* el_pfunc_t *, char **/ - case EL_RPROMPT_ESC: { - el_pfunc_t *p = va_arg(ap, el_pfunc_t *); - char *c = va_arg(ap, char *); - wchar_t wc = 0; - ret = prompt_get(el, p, &wc, op); - *c = (char)wc; - break; - } - - case EL_EDITOR: { - const char **p = va_arg(ap, const char **); - const wchar_t *pw; - ret = el_wget(el, op, &pw); - *p = ct_encode_string(pw, &el->el_lgcyconv); - if (!el->el_lgcyconv.csize) - ret = -1; - break; - } - - case EL_TERMINAL: /* const char ** */ - ret = el_wget(el, op, va_arg(ap, const char **)); - break; - - case EL_SIGNAL: /* int * */ - case EL_EDITMODE: - case EL_UNBUFFERED: - case EL_PREP_TERM: - ret = el_wget(el, op, va_arg(ap, int *)); - break; - - case EL_GETTC: { - char *argv[20]; - static char gettc[] = "gettc"; - int i; - for (i = 1; i < (int)__arraycount(argv); ++i) - if ((argv[i] = va_arg(ap, char *)) == NULL) - break; - argv[0] = gettc; - ret = terminal_gettc(el, i, argv); - break; - } - - /* XXX: do we need to change el_rfunc_t? */ - case EL_GETCFN: /* el_rfunc_t */ - ret = el_wget(el, op, va_arg(ap, el_rfunc_t *)); - break; - - case EL_CLIENTDATA: /* void ** */ - ret = el_wget(el, op, va_arg(ap, void **)); - break; - - case EL_GETFP: { /* int, FILE ** */ - int what = va_arg(ap, int); - FILE **fpp = va_arg(ap, FILE **); - ret = el_wget(el, op, what, fpp); - break; - } - - default: - ret = -1; - break; - } - - va_end(ap); - return ret; -} - - -const LineInfo * -el_line(EditLine *el) -{ - const LineInfoW *winfo = el_wline(el); - LineInfo *info = &el->el_lgcylinfo; - size_t offset; - const Char *p; - - info->buffer = ct_encode_string(winfo->buffer, &el->el_lgcyconv); - - offset = 0; - for (p = winfo->buffer; p < winfo->cursor; p++) - offset += ct_enc_width(*p); - info->cursor = info->buffer + offset; - - offset = 0; - for (p = winfo->buffer; p < winfo->lastchar; p++) - offset += ct_enc_width(*p); - info->lastchar = info->buffer + offset; - - return info; -} - - -int -el_insertstr(EditLine *el, const char *str) -{ - return el_winsertstr(el, ct_decode_string(str, &el->el_lgcyconv)); -} diff --git a/cmd-line-utils/libedit/emacs.c b/cmd-line-utils/libedit/emacs.c deleted file mode 100644 index 554d3970485..00000000000 --- a/cmd-line-utils/libedit/emacs.c +++ /dev/null @@ -1,507 +0,0 @@ -/* $NetBSD: emacs.c,v 1.25 2011/07/29 15:16:33 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)emacs.c 8.1 (Berkeley) 6/4/93"; -#else -#endif -#endif /* not lint && not SCCSID */ - -/* - * emacs.c: Emacs functions - */ -#include "el.h" - -/* em_delete_or_list(): - * Delete character under cursor or list completions if at end of line - * [^D] - */ -protected el_action_t -/*ARGSUSED*/ -em_delete_or_list(EditLine *el, Int c) -{ - - if (el->el_line.cursor == el->el_line.lastchar) { - /* if I'm at the end */ - if (el->el_line.cursor == el->el_line.buffer) { - /* and the beginning */ - terminal_writec(el, c); /* then do an EOF */ - return CC_EOF; - } else { - /* - * Here we could list completions, but it is an - * error right now - */ - terminal_beep(el); - return CC_ERROR; - } - } else { - if (el->el_state.doingarg) - c_delafter(el, el->el_state.argument); - else - c_delafter1(el); - if (el->el_line.cursor > el->el_line.lastchar) - el->el_line.cursor = el->el_line.lastchar; - /* bounds check */ - return CC_REFRESH; - } -} - - -/* em_delete_next_word(): - * Cut from cursor to end of current word - * [M-d] - */ -protected el_action_t -/*ARGSUSED*/ -em_delete_next_word(EditLine *el, Int c __attribute__((__unused__))) -{ - Char *cp, *p, *kp; - - if (el->el_line.cursor == el->el_line.lastchar) - return CC_ERROR; - - cp = c__next_word(el->el_line.cursor, el->el_line.lastchar, - el->el_state.argument, ce__isword); - - for (p = el->el_line.cursor, kp = el->el_chared.c_kill.buf; p < cp; p++) - /* save the text */ - *kp++ = *p; - el->el_chared.c_kill.last = kp; - - c_delafter(el, (int)(cp - el->el_line.cursor)); /* delete after dot */ - if (el->el_line.cursor > el->el_line.lastchar) - el->el_line.cursor = el->el_line.lastchar; - /* bounds check */ - return CC_REFRESH; -} - - -/* em_yank(): - * Paste cut buffer at cursor position - * [^Y] - */ -protected el_action_t -/*ARGSUSED*/ -em_yank(EditLine *el, Int c __attribute__((__unused__))) -{ - Char *kp, *cp; - - if (el->el_chared.c_kill.last == el->el_chared.c_kill.buf) - return CC_NORM; - - if (el->el_line.lastchar + - (el->el_chared.c_kill.last - el->el_chared.c_kill.buf) >= - el->el_line.limit) - return CC_ERROR; - - el->el_chared.c_kill.mark = el->el_line.cursor; - cp = el->el_line.cursor; - - /* open the space, */ - c_insert(el, - (int)(el->el_chared.c_kill.last - el->el_chared.c_kill.buf)); - /* copy the chars */ - for (kp = el->el_chared.c_kill.buf; kp < el->el_chared.c_kill.last; kp++) - *cp++ = *kp; - - /* if an arg, cursor at beginning else cursor at end */ - if (el->el_state.argument == 1) - el->el_line.cursor = cp; - - return CC_REFRESH; -} - - -/* em_kill_line(): - * Cut the entire line and save in cut buffer - * [^U] - */ -protected el_action_t -/*ARGSUSED*/ -em_kill_line(EditLine *el, Int c __attribute__((__unused__))) -{ - Char *kp, *cp; - - cp = el->el_line.buffer; - kp = el->el_chared.c_kill.buf; - while (cp < el->el_line.lastchar) - *kp++ = *cp++; /* copy it */ - el->el_chared.c_kill.last = kp; - /* zap! -- delete all of it */ - el->el_line.lastchar = el->el_line.buffer; - el->el_line.cursor = el->el_line.buffer; - return CC_REFRESH; -} - - -/* em_kill_region(): - * Cut area between mark and cursor and save in cut buffer - * [^W] - */ -protected el_action_t -/*ARGSUSED*/ -em_kill_region(EditLine *el, Int c __attribute__((__unused__))) -{ - Char *kp, *cp; - - if (!el->el_chared.c_kill.mark) - return CC_ERROR; - - if (el->el_chared.c_kill.mark > el->el_line.cursor) { - cp = el->el_line.cursor; - kp = el->el_chared.c_kill.buf; - while (cp < el->el_chared.c_kill.mark) - *kp++ = *cp++; /* copy it */ - el->el_chared.c_kill.last = kp; - c_delafter(el, (int)(cp - el->el_line.cursor)); - } else { /* mark is before cursor */ - cp = el->el_chared.c_kill.mark; - kp = el->el_chared.c_kill.buf; - while (cp < el->el_line.cursor) - *kp++ = *cp++; /* copy it */ - el->el_chared.c_kill.last = kp; - c_delbefore(el, (int)(cp - el->el_chared.c_kill.mark)); - el->el_line.cursor = el->el_chared.c_kill.mark; - } - return CC_REFRESH; -} - - -/* em_copy_region(): - * Copy area between mark and cursor to cut buffer - * [M-W] - */ -protected el_action_t -/*ARGSUSED*/ -em_copy_region(EditLine *el, Int c __attribute__((__unused__))) -{ - Char *kp, *cp; - - if (!el->el_chared.c_kill.mark) - return CC_ERROR; - - if (el->el_chared.c_kill.mark > el->el_line.cursor) { - cp = el->el_line.cursor; - kp = el->el_chared.c_kill.buf; - while (cp < el->el_chared.c_kill.mark) - *kp++ = *cp++; /* copy it */ - el->el_chared.c_kill.last = kp; - } else { - cp = el->el_chared.c_kill.mark; - kp = el->el_chared.c_kill.buf; - while (cp < el->el_line.cursor) - *kp++ = *cp++; /* copy it */ - el->el_chared.c_kill.last = kp; - } - return CC_NORM; -} - - -/* em_gosmacs_transpose(): - * Exchange the two characters before the cursor - * Gosling emacs transpose chars [^T] - */ -protected el_action_t -em_gosmacs_transpose(EditLine *el, Int c) -{ - - if (el->el_line.cursor > &el->el_line.buffer[1]) { - /* must have at least two chars entered */ - c = el->el_line.cursor[-2]; - el->el_line.cursor[-2] = el->el_line.cursor[-1]; - el->el_line.cursor[-1] = c; - return CC_REFRESH; - } else - return CC_ERROR; -} - - -/* em_next_word(): - * Move next to end of current word - * [M-f] - */ -protected el_action_t -/*ARGSUSED*/ -em_next_word(EditLine *el, Int c __attribute__((__unused__))) -{ - if (el->el_line.cursor == el->el_line.lastchar) - return CC_ERROR; - - el->el_line.cursor = c__next_word(el->el_line.cursor, - el->el_line.lastchar, - el->el_state.argument, - ce__isword); - - if (el->el_map.type == MAP_VI) - if (el->el_chared.c_vcmd.action != NOP) { - cv_delfini(el); - return CC_REFRESH; - } - return CC_CURSOR; -} - - -/* em_upper_case(): - * Uppercase the characters from cursor to end of current word - * [M-u] - */ -protected el_action_t -/*ARGSUSED*/ -em_upper_case(EditLine *el, Int c __attribute__((__unused__))) -{ - Char *cp, *ep; - - ep = c__next_word(el->el_line.cursor, el->el_line.lastchar, - el->el_state.argument, ce__isword); - - for (cp = el->el_line.cursor; cp < ep; cp++) - if (Islower(*cp)) - *cp = Toupper(*cp); - - el->el_line.cursor = ep; - if (el->el_line.cursor > el->el_line.lastchar) - el->el_line.cursor = el->el_line.lastchar; - return CC_REFRESH; -} - - -/* em_capitol_case(): - * Capitalize the characters from cursor to end of current word - * [M-c] - */ -protected el_action_t -/*ARGSUSED*/ -em_capitol_case(EditLine *el, Int c __attribute__((__unused__))) -{ - Char *cp, *ep; - - ep = c__next_word(el->el_line.cursor, el->el_line.lastchar, - el->el_state.argument, ce__isword); - - for (cp = el->el_line.cursor; cp < ep; cp++) { - if (Isalpha(*cp)) { - if (Islower(*cp)) - *cp = Toupper(*cp); - cp++; - break; - } - } - for (; cp < ep; cp++) - if (Isupper(*cp)) - *cp = Tolower(*cp); - - el->el_line.cursor = ep; - if (el->el_line.cursor > el->el_line.lastchar) - el->el_line.cursor = el->el_line.lastchar; - return CC_REFRESH; -} - - -/* em_lower_case(): - * Lowercase the characters from cursor to end of current word - * [M-l] - */ -protected el_action_t -/*ARGSUSED*/ -em_lower_case(EditLine *el, Int c __attribute__((__unused__))) -{ - Char *cp, *ep; - - ep = c__next_word(el->el_line.cursor, el->el_line.lastchar, - el->el_state.argument, ce__isword); - - for (cp = el->el_line.cursor; cp < ep; cp++) - if (Isupper(*cp)) - *cp = Tolower(*cp); - - el->el_line.cursor = ep; - if (el->el_line.cursor > el->el_line.lastchar) - el->el_line.cursor = el->el_line.lastchar; - return CC_REFRESH; -} - - -/* em_set_mark(): - * Set the mark at cursor - * [^@] - */ -protected el_action_t -/*ARGSUSED*/ -em_set_mark(EditLine *el, Int c __attribute__((__unused__))) -{ - - el->el_chared.c_kill.mark = el->el_line.cursor; - return CC_NORM; -} - - -/* em_exchange_mark(): - * Exchange the cursor and mark - * [^X^X] - */ -protected el_action_t -/*ARGSUSED*/ -em_exchange_mark(EditLine *el, Int c __attribute__((__unused__))) -{ - Char *cp; - - cp = el->el_line.cursor; - el->el_line.cursor = el->el_chared.c_kill.mark; - el->el_chared.c_kill.mark = cp; - return CC_CURSOR; -} - - -/* em_universal_argument(): - * Universal argument (argument times 4) - * [^U] - */ -protected el_action_t -/*ARGSUSED*/ -em_universal_argument(EditLine *el, Int c __attribute__((__unused__))) -{ /* multiply current argument by 4 */ - - if (el->el_state.argument > 1000000) - return CC_ERROR; - el->el_state.doingarg = 1; - el->el_state.argument *= 4; - return CC_ARGHACK; -} - - -/* em_meta_next(): - * Add 8th bit to next character typed - * [] - */ -protected el_action_t -/*ARGSUSED*/ -em_meta_next(EditLine *el, Int c __attribute__((__unused__))) -{ - - el->el_state.metanext = 1; - return CC_ARGHACK; -} - - -/* em_toggle_overwrite(): - * Switch from insert to overwrite mode or vice versa - */ -protected el_action_t -/*ARGSUSED*/ -em_toggle_overwrite(EditLine *el, Int c __attribute__((__unused__))) -{ - - el->el_state.inputmode = (el->el_state.inputmode == MODE_INSERT) ? - MODE_REPLACE : MODE_INSERT; - return CC_NORM; -} - - -/* em_copy_prev_word(): - * Copy current word to cursor - */ -protected el_action_t -/*ARGSUSED*/ -em_copy_prev_word(EditLine *el, Int c __attribute__((__unused__))) -{ - Char *cp, *oldc, *dp; - - if (el->el_line.cursor == el->el_line.buffer) - return CC_ERROR; - - oldc = el->el_line.cursor; - /* does a bounds check */ - cp = c__prev_word(el->el_line.cursor, el->el_line.buffer, - el->el_state.argument, ce__isword); - - c_insert(el, (int)(oldc - cp)); - for (dp = oldc; cp < oldc && dp < el->el_line.lastchar; cp++) - *dp++ = *cp; - - el->el_line.cursor = dp;/* put cursor at end */ - - return CC_REFRESH; -} - - -/* em_inc_search_next(): - * Emacs incremental next search - */ -protected el_action_t -/*ARGSUSED*/ -em_inc_search_next(EditLine *el, Int c __attribute__((__unused__))) -{ - - el->el_search.patlen = 0; - return ce_inc_search(el, ED_SEARCH_NEXT_HISTORY); -} - - -/* em_inc_search_prev(): - * Emacs incremental reverse search - */ -protected el_action_t -/*ARGSUSED*/ -em_inc_search_prev(EditLine *el, Int c __attribute__((__unused__))) -{ - - el->el_search.patlen = 0; - return ce_inc_search(el, ED_SEARCH_PREV_HISTORY); -} - - -/* em_delete_prev_char(): - * Delete the character to the left of the cursor - * [^?] - */ -protected el_action_t -/*ARGSUSED*/ -em_delete_prev_char(EditLine *el, Int c __attribute__((__unused__))) -{ - - if (el->el_line.cursor <= el->el_line.buffer) - return CC_ERROR; - - if (el->el_state.doingarg) - c_delbefore(el, el->el_state.argument); - else - c_delbefore1(el); - el->el_line.cursor -= el->el_state.argument; - if (el->el_line.cursor < el->el_line.buffer) - el->el_line.cursor = el->el_line.buffer; - return CC_REFRESH; -} diff --git a/cmd-line-utils/libedit/filecomplete.c b/cmd-line-utils/libedit/filecomplete.c deleted file mode 100644 index b67b54510bf..00000000000 --- a/cmd-line-utils/libedit/filecomplete.c +++ /dev/null @@ -1,612 +0,0 @@ -/* $NetBSD: filecomplete.c,v 1.31 2011/09/16 16:13:16 plunky Exp $ */ - -/*- - * Copyright (c) 1997 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Jaromir Dolecek. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* AIX requires this to be the first thing in the file. */ -#if defined (_AIX) && !defined (__GNUC__) - #pragma alloca -#endif - -#include "config.h" - -/* XXXMYSQL */ -#ifdef __GNUC__ -# undef alloca -# define alloca(n) __builtin_alloca (n) -#else -# ifdef HAVE_ALLOCA_H -# include -# else -# ifndef _AIX -extern char *alloca (); -# endif -# endif -#endif - -#if !defined(lint) && !defined(SCCSID) -#endif /* not lint && not SCCSID */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_VIS_H -#include -#else -#include "np/vis.h" -#endif -#ifdef HAVE_ALLOCA_H -#include -#endif -#include "el.h" -#include "fcns.h" /* for EL_NUM_FCNS */ -#include "histedit.h" -#include "filecomplete.h" - -static const Char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', - '$', '>', '<', '=', ';', '|', '&', '{', '(', '\0' }; - - -/********************************/ -/* completion functions */ - -/* - * does tilde expansion of strings of type ``~user/foo'' - * if ``user'' isn't valid user name or ``txt'' doesn't start - * w/ '~', returns pointer to strdup()ed copy of ``txt'' - * - * it's callers's responsibility to free() returned string - */ -char * -fn_tilde_expand(const char *txt) -{ -#if defined(HAVE_GETPW_R_POSIX) || defined(HAVE_GETPW_R_DRAFT) - struct passwd pwres; - char pwbuf[1024]; -#endif - struct passwd *pass; - char *temp; - size_t len = 0; - - if (txt[0] != '~') - return strdup(txt); - - temp = strchr(txt + 1, '/'); - if (temp == NULL) { - temp = strdup(txt + 1); - if (temp == NULL) - return NULL; - } else { - /* text until string after slash */ - len = (size_t)(temp - txt + 1); - temp = el_malloc(len * sizeof(*temp)); - if (temp == NULL) - return NULL; - (void)strncpy(temp, txt + 1, len - 2); - temp[len - 2] = '\0'; - } - if (temp[0] == 0) { -#ifdef HAVE_GETPW_R_POSIX - if (getpwuid_r(getuid(), &pwres, pwbuf, sizeof(pwbuf), - &pass) != 0) - pass = NULL; -#elif HAVE_GETPW_R_DRAFT - pass = getpwuid_r(getuid(), &pwres, pwbuf, sizeof(pwbuf)); -#else - pass = getpwuid(getuid()); -#endif - } else { -#ifdef HAVE_GETPW_R_POSIX - if (getpwnam_r(temp, &pwres, pwbuf, sizeof(pwbuf), &pass) != 0) - pass = NULL; -#elif HAVE_GETPW_R_DRAFT - pass = getpwnam_r(temp, &pwres, pwbuf, sizeof(pwbuf)); -#else - pass = getpwnam(temp); -#endif - } - el_free(temp); /* value no more needed */ - if (pass == NULL) - return strdup(txt); - - /* update pointer txt to point at string immedially following */ - /* first slash */ - txt += len; - - len = strlen(pass->pw_dir) + 1 + strlen(txt) + 1; - temp = el_malloc(len * sizeof(*temp)); - if (temp == NULL) - return NULL; - (void)snprintf(temp, len, "%s/%s", pass->pw_dir, txt); - - return temp; -} - - -/* - * return first found file name starting by the ``text'' or NULL if no - * such file can be found - * value of ``state'' is ignored - * - * it's caller's responsibility to free returned string - */ -char * -fn_filename_completion_function(const char *text, int state) -{ - static DIR *dir = NULL; - static char *filename = NULL, *dirname = NULL, *dirpath = NULL; - static size_t filename_len = 0; - struct dirent *entry; - char *temp; - size_t len; - - if (state == 0 || dir == NULL) { - temp = strrchr(text, '/'); - if (temp) { - char *nptr; - temp++; - nptr = el_realloc(filename, (strlen(temp) + 1) * - sizeof(*nptr)); - if (nptr == NULL) { - el_free(filename); - filename = NULL; - return NULL; - } - filename = nptr; - (void)strcpy(filename, temp); - len = (size_t)(temp - text); /* including last slash */ - - nptr = el_realloc(dirname, (len + 1) * - sizeof(*nptr)); - if (nptr == NULL) { - el_free(dirname); - dirname = NULL; - return NULL; - } - dirname = nptr; - (void)strncpy(dirname, text, len); - dirname[len] = '\0'; - } else { - el_free(filename); - if (*text == 0) - filename = NULL; - else { - filename = strdup(text); - if (filename == NULL) - return NULL; - } - el_free(dirname); - dirname = NULL; - } - - if (dir != NULL) { - (void)closedir(dir); - dir = NULL; - } - - /* support for ``~user'' syntax */ - - el_free(dirpath); - dirpath = NULL; - if (dirname == NULL) { - if ((dirname = strdup("")) == NULL) - return NULL; - dirpath = strdup("./"); - } else if (*dirname == '~') - dirpath = fn_tilde_expand(dirname); - else - dirpath = strdup(dirname); - - if (dirpath == NULL) - return NULL; - - dir = opendir(dirpath); - if (!dir) - return NULL; /* cannot open the directory */ - - /* will be used in cycle */ - filename_len = filename ? strlen(filename) : 0; - } - - /* find the match */ - while ((entry = readdir(dir)) != NULL) { - /* skip . and .. */ - if (entry->d_name[0] == '.' && (!entry->d_name[1] - || (entry->d_name[1] == '.' && !entry->d_name[2]))) - continue; - if (filename_len == 0) - break; - /* otherwise, get first entry where first */ - /* filename_len characters are equal */ - if (entry->d_name[0] == filename[0] -#if HAVE_STRUCT_DIRENT_D_NAMLEN - && entry->d_namlen >= filename_len -#else - && strlen(entry->d_name) >= filename_len -#endif - && strncmp(entry->d_name, filename, - filename_len) == 0) - break; - } - - if (entry) { /* match found */ - -#if HAVE_STRUCT_DIRENT_D_NAMLEN - len = entry->d_namlen; -#else - len = strlen(entry->d_name); -#endif - - len = strlen(dirname) + len + 1; - temp = el_malloc(len * sizeof(*temp)); - if (temp == NULL) - return NULL; - (void)snprintf(temp, len, "%s%s", dirname, entry->d_name); - } else { - (void)closedir(dir); - dir = NULL; - temp = NULL; - } - - return temp; -} - - -static const char * -append_char_function(const char *name) -{ - struct stat stbuf; - char *expname = *name == '~' ? fn_tilde_expand(name) : NULL; - const char *rs = " "; - - if (stat(expname ? expname : name, &stbuf) == -1) - goto out; - if (S_ISDIR(stbuf.st_mode)) - rs = "/"; -out: - if (expname) - el_free(expname); - return rs; -} -/* - * returns list of completions for text given - * non-static for readline. - */ -char ** completion_matches(const char *, char *(*)(const char *, int)); -char ** -completion_matches(const char *text, char *(*genfunc)(const char *, int)) -{ - char **match_list = NULL, *retstr, *prevstr; - size_t match_list_len, max_equal, which, i; - size_t matches; - - matches = 0; - match_list_len = 1; - while ((retstr = (*genfunc) (text, (int)matches)) != NULL) { - /* allow for list terminator here */ - if (matches + 3 >= match_list_len) { - char **nmatch_list; - while (matches + 3 >= match_list_len) - match_list_len <<= 1; - nmatch_list = el_realloc(match_list, - match_list_len * sizeof(*nmatch_list)); - if (nmatch_list == NULL) { - el_free(match_list); - return NULL; - } - match_list = nmatch_list; - - } - match_list[++matches] = retstr; - } - - if (!match_list) - return NULL; /* nothing found */ - - /* find least denominator and insert it to match_list[0] */ - which = 2; - prevstr = match_list[1]; - max_equal = strlen(prevstr); - for (; which <= matches; which++) { - for (i = 0; i < max_equal && - prevstr[i] == match_list[which][i]; i++) - continue; - max_equal = i; - } - - retstr = el_malloc((max_equal + 1) * sizeof(*retstr)); - if (retstr == NULL) { - el_free(match_list); - return NULL; - } - (void)strncpy(retstr, match_list[1], max_equal); - retstr[max_equal] = '\0'; - match_list[0] = retstr; - - /* add NULL as last pointer to the array */ - match_list[matches + 1] = NULL; - - return match_list; -} - -/* - * Sort function for qsort(). Just wrapper around strcasecmp(). - */ -static int -_fn_qsort_string_compare(const void *i1, const void *i2) -{ - const char *s1 = ((const char * const *)i1)[0]; - const char *s2 = ((const char * const *)i2)[0]; - - return strcasecmp(s1, s2); -} - -/* - * Display list of strings in columnar format on readline's output stream. - * 'matches' is list of strings, 'num' is number of strings in 'matches', - * 'width' is maximum length of string in 'matches'. - * - * matches[0] is not one of the match strings, but it is counted in - * num, so the strings are matches[1] *through* matches[num-1]. - */ -void -fn_display_match_list (EditLine *el, char **matches, size_t num, size_t width) -{ - size_t line, lines, col, cols, thisguy; - int screenwidth = el->el_terminal.t_size.h; - - /* Ignore matches[0]. Avoid 1-based array logic below. */ - matches++; - num--; - - /* - * Find out how many entries can be put on one line; count - * with one space between strings the same way it's printed. - */ - cols = (size_t)screenwidth / (width + 1); - if (cols == 0) - cols = 1; - - /* how many lines of output, rounded up */ - lines = (num + cols - 1) / cols; - - /* Sort the items. */ - qsort(matches, num, sizeof(char *), _fn_qsort_string_compare); - - /* - * On the ith line print elements i, i+lines, i+lines*2, etc. - */ - for (line = 0; line < lines; line++) { - for (col = 0; col < cols; col++) { - thisguy = line + col * lines; - if (thisguy >= num) - break; - (void)fprintf(el->el_outfile, "%s%-*s", - col == 0 ? "" : " ", (int)width, matches[thisguy]); - } - (void)fprintf(el->el_outfile, "\n"); - } -} - -/* - * Complete the word at or before point, - * 'what_to_do' says what to do with the completion. - * \t means do standard completion. - * `?' means list the possible completions. - * `*' means insert all of the possible completions. - * `!' means to do standard completion, and list all possible completions if - * there is more than one. - * - * Note: '*' support is not implemented - * '!' could never be invoked - */ -int -fn_complete(EditLine *el, - char *(*complet_func)(const char *, int), - char **(*attempted_completion_function)(const char *, int, int), - const Char *word_break, const Char *special_prefixes, - const char *(*app_func)(const char *), size_t query_items, - int *completion_type, int *over, int *point, int *end) -{ - const TYPE(LineInfo) *li; - Char *temp; - char **matches; - const Char *ctemp; - size_t len; - int what_to_do = '\t'; - int retval = CC_NORM; - - if (el->el_state.lastcmd == el->el_state.thiscmd) - what_to_do = '?'; - - /* readline's rl_complete() has to be told what we did... */ - if (completion_type != NULL) - *completion_type = what_to_do; - - if (!complet_func) - complet_func = fn_filename_completion_function; - if (!app_func) - app_func = append_char_function; - - /* We now look backwards for the start of a filename/variable word */ - li = FUN(el,line)(el); - ctemp = li->cursor; - while (ctemp > li->buffer - && !Strchr(word_break, ctemp[-1]) - && (!special_prefixes || !Strchr(special_prefixes, ctemp[-1]) ) ) - ctemp--; - - len = (size_t)(li->cursor - ctemp); -#if defined(__SSP__) || defined(__SSP_ALL__) - temp = el_malloc((len + 1) * sizeof(*temp)); -#else - temp = alloca((len + 1) * sizeof(*temp)); -#endif - (void)Strncpy(temp, ctemp, len); - temp[len] = '\0'; - - /* these can be used by function called in completion_matches() */ - /* or (*attempted_completion_function)() */ - if (point != 0) - *point = (int)(li->cursor - li->buffer); - if (end != NULL) - *end = (int)(li->lastchar - li->buffer); - - if (attempted_completion_function) { - int cur_off = (int)(li->cursor - li->buffer); - matches = (*attempted_completion_function)( - ct_encode_string(temp, &el->el_scratch), - cur_off - (int)len, cur_off); - } else - matches = 0; - if (!attempted_completion_function || - (over != NULL && !*over && !matches)) - matches = completion_matches( - ct_encode_string(temp, &el->el_scratch), complet_func); - - if (over != NULL) - *over = 0; - - if (matches) { - int i; - size_t matches_num, maxlen, match_len, match_display=1; - - retval = CC_REFRESH; - /* - * Only replace the completed string with common part of - * possible matches if there is possible completion. - */ - if (matches[0][0] != '\0') { - el_deletestr(el, (int) len); - FUN(el,insertstr)(el, - ct_decode_string(matches[0], &el->el_scratch)); - } - - if (what_to_do == '?') - goto display_matches; - - if (matches[2] == NULL && strcmp(matches[0], matches[1]) == 0) { - /* - * We found exact match. Add a space after - * it, unless we do filename completion and the - * object is a directory. - */ - FUN(el,insertstr)(el, - ct_decode_string((*app_func)(matches[0]), - &el->el_scratch)); - } else if (what_to_do == '!') { - display_matches: - /* - * More than one match and requested to list possible - * matches. - */ - - for(i = 1, maxlen = 0; matches[i]; i++) { - match_len = strlen(matches[i]); - if (match_len > maxlen) - maxlen = match_len; - } - /* matches[1] through matches[i-1] are available */ - matches_num = (size_t)(i - 1); - - /* newline to get on next line from command line */ - (void)fprintf(el->el_outfile, "\n"); - - /* - * If there are too many items, ask user for display - * confirmation. - */ - if (matches_num > query_items) { - (void)fprintf(el->el_outfile, - "Display all %zu possibilities? (y or n) ", - matches_num); - (void)fflush(el->el_outfile); - if (getc(stdin) != 'y') - match_display = 0; - (void)fprintf(el->el_outfile, "\n"); - } - - if (match_display) { - /* - * Interface of this function requires the - * strings be matches[1..num-1] for compat. - * We have matches_num strings not counting - * the prefix in matches[0], so we need to - * add 1 to matches_num for the call. - */ - fn_display_match_list(el, matches, - matches_num+1, maxlen); - } - retval = CC_REDISPLAY; - } else if (matches[0][0]) { - /* - * There was some common match, but the name was - * not complete enough. Next tab will print possible - * completions. - */ - el_beep(el); - } else { - /* lcd is not a valid object - further specification */ - /* is needed */ - el_beep(el); - retval = CC_NORM; - } - - /* free elements of array and the array itself */ - for (i = 0; matches[i]; i++) - el_free(matches[i]); - el_free(matches); - matches = NULL; - } -#if defined(__SSP__) || defined(__SSP_ALL__) - el_free(temp); -#endif - return retval; -} - -/* - * el-compatible wrapper around rl_complete; needed for key binding - */ -/* ARGSUSED */ -unsigned char -_el_fn_complete(EditLine *el, int ch __attribute__((__unused__))) -{ - return (unsigned char)fn_complete(el, NULL, NULL, - break_chars, NULL, NULL, (size_t)100, - NULL, NULL, NULL, NULL); -} diff --git a/cmd-line-utils/libedit/filecomplete.h b/cmd-line-utils/libedit/filecomplete.h deleted file mode 100644 index 971e6e05939..00000000000 --- a/cmd-line-utils/libedit/filecomplete.h +++ /dev/null @@ -1,44 +0,0 @@ -/* $NetBSD: filecomplete.h,v 1.9 2009/12/30 22:37:40 christos Exp $ */ - -/*- - * Copyright (c) 1997 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Jaromir Dolecek. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef _FILECOMPLETE_H_ -#define _FILECOMPLETE_H_ - -int fn_complete(EditLine *, - char *(*)(const char *, int), - char **(*)(const char *, int, int), - const Char *, const Char *, const char *(*)(const char *), size_t, - int *, int *, int *, int *); - -void fn_display_match_list(EditLine *, char **, size_t, size_t); -char *fn_tilde_expand(const char *); -char *fn_filename_completion_function(const char *, int); - -#endif diff --git a/cmd-line-utils/libedit/hist.c b/cmd-line-utils/libedit/hist.c deleted file mode 100644 index d24f5e7ff53..00000000000 --- a/cmd-line-utils/libedit/hist.c +++ /dev/null @@ -1,222 +0,0 @@ -/* $NetBSD: hist.c,v 1.20 2011/07/29 15:16:33 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)hist.c 8.1 (Berkeley) 6/4/93"; -#else -#endif -#endif /* not lint && not SCCSID */ - -/* - * hist.c: History access functions - */ -#include -#include "el.h" - -/* hist_init(): - * Initialization function. - */ -protected int -hist_init(EditLine *el) -{ - - el->el_history.fun = NULL; - el->el_history.ref = NULL; - el->el_history.buf = el_malloc(EL_BUFSIZ * sizeof(*el->el_history.buf)); - el->el_history.sz = EL_BUFSIZ; - if (el->el_history.buf == NULL) - return -1; - el->el_history.last = el->el_history.buf; - return 0; -} - - -/* hist_end(): - * clean up history; - */ -protected void -hist_end(EditLine *el) -{ - - el_free(el->el_history.buf); - el->el_history.buf = NULL; -} - - -/* hist_set(): - * Set new history interface - */ -protected int -hist_set(EditLine *el, hist_fun_t fun, void *ptr) -{ - - el->el_history.ref = ptr; - el->el_history.fun = fun; - return 0; -} - - -/* hist_get(): - * Get a history line and update it in the buffer. - * eventno tells us the event to get. - */ -protected el_action_t -hist_get(EditLine *el) -{ - const Char *hp; - int h; - - if (el->el_history.eventno == 0) { /* if really the current line */ - (void) Strncpy(el->el_line.buffer, el->el_history.buf, - el->el_history.sz); - el->el_line.lastchar = el->el_line.buffer + - (el->el_history.last - el->el_history.buf); - -#ifdef KSHVI - if (el->el_map.type == MAP_VI) - el->el_line.cursor = el->el_line.buffer; - else -#endif /* KSHVI */ - el->el_line.cursor = el->el_line.lastchar; - - return CC_REFRESH; - } - if (el->el_history.ref == NULL) - return CC_ERROR; - - hp = HIST_FIRST(el); - - if (hp == NULL) - return CC_ERROR; - - for (h = 1; h < el->el_history.eventno; h++) - if ((hp = HIST_NEXT(el)) == NULL) { - el->el_history.eventno = h; - return CC_ERROR; - } - (void) Strncpy(el->el_line.buffer, hp, - (size_t)(el->el_line.limit - el->el_line.buffer)); - el->el_line.buffer[el->el_line.limit - el->el_line.buffer - 1] = '\0'; - el->el_line.lastchar = el->el_line.buffer + Strlen(el->el_line.buffer); - - if (el->el_line.lastchar > el->el_line.buffer - && el->el_line.lastchar[-1] == '\n') - el->el_line.lastchar--; - if (el->el_line.lastchar > el->el_line.buffer - && el->el_line.lastchar[-1] == ' ') - el->el_line.lastchar--; -#ifdef KSHVI - if (el->el_map.type == MAP_VI) - el->el_line.cursor = el->el_line.buffer; - else -#endif /* KSHVI */ - el->el_line.cursor = el->el_line.lastchar; - - return CC_REFRESH; -} - - -/* hist_command() - * process a history command - */ -protected int -hist_command(EditLine *el, int argc, const Char **argv) -{ - const Char *str; - int num; - TYPE(HistEvent) ev; - - if (el->el_history.ref == NULL) - return -1; - - if (argc == 1 || Strcmp(argv[1], STR("list")) == 0) { - /* List history entries */ - - for (str = HIST_LAST(el); str != NULL; str = HIST_PREV(el)) - (void) fprintf(el->el_outfile, "%d %s", - el->el_history.ev.num, ct_encode_string(str, &el->el_scratch)); - return 0; - } - - if (argc != 3) - return -1; - - num = (int)Strtol(argv[2], NULL, 0); - - if (Strcmp(argv[1], STR("size")) == 0) - return FUNW(history)(el->el_history.ref, &ev, H_SETSIZE, num); - - if (Strcmp(argv[1], STR("unique")) == 0) - return FUNW(history)(el->el_history.ref, &ev, H_SETUNIQUE, num); - - return -1; -} - -/* hist_enlargebuf() - * Enlarge history buffer to specified value. Called from el_enlargebufs(). - * Return 0 for failure, 1 for success. - */ -protected int -/*ARGSUSED*/ -hist_enlargebuf(EditLine *el, size_t oldsz, size_t newsz) -{ - Char *newbuf; - - newbuf = el_realloc(el->el_history.buf, newsz * sizeof(*newbuf)); - if (!newbuf) - return 0; - - (void) memset(&newbuf[oldsz], '\0', (newsz - oldsz) * sizeof(*newbuf)); - - el->el_history.last = newbuf + - (el->el_history.last - el->el_history.buf); - el->el_history.buf = newbuf; - el->el_history.sz = newsz; - - return 1; -} - -#ifdef WIDECHAR -protected wchar_t * -hist_convert(EditLine *el, int fn, void *arg) -{ - HistEventW ev; - if ((*(el)->el_history.fun)((el)->el_history.ref, &ev, fn, arg) == -1) - return NULL; - return ct_decode_string((const char *)(const void *)ev.str, - &el->el_scratch); -} -#endif diff --git a/cmd-line-utils/libedit/hist.h b/cmd-line-utils/libedit/hist.h deleted file mode 100644 index a63be499dbd..00000000000 --- a/cmd-line-utils/libedit/hist.h +++ /dev/null @@ -1,87 +0,0 @@ -/* $NetBSD: hist.h,v 1.13 2011/07/28 20:50:55 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)hist.h 8.1 (Berkeley) 6/4/93 - */ - -/* - * el.hist.c: History functions - */ -#ifndef _h_el_hist -#define _h_el_hist - -#include "histedit.h" - -typedef int (*hist_fun_t)(void *, TYPE(HistEvent) *, int, ...); - -typedef struct el_history_t { - Char *buf; /* The history buffer */ - size_t sz; /* Size of history buffer */ - Char *last; /* The last character */ - int eventno; /* Event we are looking for */ - void * ref; /* Argument for history fcns */ - hist_fun_t fun; /* Event access */ - TYPE(HistEvent) ev; /* Event cookie */ -} el_history_t; - -#define HIST_FUN_INTERNAL(el, fn, arg) \ - ((((*(el)->el_history.fun) ((el)->el_history.ref, &(el)->el_history.ev, \ - fn, arg)) == -1) ? NULL : (el)->el_history.ev.str) -#ifdef WIDECHAR -#define HIST_FUN(el, fn, arg) \ - (((el)->el_flags & NARROW_HISTORY) ? hist_convert(el, fn, arg) : \ - HIST_FUN_INTERNAL(el, fn, arg)) -#else -#define HIST_FUN(el, fn, arg) HIST_FUN_INTERNAL(el, fn, arg) -#endif - - -#define HIST_NEXT(el) HIST_FUN(el, H_NEXT, NULL) -#define HIST_FIRST(el) HIST_FUN(el, H_FIRST, NULL) -#define HIST_LAST(el) HIST_FUN(el, H_LAST, NULL) -#define HIST_PREV(el) HIST_FUN(el, H_PREV, NULL) -#define HIST_SET(el, num) HIST_FUN(el, H_SET, num) -#define HIST_LOAD(el, fname) HIST_FUN(el, H_LOAD fname) -#define HIST_SAVE(el, fname) HIST_FUN(el, H_SAVE fname) - -protected int hist_init(EditLine *); -protected void hist_end(EditLine *); -protected el_action_t hist_get(EditLine *); -protected int hist_set(EditLine *, hist_fun_t, void *); -protected int hist_command(EditLine *, int, const Char **); -protected int hist_enlargebuf(EditLine *, size_t, size_t); -#ifdef WIDECHAR -protected wchar_t *hist_convert(EditLine *, int, void *); -#endif - -#endif /* _h_el_hist */ diff --git a/cmd-line-utils/libedit/histedit.h b/cmd-line-utils/libedit/histedit.h deleted file mode 100644 index 523d27b0be2..00000000000 --- a/cmd-line-utils/libedit/histedit.h +++ /dev/null @@ -1,315 +0,0 @@ -/* $NetBSD: histedit.h,v 1.48 2011/07/28 20:50:55 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)histedit.h 8.2 (Berkeley) 1/3/94 - */ - -/* - * histedit.h: Line editor and history interface. - */ -#ifndef _HISTEDIT_H_ -#define _HISTEDIT_H_ - -#define LIBEDIT_MAJOR 2 -#define LIBEDIT_MINOR 11 - -/* XXXMYSQL : stdint.h might not be available on older Solaris platforms. */ -#if defined(__sun) || defined(__sun__) -#include -#else -#include -#endif - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * ==== Editing ==== - */ - -typedef struct editline EditLine; - -/* - * For user-defined function interface - */ -typedef struct lineinfo { - const char *buffer; - const char *cursor; - const char *lastchar; -} LineInfo; - -/* - * EditLine editor function return codes. - * For user-defined function interface - */ -#define CC_NORM 0 -#define CC_NEWLINE 1 -#define CC_EOF 2 -#define CC_ARGHACK 3 -#define CC_REFRESH 4 -#define CC_CURSOR 5 -#define CC_ERROR 6 -#define CC_FATAL 7 -#define CC_REDISPLAY 8 -#define CC_REFRESH_BEEP 9 - -/* - * Initialization, cleanup, and resetting - */ -EditLine *el_init(const char *, FILE *, FILE *, FILE *); -void el_end(EditLine *); -void el_reset(EditLine *); - -/* - * Get a line, a character or push a string back in the input queue - */ -const char *el_gets(EditLine *, int *); -int el_getc(EditLine *, char *); -void el_push(EditLine *, const char *); - -/* - * Beep! - */ -void el_beep(EditLine *); - -/* - * High level function internals control - * Parses argc, argv array and executes builtin editline commands - */ -int el_parse(EditLine *, int, const char **); - -/* - * Low level editline access functions - */ -int el_set(EditLine *, int, ...); -int el_get(EditLine *, int, ...); -unsigned char _el_fn_complete(EditLine *, int); - -/* - * el_set/el_get parameters - * - * When using el_wset/el_wget (as opposed to el_set/el_get): - * Char is wchar_t, otherwise it is char. - * prompt_func is el_wpfunc_t, otherwise it is el_pfunc_t . - - * Prompt function prototypes are: - * typedef char *(*el_pfunct_t) (EditLine *); - * typedef wchar_t *(*el_wpfunct_t) (EditLine *); - * - * For operations that support set or set/get, the argument types listed are for - * the "set" operation. For "get", each listed type must be a pointer. - * E.g. EL_EDITMODE takes an int when set, but an int* when get. - * - * Operations that only support "get" have the correct argument types listed. - */ -#define EL_PROMPT 0 /* , prompt_func); set/get */ -#define EL_TERMINAL 1 /* , const char *); set/get */ -#define EL_EDITOR 2 /* , const Char *); set/get */ -#define EL_SIGNAL 3 /* , int); set/get */ -#define EL_BIND 4 /* , const Char *, ..., NULL); set */ -#define EL_TELLTC 5 /* , const Char *, ..., NULL); set */ -#define EL_SETTC 6 /* , const Char *, ..., NULL); set */ -#define EL_ECHOTC 7 /* , const Char *, ..., NULL); set */ -#define EL_SETTY 8 /* , const Char *, ..., NULL); set */ -#define EL_ADDFN 9 /* , const Char *, const Char, set */ - /* el_func_t); */ -#define EL_HIST 10 /* , hist_fun_t, const void *); set */ -#define EL_EDITMODE 11 /* , int); set/get */ -#define EL_RPROMPT 12 /* , prompt_func); set/get */ -#define EL_GETCFN 13 /* , el_rfunc_t); set/get */ -#define EL_CLIENTDATA 14 /* , void *); set/get */ -#define EL_UNBUFFERED 15 /* , int); set/get */ -#define EL_PREP_TERM 16 /* , int); set */ -#define EL_GETTC 17 /* , const Char *, ..., NULL); get */ -#define EL_GETFP 18 /* , int, FILE **); get */ -#define EL_SETFP 19 /* , int, FILE *); set */ -#define EL_REFRESH 20 /* , void); set */ -#define EL_PROMPT_ESC 21 /* , prompt_func, Char); set/get */ -#define EL_RPROMPT_ESC 22 /* , prompt_func, Char); set/get */ -#define EL_RESIZE 23 /* , el_zfunc_t, void *); set */ - -#define EL_BUILTIN_GETCFN (NULL) - -/* - * Source named file or $PWD/.editrc or $HOME/.editrc - */ -int el_source(EditLine *, const char *); - -/* - * Must be called when the terminal changes size; If EL_SIGNAL - * is set this is done automatically otherwise it is the responsibility - * of the application - */ -void el_resize(EditLine *); - -/* - * User-defined function interface. - */ -const LineInfo *el_line(EditLine *); -int el_insertstr(EditLine *, const char *); -void el_deletestr(EditLine *, int); - - -/* - * ==== History ==== - */ - -typedef struct history History; - -typedef struct HistEvent { - int num; - const char *str; -} HistEvent; - -/* - * History access functions. - */ -History * history_init(void); -void history_end(History *); - -int history(History *, HistEvent *, int, ...); - -#define H_FUNC 0 /* , UTSL */ -#define H_SETSIZE 1 /* , const int); */ -#define H_GETSIZE 2 /* , void); */ -#define H_FIRST 3 /* , void); */ -#define H_LAST 4 /* , void); */ -#define H_PREV 5 /* , void); */ -#define H_NEXT 6 /* , void); */ -#define H_CURR 8 /* , const int); */ -#define H_SET 7 /* , int); */ -#define H_ADD 9 /* , const wchar_t *); */ -#define H_ENTER 10 /* , const wchar_t *); */ -#define H_APPEND 11 /* , const wchar_t *); */ -#define H_END 12 /* , void); */ -#define H_NEXT_STR 13 /* , const wchar_t *); */ -#define H_PREV_STR 14 /* , const wchar_t *); */ -#define H_NEXT_EVENT 15 /* , const int); */ -#define H_PREV_EVENT 16 /* , const int); */ -#define H_LOAD 17 /* , const char *); */ -#define H_SAVE 18 /* , const char *); */ -#define H_CLEAR 19 /* , void); */ -#define H_SETUNIQUE 20 /* , int); */ -#define H_GETUNIQUE 21 /* , void); */ -#define H_DEL 22 /* , int); */ -#define H_NEXT_EVDATA 23 /* , const int, histdata_t *); */ -#define H_DELDATA 24 /* , int, histdata_t *);*/ -#define H_REPLACE 25 /* , const char *, histdata_t); */ - - - -/* - * ==== Tokenization ==== - */ - -typedef struct tokenizer Tokenizer; - -/* - * String tokenization functions, using simplified sh(1) quoting rules - */ -Tokenizer *tok_init(const char *); -void tok_end(Tokenizer *); -void tok_reset(Tokenizer *); -int tok_line(Tokenizer *, const LineInfo *, - int *, const char ***, int *, int *); -int tok_str(Tokenizer *, const char *, - int *, const char ***); - -/* - * Begin Wide Character Support - */ - -/* - * Wide character versions - */ - -/* - * ==== Editing ==== - */ -typedef struct lineinfow { - const wchar_t *buffer; - const wchar_t *cursor; - const wchar_t *lastchar; -} LineInfoW; - -const wchar_t *el_wgets(EditLine *, int *); -int el_wgetc(EditLine *, wchar_t *); -void el_wpush(EditLine *, const wchar_t *); - -int el_wparse(EditLine *, int, const wchar_t **); - -int el_wset(EditLine *, int, ...); -int el_wget(EditLine *, int, ...); - -const LineInfoW *el_wline(EditLine *); -int el_winsertstr(EditLine *, const wchar_t *); -#define el_wdeletestr el_deletestr - -/* - * ==== History ==== - */ -typedef struct histeventW { - int num; - const wchar_t *str; -} HistEventW; - -typedef struct historyW HistoryW; - -HistoryW * history_winit(void); -void history_wend(HistoryW *); - -int history_w(HistoryW *, HistEventW *, int, ...); - -/* - * ==== Tokenization ==== - */ -typedef struct tokenizerW TokenizerW; - -/* Wide character tokenizer support */ -TokenizerW *tok_winit(const wchar_t *); -void tok_wend(TokenizerW *); -void tok_wreset(TokenizerW *); -int tok_wline(TokenizerW *, const LineInfoW *, - int *, const wchar_t ***, int *, int *); -int tok_wstr(TokenizerW *, const wchar_t *, - int *, const wchar_t ***); - -#ifdef __cplusplus -} -#endif - -#endif /* _HISTEDIT_H_ */ diff --git a/cmd-line-utils/libedit/history.c b/cmd-line-utils/libedit/history.c deleted file mode 100644 index 6d2176c258b..00000000000 --- a/cmd-line-utils/libedit/history.c +++ /dev/null @@ -1,1102 +0,0 @@ -/* $NetBSD: history.c,v 1.45 2011/07/29 23:44:44 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)history.c 8.1 (Berkeley) 6/4/93"; -#else -#endif -#endif /* not lint && not SCCSID */ - -/* - * hist.c: TYPE(History) access functions - */ -#include -#include -#include -#ifdef HAVE_VIS_H -#include -#else -#include "np/vis.h" -#endif -#include - -static const char hist_cookie[] = "_HiStOrY_V2_\n"; - -#include "histedit.h" -#include "chartype.h" - -typedef int (*history_gfun_t)(void *, TYPE(HistEvent) *); -typedef int (*history_efun_t)(void *, TYPE(HistEvent) *, const Char *); -typedef void (*history_vfun_t)(void *, TYPE(HistEvent) *); -typedef int (*history_sfun_t)(void *, TYPE(HistEvent) *, const int); - -struct TYPE(history) { - void *h_ref; /* Argument for history fcns */ - int h_ent; /* Last entry point for history */ - history_gfun_t h_first; /* Get the first element */ - history_gfun_t h_next; /* Get the next element */ - history_gfun_t h_last; /* Get the last element */ - history_gfun_t h_prev; /* Get the previous element */ - history_gfun_t h_curr; /* Get the current element */ - history_sfun_t h_set; /* Set the current element */ - history_sfun_t h_del; /* Set the given element */ - history_vfun_t h_clear; /* Clear the history list */ - history_efun_t h_enter; /* Add an element */ - history_efun_t h_add; /* Append to an element */ -}; - -#define HNEXT(h, ev) (*(h)->h_next)((h)->h_ref, ev) -#define HFIRST(h, ev) (*(h)->h_first)((h)->h_ref, ev) -#define HPREV(h, ev) (*(h)->h_prev)((h)->h_ref, ev) -#define HLAST(h, ev) (*(h)->h_last)((h)->h_ref, ev) -#define HCURR(h, ev) (*(h)->h_curr)((h)->h_ref, ev) -#define HSET(h, ev, n) (*(h)->h_set)((h)->h_ref, ev, n) -#define HCLEAR(h, ev) (*(h)->h_clear)((h)->h_ref, ev) -#define HENTER(h, ev, str) (*(h)->h_enter)((h)->h_ref, ev, str) -#define HADD(h, ev, str) (*(h)->h_add)((h)->h_ref, ev, str) -#define HDEL(h, ev, n) (*(h)->h_del)((h)->h_ref, ev, n) - -#define h_strdup(a) Strdup(a) -#define h_malloc(a) malloc(a) -#define h_realloc(a, b) realloc((a), (b)) -#define h_free(a) free(a) - -typedef struct { - int num; - Char *str; -} HistEventPrivate; - - - -private int history_setsize(TYPE(History) *, TYPE(HistEvent) *, int); -private int history_getsize(TYPE(History) *, TYPE(HistEvent) *); -private int history_setunique(TYPE(History) *, TYPE(HistEvent) *, int); -private int history_getunique(TYPE(History) *, TYPE(HistEvent) *); -private int history_set_fun(TYPE(History) *, TYPE(History) *); -private int history_load(TYPE(History) *, const char *); -private int history_save(TYPE(History) *, const char *); -private int history_prev_event(TYPE(History) *, TYPE(HistEvent) *, int); -private int history_next_event(TYPE(History) *, TYPE(HistEvent) *, int); -private int history_next_string(TYPE(History) *, TYPE(HistEvent) *, const Char *); -private int history_prev_string(TYPE(History) *, TYPE(HistEvent) *, const Char *); - - -/***********************************************************************/ - -/* - * Builtin- history implementation - */ -typedef struct hentry_t { - TYPE(HistEvent) ev; /* What we return */ - void *data; /* data */ - struct hentry_t *next; /* Next entry */ - struct hentry_t *prev; /* Previous entry */ -} hentry_t; - -typedef struct history_t { - hentry_t list; /* Fake list header element */ - hentry_t *cursor; /* Current element in the list */ - int max; /* Maximum number of events */ - int cur; /* Current number of events */ - int eventid; /* For generation of unique event id */ - int flags; /* TYPE(History) flags */ -#define H_UNIQUE 1 /* Store only unique elements */ -} history_t; - -private int history_def_next(void *, TYPE(HistEvent) *); -private int history_def_first(void *, TYPE(HistEvent) *); -private int history_def_prev(void *, TYPE(HistEvent) *); -private int history_def_last(void *, TYPE(HistEvent) *); -private int history_def_curr(void *, TYPE(HistEvent) *); -private int history_def_set(void *, TYPE(HistEvent) *, const int); -private void history_def_clear(void *, TYPE(HistEvent) *); -private int history_def_enter(void *, TYPE(HistEvent) *, const Char *); -private int history_def_add(void *, TYPE(HistEvent) *, const Char *); -private int history_def_del(void *, TYPE(HistEvent) *, const int); - -private int history_def_init(void **, TYPE(HistEvent) *, int); -private int history_def_insert(history_t *, TYPE(HistEvent) *, const Char *); -private void history_def_delete(history_t *, TYPE(HistEvent) *, hentry_t *); - -private int history_deldata_nth(history_t *, TYPE(HistEvent) *, int, void **); -private int history_set_nth(void *, TYPE(HistEvent) *, int); - -#define history_def_setsize(p, num)(void) (((history_t *)p)->max = (num)) -#define history_def_getsize(p) (((history_t *)p)->cur) -#define history_def_getunique(p) (((((history_t *)p)->flags) & H_UNIQUE) != 0) -#define history_def_setunique(p, uni) \ - if (uni) \ - (((history_t *)p)->flags) |= H_UNIQUE; \ - else \ - (((history_t *)p)->flags) &= ~H_UNIQUE - -#define he_strerror(code) he_errlist[code] -#define he_seterrev(evp, code) {\ - evp->num = code;\ - evp->str = he_strerror(code);\ - } - -/* error messages */ -static const Char *const he_errlist[] = { - STR("OK"), - STR("unknown error"), - STR("malloc() failed"), - STR("first event not found"), - STR("last event not found"), - STR("empty list"), - STR("no next event"), - STR("no previous event"), - STR("current event is invalid"), - STR("event not found"), - STR("can't read history from file"), - STR("can't write history"), - STR("required parameter(s) not supplied"), - STR("history size negative"), - STR("function not allowed with other history-functions-set the default"), - STR("bad parameters") -}; -/* error codes */ -#define _HE_OK 0 -#define _HE_UNKNOWN 1 -#define _HE_MALLOC_FAILED 2 -#define _HE_FIRST_NOTFOUND 3 -#define _HE_LAST_NOTFOUND 4 -#define _HE_EMPTY_LIST 5 -#define _HE_END_REACHED 6 -#define _HE_START_REACHED 7 -#define _HE_CURR_INVALID 8 -#define _HE_NOT_FOUND 9 -#define _HE_HIST_READ 10 -#define _HE_HIST_WRITE 11 -#define _HE_PARAM_MISSING 12 -#define _HE_SIZE_NEGATIVE 13 -#define _HE_NOT_ALLOWED 14 -#define _HE_BAD_PARAM 15 - -/* history_def_first(): - * Default function to return the first event in the history. - */ -private int -history_def_first(void *p, TYPE(HistEvent) *ev) -{ - history_t *h = (history_t *) p; - - h->cursor = h->list.next; - if (h->cursor != &h->list) - *ev = h->cursor->ev; - else { - he_seterrev(ev, _HE_FIRST_NOTFOUND); - return -1; - } - - return 0; -} - - -/* history_def_last(): - * Default function to return the last event in the history. - */ -private int -history_def_last(void *p, TYPE(HistEvent) *ev) -{ - history_t *h = (history_t *) p; - - h->cursor = h->list.prev; - if (h->cursor != &h->list) - *ev = h->cursor->ev; - else { - he_seterrev(ev, _HE_LAST_NOTFOUND); - return -1; - } - - return 0; -} - - -/* history_def_next(): - * Default function to return the next event in the history. - */ -private int -history_def_next(void *p, TYPE(HistEvent) *ev) -{ - history_t *h = (history_t *) p; - - if (h->cursor == &h->list) { - he_seterrev(ev, _HE_EMPTY_LIST); - return -1; - } - - if (h->cursor->next == &h->list) { - he_seterrev(ev, _HE_END_REACHED); - return -1; - } - - h->cursor = h->cursor->next; - *ev = h->cursor->ev; - - return 0; -} - - -/* history_def_prev(): - * Default function to return the previous event in the history. - */ -private int -history_def_prev(void *p, TYPE(HistEvent) *ev) -{ - history_t *h = (history_t *) p; - - if (h->cursor == &h->list) { - he_seterrev(ev, - (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST); - return -1; - } - - if (h->cursor->prev == &h->list) { - he_seterrev(ev, _HE_START_REACHED); - return -1; - } - - h->cursor = h->cursor->prev; - *ev = h->cursor->ev; - - return 0; -} - - -/* history_def_curr(): - * Default function to return the current event in the history. - */ -private int -history_def_curr(void *p, TYPE(HistEvent) *ev) -{ - history_t *h = (history_t *) p; - - if (h->cursor != &h->list) - *ev = h->cursor->ev; - else { - he_seterrev(ev, - (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST); - return -1; - } - - return 0; -} - - -/* history_def_set(): - * Default function to set the current event in the history to the - * given one. - */ -private int -history_def_set(void *p, TYPE(HistEvent) *ev, const int n) -{ - history_t *h = (history_t *) p; - - if (h->cur == 0) { - he_seterrev(ev, _HE_EMPTY_LIST); - return -1; - } - if (h->cursor == &h->list || h->cursor->ev.num != n) { - for (h->cursor = h->list.next; h->cursor != &h->list; - h->cursor = h->cursor->next) - if (h->cursor->ev.num == n) - break; - } - if (h->cursor == &h->list) { - he_seterrev(ev, _HE_NOT_FOUND); - return -1; - } - return 0; -} - - -/* history_set_nth(): - * Default function to set the current event in the history to the - * n-th one. - */ -private int -history_set_nth(void *p, TYPE(HistEvent) *ev, int n) -{ - history_t *h = (history_t *) p; - - if (h->cur == 0) { - he_seterrev(ev, _HE_EMPTY_LIST); - return -1; - } - for (h->cursor = h->list.prev; h->cursor != &h->list; - h->cursor = h->cursor->prev) - if (n-- <= 0) - break; - if (h->cursor == &h->list) { - he_seterrev(ev, _HE_NOT_FOUND); - return -1; - } - return 0; -} - - -/* history_def_add(): - * Append string to element - */ -private int -history_def_add(void *p, TYPE(HistEvent) *ev, const Char *str) -{ - history_t *h = (history_t *) p; - size_t len; - Char *s; - HistEventPrivate *evp = (void *)&h->cursor->ev; - - if (h->cursor == &h->list) - return history_def_enter(p, ev, str); - len = Strlen(evp->str) + Strlen(str) + 1; - s = h_malloc(len * sizeof(*s)); - if (s == NULL) { - he_seterrev(ev, _HE_MALLOC_FAILED); - return -1; - } - (void) Strncpy(s, h->cursor->ev.str, len); - s[len - 1] = '\0'; - (void) Strncat(s, str, len - Strlen(s) - 1); - h_free(evp->str); - evp->str = s; - *ev = h->cursor->ev; - return 0; -} - - -private int -history_deldata_nth(history_t *h, TYPE(HistEvent) *ev, - int num, void **data) -{ - if (history_set_nth(h, ev, num) != 0) - return -1; - /* magic value to skip delete (just set to n-th history) */ - if (data == (void **)-1) - return 0; - ev->str = Strdup(h->cursor->ev.str); - ev->num = h->cursor->ev.num; - if (data) - *data = h->cursor->data; - history_def_delete(h, ev, h->cursor); - return 0; -} - - -/* history_def_del(): - * Delete element hp of the h list - */ -/* ARGSUSED */ -private int -history_def_del(void *p, TYPE(HistEvent) *ev __attribute__((__unused__)), - const int num) -{ - history_t *h = (history_t *) p; - if (history_def_set(h, ev, num) != 0) - return -1; - ev->str = Strdup(h->cursor->ev.str); - ev->num = h->cursor->ev.num; - history_def_delete(h, ev, h->cursor); - return 0; -} - - -/* history_def_delete(): - * Delete element hp of the h list - */ -/* ARGSUSED */ -private void -history_def_delete(history_t *h, - TYPE(HistEvent) *ev __attribute__((__unused__)), hentry_t *hp) -{ - HistEventPrivate *evp = (void *)&hp->ev; - if (hp == &h->list) - abort(); - if (h->cursor == hp) { - h->cursor = hp->prev; - if (h->cursor == &h->list) - h->cursor = hp->next; - } - hp->prev->next = hp->next; - hp->next->prev = hp->prev; - h_free(evp->str); - h_free(hp); - h->cur--; -} - - -/* history_def_insert(): - * Insert element with string str in the h list - */ -private int -history_def_insert(history_t *h, TYPE(HistEvent) *ev, const Char *str) -{ - hentry_t *c; - - c = h_malloc(sizeof(*c)); - if (c == NULL) - goto oomem; - if ((c->ev.str = h_strdup(str)) == NULL) { - h_free(c); - goto oomem; - } - c->data = NULL; - c->ev.num = ++h->eventid; - c->next = h->list.next; - c->prev = &h->list; - h->list.next->prev = c; - h->list.next = c; - h->cur++; - h->cursor = c; - - *ev = c->ev; - return 0; -oomem: - he_seterrev(ev, _HE_MALLOC_FAILED); - return -1; -} - - -/* history_def_enter(): - * Default function to enter an item in the history - */ -private int -history_def_enter(void *p, TYPE(HistEvent) *ev, const Char *str) -{ - history_t *h = (history_t *) p; - - if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list && - Strcmp(h->list.next->ev.str, str) == 0) - return 0; - - if (history_def_insert(h, ev, str) == -1) - return -1; /* error, keep error message */ - - /* - * Always keep at least one entry. - * This way we don't have to check for the empty list. - */ - while (h->cur > h->max && h->cur > 0) - history_def_delete(h, ev, h->list.prev); - - return 1; -} - - -/* history_def_init(): - * Default history initialization function - */ -/* ARGSUSED */ -private int -history_def_init(void **p, TYPE(HistEvent) *ev __attribute__((__unused__)), int n) -{ - history_t *h = (history_t *) h_malloc(sizeof(*h)); - if (h == NULL) - return -1; - - if (n <= 0) - n = 0; - h->eventid = 0; - h->cur = 0; - h->max = n; - h->list.next = h->list.prev = &h->list; - h->list.ev.str = NULL; - h->list.ev.num = 0; - h->cursor = &h->list; - h->flags = 0; - *p = h; - return 0; -} - - -/* history_def_clear(): - * Default history cleanup function - */ -private void -history_def_clear(void *p, TYPE(HistEvent) *ev) -{ - history_t *h = (history_t *) p; - - while (h->list.prev != &h->list) - history_def_delete(h, ev, h->list.prev); - h->cursor = &h->list; - h->eventid = 0; - h->cur = 0; -} - - - - -/************************************************************************/ - -/* history_init(): - * Initialization function. - */ -public TYPE(History) * -FUN(history,init)(void) -{ - TYPE(HistEvent) ev; - TYPE(History) *h = (TYPE(History) *) h_malloc(sizeof(*h)); - if (h == NULL) - return NULL; - - if (history_def_init(&h->h_ref, &ev, 0) == -1) { - h_free(h); - return NULL; - } - h->h_ent = -1; - h->h_next = history_def_next; - h->h_first = history_def_first; - h->h_last = history_def_last; - h->h_prev = history_def_prev; - h->h_curr = history_def_curr; - h->h_set = history_def_set; - h->h_clear = history_def_clear; - h->h_enter = history_def_enter; - h->h_add = history_def_add; - h->h_del = history_def_del; - - return h; -} - - -/* history_end(): - * clean up history; - */ -public void -FUN(history,end)(TYPE(History) *h) -{ - TYPE(HistEvent) ev; - - if (h->h_next == history_def_next) - history_def_clear(h->h_ref, &ev); - h_free(h->h_ref); - h_free(h); -} - - - -/* history_setsize(): - * Set history number of events - */ -private int -history_setsize(TYPE(History) *h, TYPE(HistEvent) *ev, int num) -{ - - if (h->h_next != history_def_next) { - he_seterrev(ev, _HE_NOT_ALLOWED); - return -1; - } - if (num < 0) { - he_seterrev(ev, _HE_BAD_PARAM); - return -1; - } - history_def_setsize(h->h_ref, num); - return 0; -} - - -/* history_getsize(): - * Get number of events currently in history - */ -private int -history_getsize(TYPE(History) *h, TYPE(HistEvent) *ev) -{ - if (h->h_next != history_def_next) { - he_seterrev(ev, _HE_NOT_ALLOWED); - return -1; - } - ev->num = history_def_getsize(h->h_ref); - if (ev->num < -1) { - he_seterrev(ev, _HE_SIZE_NEGATIVE); - return -1; - } - return 0; -} - - -/* history_setunique(): - * Set if adjacent equal events should not be entered in history. - */ -private int -history_setunique(TYPE(History) *h, TYPE(HistEvent) *ev, int uni) -{ - - if (h->h_next != history_def_next) { - he_seterrev(ev, _HE_NOT_ALLOWED); - return -1; - } - history_def_setunique(h->h_ref, uni); - return 0; -} - - -/* history_getunique(): - * Get if adjacent equal events should not be entered in history. - */ -private int -history_getunique(TYPE(History) *h, TYPE(HistEvent) *ev) -{ - if (h->h_next != history_def_next) { - he_seterrev(ev, _HE_NOT_ALLOWED); - return -1; - } - ev->num = history_def_getunique(h->h_ref); - return 0; -} - - -/* history_set_fun(): - * Set history functions - */ -private int -history_set_fun(TYPE(History) *h, TYPE(History) *nh) -{ - TYPE(HistEvent) ev; - - if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL || - nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL || - nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL || - nh->h_del == NULL || nh->h_ref == NULL) { - if (h->h_next != history_def_next) { - history_def_init(&h->h_ref, &ev, 0); - h->h_first = history_def_first; - h->h_next = history_def_next; - h->h_last = history_def_last; - h->h_prev = history_def_prev; - h->h_curr = history_def_curr; - h->h_set = history_def_set; - h->h_clear = history_def_clear; - h->h_enter = history_def_enter; - h->h_add = history_def_add; - h->h_del = history_def_del; - } - return -1; - } - if (h->h_next == history_def_next) - history_def_clear(h->h_ref, &ev); - - h->h_ent = -1; - h->h_first = nh->h_first; - h->h_next = nh->h_next; - h->h_last = nh->h_last; - h->h_prev = nh->h_prev; - h->h_curr = nh->h_curr; - h->h_set = nh->h_set; - h->h_clear = nh->h_clear; - h->h_enter = nh->h_enter; - h->h_add = nh->h_add; - h->h_del = nh->h_del; - - return 0; -} - - -/* history_load(): - * TYPE(History) load function - */ -private int -history_load(TYPE(History) *h, const char *fname) -{ - FILE *fp; - char *line; - size_t sz, max_size; - char *ptr; - int i = -1; - TYPE(HistEvent) ev; -#ifdef WIDECHAR - static ct_buffer_t conv; -#endif - - if ((fp = fopen(fname, "r")) == NULL) - return i; - - if ((line = fgetln(fp, &sz)) == NULL) - goto done; - - if (strncmp(line, hist_cookie, sz) != 0) - goto done; - - ptr = h_malloc((max_size = 1024) * sizeof(*ptr)); - if (ptr == NULL) - goto done; - for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) { - char c = line[sz]; - - if (sz != 0 && line[sz - 1] == '\n') - line[--sz] = '\0'; - else - line[sz] = '\0'; - - if (max_size < sz) { - char *nptr; - max_size = (sz + 1024) & (size_t)~1023; - nptr = h_realloc(ptr, max_size * sizeof(*ptr)); - if (nptr == NULL) { - i = -1; - goto oomem; - } - ptr = nptr; - } - (void) strunvis(ptr, line); - line[sz] = c; - if (HENTER(h, &ev, ct_decode_string(ptr, &conv)) == -1) { - i = -1; - goto oomem; - } - } -oomem: - h_free(ptr); -done: - (void) fclose(fp); - return i; -} - - -/* history_save(): - * TYPE(History) save function - */ -private int -history_save(TYPE(History) *h, const char *fname) -{ - FILE *fp; - TYPE(HistEvent) ev; - int i = -1, retval; - size_t len, max_size; - char *ptr; - const char *str; -#ifdef WIDECHAR - static ct_buffer_t conv; -#endif - - if ((fp = fopen(fname, "w")) == NULL) - return -1; - - if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) - goto done; - if (fputs(hist_cookie, fp) == EOF) - goto done; - ptr = h_malloc((max_size = 1024) * sizeof(*ptr)); - if (ptr == NULL) - goto done; - for (i = 0, retval = HLAST(h, &ev); - retval != -1; - retval = HPREV(h, &ev), i++) { - str = ct_encode_string(ev.str, &conv); - len = strlen(str) * 4; - if (len >= max_size) { - char *nptr; - max_size = (len + 1024) & (size_t)~1023; - nptr = h_realloc(ptr, max_size * sizeof(*ptr)); - if (nptr == NULL) { - i = -1; - goto oomem; - } - ptr = nptr; - } - (void) strvis(ptr, str, VIS_WHITE); - (void) fprintf(fp, "%s\n", ptr); - } -oomem: - h_free(ptr); -done: - (void) fclose(fp); - return i; -} - - -/* history_prev_event(): - * Find the previous event, with number given - */ -private int -history_prev_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num) -{ - int retval; - - for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev)) - if (ev->num == num) - return 0; - - he_seterrev(ev, _HE_NOT_FOUND); - return -1; -} - - -private int -history_next_evdata(TYPE(History) *h, TYPE(HistEvent) *ev, int num, void **d) -{ - int retval; - - for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev)) - if (ev->num == num) { - if (d) - *d = ((history_t *)h->h_ref)->cursor->data; - return 0; - } - - he_seterrev(ev, _HE_NOT_FOUND); - return -1; -} - - -/* history_next_event(): - * Find the next event, with number given - */ -private int -history_next_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num) -{ - int retval; - - for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev)) - if (ev->num == num) - return 0; - - he_seterrev(ev, _HE_NOT_FOUND); - return -1; -} - - -/* history_prev_string(): - * Find the previous event beginning with string - */ -private int -history_prev_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str) -{ - size_t len = Strlen(str); - int retval; - - for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev)) - if (Strncmp(str, ev->str, len) == 0) - return 0; - - he_seterrev(ev, _HE_NOT_FOUND); - return -1; -} - - -/* history_next_string(): - * Find the next event beginning with string - */ -private int -history_next_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str) -{ - size_t len = Strlen(str); - int retval; - - for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev)) - if (Strncmp(str, ev->str, len) == 0) - return 0; - - he_seterrev(ev, _HE_NOT_FOUND); - return -1; -} - - -/* history(): - * User interface to history functions. - */ -int -FUNW(history)(TYPE(History) *h, TYPE(HistEvent) *ev, int fun, ...) -{ - va_list va; - const Char *str; - int retval; - - va_start(va, fun); - - he_seterrev(ev, _HE_OK); - - switch (fun) { - case H_GETSIZE: - retval = history_getsize(h, ev); - break; - - case H_SETSIZE: - retval = history_setsize(h, ev, va_arg(va, int)); - break; - - case H_GETUNIQUE: - retval = history_getunique(h, ev); - break; - - case H_SETUNIQUE: - retval = history_setunique(h, ev, va_arg(va, int)); - break; - - case H_ADD: - str = va_arg(va, const Char *); - retval = HADD(h, ev, str); - break; - - case H_DEL: - retval = HDEL(h, ev, va_arg(va, const int)); - break; - - case H_ENTER: - str = va_arg(va, const Char *); - if ((retval = HENTER(h, ev, str)) != -1) - h->h_ent = ev->num; - break; - - case H_APPEND: - str = va_arg(va, const Char *); - if ((retval = HSET(h, ev, h->h_ent)) != -1) - retval = HADD(h, ev, str); - break; - - case H_FIRST: - retval = HFIRST(h, ev); - break; - - case H_NEXT: - retval = HNEXT(h, ev); - break; - - case H_LAST: - retval = HLAST(h, ev); - break; - - case H_PREV: - retval = HPREV(h, ev); - break; - - case H_CURR: - retval = HCURR(h, ev); - break; - - case H_SET: - retval = HSET(h, ev, va_arg(va, const int)); - break; - - case H_CLEAR: - HCLEAR(h, ev); - retval = 0; - break; - - case H_LOAD: - retval = history_load(h, va_arg(va, const char *)); - if (retval == -1) - he_seterrev(ev, _HE_HIST_READ); - break; - - case H_SAVE: - retval = history_save(h, va_arg(va, const char *)); - if (retval == -1) - he_seterrev(ev, _HE_HIST_WRITE); - break; - - case H_PREV_EVENT: - retval = history_prev_event(h, ev, va_arg(va, int)); - break; - - case H_NEXT_EVENT: - retval = history_next_event(h, ev, va_arg(va, int)); - break; - - case H_PREV_STR: - retval = history_prev_string(h, ev, va_arg(va, const Char *)); - break; - - case H_NEXT_STR: - retval = history_next_string(h, ev, va_arg(va, const Char *)); - break; - - case H_FUNC: - { - TYPE(History) hf; - - hf.h_ref = va_arg(va, void *); - h->h_ent = -1; - hf.h_first = va_arg(va, history_gfun_t); - hf.h_next = va_arg(va, history_gfun_t); - hf.h_last = va_arg(va, history_gfun_t); - hf.h_prev = va_arg(va, history_gfun_t); - hf.h_curr = va_arg(va, history_gfun_t); - hf.h_set = va_arg(va, history_sfun_t); - hf.h_clear = va_arg(va, history_vfun_t); - hf.h_enter = va_arg(va, history_efun_t); - hf.h_add = va_arg(va, history_efun_t); - hf.h_del = va_arg(va, history_sfun_t); - - if ((retval = history_set_fun(h, &hf)) == -1) - he_seterrev(ev, _HE_PARAM_MISSING); - break; - } - - case H_END: - FUN(history,end)(h); - retval = 0; - break; - - case H_NEXT_EVDATA: - { - int num = va_arg(va, int); - void **d = va_arg(va, void **); - retval = history_next_evdata(h, ev, num, d); - break; - } - - case H_DELDATA: - { - int num = va_arg(va, int); - void **d = va_arg(va, void **); - retval = history_deldata_nth((history_t *)h->h_ref, ev, num, d); - break; - } - - case H_REPLACE: /* only use after H_NEXT_EVDATA */ - { - const Char *line = va_arg(va, const Char *); - void *d = va_arg(va, void *); - const Char *s; - if(!line || !(s = Strdup(line))) { - retval = -1; - break; - } - ((history_t *)h->h_ref)->cursor->ev.str = s; - ((history_t *)h->h_ref)->cursor->data = d; - retval = 0; - break; - } - - default: - retval = -1; - he_seterrev(ev, _HE_UNKNOWN); - break; - } - va_end(va); - return retval; -} diff --git a/cmd-line-utils/libedit/historyn.c b/cmd-line-utils/libedit/historyn.c deleted file mode 100644 index 99871ea2075..00000000000 --- a/cmd-line-utils/libedit/historyn.c +++ /dev/null @@ -1,5 +0,0 @@ -#define NARROW_WRAPPER -#include "config.h" -#undef WIDECHAR -#define NARROWCHAR -#include "./history.c" diff --git a/cmd-line-utils/libedit/keymacro.c b/cmd-line-utils/libedit/keymacro.c deleted file mode 100644 index 8df60e85d6c..00000000000 --- a/cmd-line-utils/libedit/keymacro.c +++ /dev/null @@ -1,677 +0,0 @@ -/* $NetBSD: keymacro.c,v 1.7 2011/08/16 16:25:15 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)key.c 8.1 (Berkeley) 6/4/93"; -#else -#endif -#endif /* not lint && not SCCSID */ - -/* - * keymacro.c: This module contains the procedures for maintaining - * the extended-key map. - * - * An extended-key (key) is a sequence of keystrokes introduced - * with a sequence introducer and consisting of an arbitrary - * number of characters. This module maintains a map (the - * el->el_keymacro.map) - * to convert these extended-key sequences into input strs - * (XK_STR), editor functions (XK_CMD), or unix commands (XK_EXE). - * - * Warning: - * If key is a substr of some other keys, then the longer - * keys are lost!! That is, if the keys "abcd" and "abcef" - * are in el->el_keymacro.map, adding the key "abc" will cause - * the first two definitions to be lost. - * - * Restrictions: - * ------------- - * 1) It is not possible to have one key that is a - * substr of another. - */ -#include -#include - -#include "el.h" - -/* - * The Nodes of the el->el_keymacro.map. The el->el_keymacro.map is a - * linked list of these node elements - */ -struct keymacro_node_t { - Char ch; /* single character of key */ - int type; /* node type */ - keymacro_value_t val; /* command code or pointer to str, */ - /* if this is a leaf */ - struct keymacro_node_t *next; /* ptr to next char of this key */ - struct keymacro_node_t *sibling;/* ptr to another key with same prefix*/ -}; - -private int node_trav(EditLine *, keymacro_node_t *, Char *, - keymacro_value_t *); -private int node__try(EditLine *, keymacro_node_t *, const Char *, - keymacro_value_t *, int); -private keymacro_node_t *node__get(Int); -private void node__free(keymacro_node_t *); -private void node__put(EditLine *, keymacro_node_t *); -private int node__delete(EditLine *, keymacro_node_t **, - const Char *); -private int node_lookup(EditLine *, const Char *, - keymacro_node_t *, size_t); -private int node_enum(EditLine *, keymacro_node_t *, size_t); - -#define KEY_BUFSIZ EL_BUFSIZ - - -/* keymacro_init(): - * Initialize the key maps - */ -protected int -keymacro_init(EditLine *el) -{ - - el->el_keymacro.buf = el_malloc(KEY_BUFSIZ * - sizeof(*el->el_keymacro.buf)); - if (el->el_keymacro.buf == NULL) - return -1; - el->el_keymacro.map = NULL; - keymacro_reset(el); - return 0; -} - -/* keymacro_end(): - * Free the key maps - */ -protected void -keymacro_end(EditLine *el) -{ - - el_free(el->el_keymacro.buf); - el->el_keymacro.buf = NULL; - node__free(el->el_keymacro.map); -} - - -/* keymacro_map_cmd(): - * Associate cmd with a key value - */ -protected keymacro_value_t * -keymacro_map_cmd(EditLine *el, int cmd) -{ - - el->el_keymacro.val.cmd = (el_action_t) cmd; - return &el->el_keymacro.val; -} - - -/* keymacro_map_str(): - * Associate str with a key value - */ -protected keymacro_value_t * -keymacro_map_str(EditLine *el, Char *str) -{ - - el->el_keymacro.val.str = str; - return &el->el_keymacro.val; -} - - -/* keymacro_reset(): - * Takes all nodes on el->el_keymacro.map and puts them on free list. - * Then initializes el->el_keymacro.map with arrow keys - * [Always bind the ansi arrow keys?] - */ -protected void -keymacro_reset(EditLine *el) -{ - - node__put(el, el->el_keymacro.map); - el->el_keymacro.map = NULL; - return; -} - - -/* keymacro_get(): - * Calls the recursive function with entry point el->el_keymacro.map - * Looks up *ch in map and then reads characters until a - * complete match is found or a mismatch occurs. Returns the - * type of the match found (XK_STR, XK_CMD, or XK_EXE). - * Returns NULL in val.str and XK_STR for no match. - * The last character read is returned in *ch. - */ -protected int -keymacro_get(EditLine *el, Char *ch, keymacro_value_t *val) -{ - - return node_trav(el, el->el_keymacro.map, ch, val); -} - - -/* keymacro_add(): - * Adds key to the el->el_keymacro.map and associates the value in - * val with it. If key is already is in el->el_keymacro.map, the new - * code is applied to the existing key. Ntype specifies if code is a - * command, an out str or a unix command. - */ -protected void -keymacro_add(EditLine *el, const Char *key, keymacro_value_t *val, int ntype) -{ - - if (key[0] == '\0') { - (void) fprintf(el->el_errfile, - "keymacro_add: Null extended-key not allowed.\n"); - return; - } - if (ntype == XK_CMD && val->cmd == ED_SEQUENCE_LEAD_IN) { - (void) fprintf(el->el_errfile, - "keymacro_add: sequence-lead-in command not allowed\n"); - return; - } - if (el->el_keymacro.map == NULL) - /* tree is initially empty. Set up new node to match key[0] */ - el->el_keymacro.map = node__get(key[0]); - /* it is properly initialized */ - - /* Now recurse through el->el_keymacro.map */ - (void) node__try(el, el->el_keymacro.map, key, val, ntype); - return; -} - - -/* keymacro_clear(): - * - */ -protected void -keymacro_clear(EditLine *el, el_action_t *map, const Char *in) -{ -#ifdef WIDECHAR - if (*in > N_KEYS) /* can't be in the map */ - return; -#endif - if ((map[(unsigned char)*in] == ED_SEQUENCE_LEAD_IN) && - ((map == el->el_map.key && - el->el_map.alt[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN) || - (map == el->el_map.alt && - el->el_map.key[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN))) - (void) keymacro_delete(el, in); -} - - -/* keymacro_delete(): - * Delete the key and all longer keys staring with key, if - * they exists. - */ -protected int -keymacro_delete(EditLine *el, const Char *key) -{ - - if (key[0] == '\0') { - (void) fprintf(el->el_errfile, - "keymacro_delete: Null extended-key not allowed.\n"); - return -1; - } - if (el->el_keymacro.map == NULL) - return 0; - - (void) node__delete(el, &el->el_keymacro.map, key); - return 0; -} - - -/* keymacro_print(): - * Print the binding associated with key key. - * Print entire el->el_keymacro.map if null - */ -protected void -keymacro_print(EditLine *el, const Char *key) -{ - - /* do nothing if el->el_keymacro.map is empty and null key specified */ - if (el->el_keymacro.map == NULL && *key == 0) - return; - - el->el_keymacro.buf[0] = '"'; - if (node_lookup(el, key, el->el_keymacro.map, (size_t)1) <= -1) - /* key is not bound */ - (void) fprintf(el->el_errfile, "Unbound extended key \"" FSTR - "\"\n", key); - return; -} - - -/* node_trav(): - * recursively traverses node in tree until match or mismatch is - * found. May read in more characters. - */ -private int -node_trav(EditLine *el, keymacro_node_t *ptr, Char *ch, keymacro_value_t *val) -{ - - if (ptr->ch == *ch) { - /* match found */ - if (ptr->next) { - /* key not complete so get next char */ - if (FUN(el,getc)(el, ch) != 1) {/* if EOF or error */ - val->cmd = ED_END_OF_FILE; - return XK_CMD; - /* PWP: Pretend we just read an end-of-file */ - } - return node_trav(el, ptr->next, ch, val); - } else { - *val = ptr->val; - if (ptr->type != XK_CMD) - *ch = '\0'; - return ptr->type; - } - } else { - /* no match found here */ - if (ptr->sibling) { - /* try next sibling */ - return node_trav(el, ptr->sibling, ch, val); - } else { - /* no next sibling -- mismatch */ - val->str = NULL; - return XK_STR; - } - } -} - - -/* node__try(): - * Find a node that matches *str or allocate a new one - */ -private int -node__try(EditLine *el, keymacro_node_t *ptr, const Char *str, - keymacro_value_t *val, int ntype) -{ - - if (ptr->ch != *str) { - keymacro_node_t *xm; - - for (xm = ptr; xm->sibling != NULL; xm = xm->sibling) - if (xm->sibling->ch == *str) - break; - if (xm->sibling == NULL) - xm->sibling = node__get(*str); /* setup new node */ - ptr = xm->sibling; - } - if (*++str == '\0') { - /* we're there */ - if (ptr->next != NULL) { - node__put(el, ptr->next); - /* lose longer keys with this prefix */ - ptr->next = NULL; - } - switch (ptr->type) { - case XK_CMD: - case XK_NOD: - break; - case XK_STR: - case XK_EXE: - if (ptr->val.str) - el_free(ptr->val.str); - break; - default: - EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", - ptr->type)); - break; - } - - switch (ptr->type = ntype) { - case XK_CMD: - ptr->val = *val; - break; - case XK_STR: - case XK_EXE: - if ((ptr->val.str = Strdup(val->str)) == NULL) - return -1; - break; - default: - EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype)); - break; - } - } else { - /* still more chars to go */ - if (ptr->next == NULL) - ptr->next = node__get(*str); /* setup new node */ - (void) node__try(el, ptr->next, str, val, ntype); - } - return 0; -} - - -/* node__delete(): - * Delete node that matches str - */ -private int -node__delete(EditLine *el, keymacro_node_t **inptr, const Char *str) -{ - keymacro_node_t *ptr; - keymacro_node_t *prev_ptr = NULL; - - ptr = *inptr; - - if (ptr->ch != *str) { - keymacro_node_t *xm; - - for (xm = ptr; xm->sibling != NULL; xm = xm->sibling) - if (xm->sibling->ch == *str) - break; - if (xm->sibling == NULL) - return 0; - prev_ptr = xm; - ptr = xm->sibling; - } - if (*++str == '\0') { - /* we're there */ - if (prev_ptr == NULL) - *inptr = ptr->sibling; - else - prev_ptr->sibling = ptr->sibling; - ptr->sibling = NULL; - node__put(el, ptr); - return 1; - } else if (ptr->next != NULL && - node__delete(el, &ptr->next, str) == 1) { - if (ptr->next != NULL) - return 0; - if (prev_ptr == NULL) - *inptr = ptr->sibling; - else - prev_ptr->sibling = ptr->sibling; - ptr->sibling = NULL; - node__put(el, ptr); - return 1; - } else { - return 0; - } -} - - -/* node__put(): - * Puts a tree of nodes onto free list using free(3). - */ -private void -node__put(EditLine *el, keymacro_node_t *ptr) -{ - if (ptr == NULL) - return; - - if (ptr->next != NULL) { - node__put(el, ptr->next); - ptr->next = NULL; - } - node__put(el, ptr->sibling); - - switch (ptr->type) { - case XK_CMD: - case XK_NOD: - break; - case XK_EXE: - case XK_STR: - if (ptr->val.str != NULL) - el_free(ptr->val.str); - break; - default: - EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ptr->type)); - break; - } - el_free(ptr); -} - - -/* node__get(): - * Returns pointer to a keymacro_node_t for ch. - */ -private keymacro_node_t * -node__get(Int ch) -{ - keymacro_node_t *ptr; - - ptr = el_malloc(sizeof(*ptr)); - if (ptr == NULL) - return NULL; - ptr->ch = ch; - ptr->type = XK_NOD; - ptr->val.str = NULL; - ptr->next = NULL; - ptr->sibling = NULL; - return ptr; -} - -private void -node__free(keymacro_node_t *k) -{ - if (k == NULL) - return; - node__free(k->sibling); - node__free(k->next); - el_free(k); -} - -/* node_lookup(): - * look for the str starting at node ptr. - * Print if last node - */ -private int -node_lookup(EditLine *el, const Char *str, keymacro_node_t *ptr, size_t cnt) -{ - ssize_t used; - - if (ptr == NULL) - return -1; /* cannot have null ptr */ - - if (!str || *str == 0) { - /* no more chars in str. node_enum from here. */ - (void) node_enum(el, ptr, cnt); - return 0; - } else { - /* If match put this char into el->el_keymacro.buf. Recurse */ - if (ptr->ch == *str) { - /* match found */ - used = ct_visual_char(el->el_keymacro.buf + cnt, - KEY_BUFSIZ - cnt, ptr->ch); - if (used == -1) - return -1; /* ran out of buffer space */ - if (ptr->next != NULL) - /* not yet at leaf */ - return (node_lookup(el, str + 1, ptr->next, - (size_t)used + cnt)); - else { - /* next node is null so key should be complete */ - if (str[1] == 0) { - size_t px = cnt + (size_t)used; - el->el_keymacro.buf[px] = '"'; - el->el_keymacro.buf[px + 1] = '\0'; - keymacro_kprint(el, el->el_keymacro.buf, - &ptr->val, ptr->type); - return 0; - } else - return -1; - /* mismatch -- str still has chars */ - } - } else { - /* no match found try sibling */ - if (ptr->sibling) - return (node_lookup(el, str, ptr->sibling, - cnt)); - else - return -1; - } - } -} - - -/* node_enum(): - * Traverse the node printing the characters it is bound in buffer - */ -private int -node_enum(EditLine *el, keymacro_node_t *ptr, size_t cnt) -{ - ssize_t used; - - if (cnt >= KEY_BUFSIZ - 5) { /* buffer too small */ - el->el_keymacro.buf[++cnt] = '"'; - el->el_keymacro.buf[++cnt] = '\0'; - (void) fprintf(el->el_errfile, - "Some extended keys too long for internal print buffer"); - (void) fprintf(el->el_errfile, " \"" FSTR "...\"\n", - el->el_keymacro.buf); - return 0; - } - if (ptr == NULL) { -#ifdef DEBUG_EDIT - (void) fprintf(el->el_errfile, - "node_enum: BUG!! Null ptr passed\n!"); -#endif - return -1; - } - /* put this char at end of str */ - used = ct_visual_char(el->el_keymacro.buf + cnt, KEY_BUFSIZ - cnt, - ptr->ch); - if (ptr->next == NULL) { - /* print this key and function */ - el->el_keymacro.buf[cnt + (size_t)used ] = '"'; - el->el_keymacro.buf[cnt + (size_t)used + 1] = '\0'; - keymacro_kprint(el, el->el_keymacro.buf, &ptr->val, ptr->type); - } else - (void) node_enum(el, ptr->next, cnt + (size_t)used); - - /* go to sibling if there is one */ - if (ptr->sibling) - (void) node_enum(el, ptr->sibling, cnt); - return 0; -} - - -/* keymacro_kprint(): - * Print the specified key and its associated - * function specified by val - */ -protected void -keymacro_kprint(EditLine *el, const Char *key, keymacro_value_t *val, int ntype) -{ - el_bindings_t *fp; - char unparsbuf[EL_BUFSIZ]; - static const char fmt[] = "%-15s-> %s\n"; - mbstate_t state; - - memset(&state, 0, sizeof(mbstate_t)); - if (val != NULL) - switch (ntype) { - case XK_STR: - case XK_EXE: - (void) keymacro__decode_str(val->str, unparsbuf, - sizeof(unparsbuf), - ntype == XK_STR ? "\"\"" : "[]"); - (void) fprintf(el->el_outfile, fmt, - ct_encode_string(key, &el->el_scratch), unparsbuf); - break; - case XK_CMD: - for (fp = el->el_map.help; fp->name; fp++) - if (val->cmd == fp->func) { - memset(&state, 0, sizeof(mbstate_t)); - wcsrtombs(unparsbuf, (const wchar_t **) &fp->name, - sizeof(unparsbuf), &state); - unparsbuf[sizeof(unparsbuf) -1] = '\0'; - (void) fprintf(el->el_outfile, fmt, - ct_encode_string(key, &el->el_scratch), unparsbuf); - break; - } -#ifdef DEBUG_KEY - if (fp->name == NULL) - (void) fprintf(el->el_outfile, - "BUG! Command not found.\n"); -#endif - - break; - default: - EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype)); - break; - } - else - (void) fprintf(el->el_outfile, fmt, ct_encode_string(key, - &el->el_scratch), "no input"); -} - - -#define ADDC(c) \ - if (b < eb) \ - *b++ = c; \ - else \ - b++ -/* keymacro__decode_str(): - * Make a printable version of the ey - */ -protected size_t -keymacro__decode_str(const Char *str, char *buf, size_t len, const char *sep) -{ - char *b = buf, *eb = b + len; - const Char *p; - mbstate_t state; - - memset(&state, 0, sizeof(mbstate_t)); - b = buf; - if (sep[0] != '\0') { - ADDC(sep[0]); - } - if (*str == '\0') { - ADDC('^'); - ADDC('@'); - goto add_endsep; - } - for (p = str; *p != 0; p++) { - Char dbuf[VISUAL_WIDTH_MAX]; - Char *p2 = dbuf; - ssize_t l = ct_visual_char(dbuf, VISUAL_WIDTH_MAX, *p); - while (l-- > 0) { - ssize_t n = ct_encode_char(b, (size_t)(eb - b), *p2++, - &state); - if (n == -1) /* ran out of space */ - goto add_endsep; - else - b += n; - } - } -add_endsep: - if (sep[0] != '\0' && sep[1] != '\0') { - ADDC(sep[1]); - } - ADDC('\0'); - if ((size_t)(b - buf) >= len) - buf[len - 1] = '\0'; - return (size_t)(b - buf); -} diff --git a/cmd-line-utils/libedit/keymacro.h b/cmd-line-utils/libedit/keymacro.h deleted file mode 100644 index 2445de5a5bc..00000000000 --- a/cmd-line-utils/libedit/keymacro.h +++ /dev/null @@ -1,76 +0,0 @@ -/* $NetBSD: keymacro.h,v 1.2 2011/07/28 03:44:36 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)key.h 8.1 (Berkeley) 6/4/93 - */ - -/* - * el.keymacro.h: Key macro header - */ -#ifndef _h_el_keymacro -#define _h_el_keymacro - -typedef union keymacro_value_t { - el_action_t cmd; /* If it is a command the # */ - Char *str; /* If it is a string... */ -} keymacro_value_t; - -typedef struct keymacro_node_t keymacro_node_t; - -typedef struct el_keymacromacro_t { - Char *buf; /* Key print buffer */ - keymacro_node_t *map; /* Key map */ - keymacro_value_t val; /* Local conversion buffer */ -} el_keymacro_t; - -#define XK_CMD 0 -#define XK_STR 1 -#define XK_NOD 2 -#define XK_EXE 3 - -protected int keymacro_init(EditLine *); -protected void keymacro_end(EditLine *); -protected keymacro_value_t *keymacro_map_cmd(EditLine *, int); -protected keymacro_value_t *keymacro_map_str(EditLine *, Char *); -protected void keymacro_reset(EditLine *); -protected int keymacro_get(EditLine *, Char *, keymacro_value_t *); -protected void keymacro_add(EditLine *, const Char *, keymacro_value_t *, int); -protected void keymacro_clear(EditLine *, el_action_t *, const Char *); -protected int keymacro_delete(EditLine *, const Char *); -protected void keymacro_print(EditLine *, const Char *); -protected void keymacro_kprint(EditLine *, const Char *, keymacro_value_t *, - int); -protected size_t keymacro__decode_str(const Char *, char *, size_t, - const char *); - -#endif /* _h_el_keymacro */ diff --git a/cmd-line-utils/libedit/makelist.sh b/cmd-line-utils/libedit/makelist.sh deleted file mode 100644 index b1a28c32370..00000000000 --- a/cmd-line-utils/libedit/makelist.sh +++ /dev/null @@ -1,264 +0,0 @@ -#!/bin/sh - -# $NetBSD: makelist,v 1.16 2010/04/18 21:17:05 christos Exp $ -# -# Copyright (c) 1992, 1993 -# The Regents of the University of California. All rights reserved. -# -# This code is derived from software contributed to Berkeley by -# Christos Zoulas of Cornell University. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. Neither the name of the University nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# @(#)makelist 5.3 (Berkeley) 6/4/93 - -# makelist.sh: Automatically generate header files... - -AWK=@AWK@ -USAGE="Usage: $0 -n|-h|-e|-fc|-fh|-bc|-bh|-m " - -if [ "x$1" = "x" ] -then - echo $USAGE 1>&2 - exit 1 -fi - -FLAG="$1" -shift - -FILES="$@" - -case $FLAG in - -# generate foo.h file from foo.c -# --n) - cat << _EOF -#undef WIDECHAR -#define NARROWCHAR -#include "${FILES}" -_EOF - ;; - --h) - set - `echo $FILES | sed -e 's/\\./_/g'` - hdr="_h_`basename $1`" - cat $FILES | $AWK ' - BEGIN { - printf("/* Automatically generated file, do not edit */\n"); - printf("#ifndef %s\n#define %s\n", "'$hdr'", "'$hdr'"); - } - /\(\):/ { - pr = substr($2, 1, 2); - if (pr == "vi" || pr == "em" || pr == "ed") { - # XXXMYSQL: support CRLF - name = substr($2, 1, index($2,"(") - 1); -# -# XXX: need a space between name and prototype so that -fc and -fh -# parsing is much easier -# - printf("protected el_action_t\t%s (EditLine *, Int);\n", name); - } - } - END { - printf("#endif /* %s */\n", "'$hdr'"); - }' - ;; - -# generate help.c from various .c files -# --bc) - cat $FILES | $AWK ' - BEGIN { - printf("/* Automatically generated file, do not edit */\n"); - printf("#include \"config.h\"\n#include \"el.h\"\n"); - printf("#include \"chartype.h\"\n"); - printf("private const struct el_bindings_t el_func_help[] = {\n"); - low = "abcdefghijklmnopqrstuvwxyz_"; - high = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_"; - for (i = 1; i <= length(low); i++) - tr[substr(low, i, 1)] = substr(high, i, 1); - } - /\(\):/ { - pr = substr($2, 1, 2); - if (pr == "vi" || pr == "em" || pr == "ed") { - # XXXMYSQL: support CRLF - name = substr($2, 1, index($2,"(") - 1); - uname = ""; - fname = ""; - for (i = 1; i <= length(name); i++) { - s = substr(name, i, 1); - uname = uname tr[s]; - if (s == "_") - s = "-"; - fname = fname s; - } - - printf(" { %-30.30s %-30.30s\n","STR(\"" fname "\"),", uname ","); - ok = 1; - } - } - /^ \*/ { - if (ok) { - printf(" STR(\""); - for (i = 2; i < NF; i++) - printf("%s ", $i); - # XXXMYSQL: support CRLF - sub("\r", "", $i); - printf("%s\") },\n", $i); - ok = 0; - } - } - END { - printf("};\n"); - printf("\nprotected const el_bindings_t* help__get()"); - printf("{ return el_func_help; }\n"); - }' - ;; - -# generate help.h from various .c files -# --bh) - $AWK ' - BEGIN { - printf("/* Automatically generated file, do not edit */\n"); - printf("#ifndef _h_help_c\n#define _h_help_c\n"); - printf("protected const el_bindings_t *help__get(void);\n"); - printf("#endif /* _h_help_c */\n"); - }' /dev/null - ;; - -# generate fcns.h from various .h files -# -# XXXMYSQL: use portable tr syntax --fh) - cat $FILES | $AWK '/el_action_t/ { print $3 }' | \ - sort | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ | $AWK ' - BEGIN { - printf("/* Automatically generated file, do not edit */\n"); - printf("#ifndef _h_fcns_c\n#define _h_fcns_c\n"); - count = 0; - } - { - printf("#define\t%-30.30s\t%3d\n", $1, count++); - } - END { - printf("#define\t%-30.30s\t%3d\n", "EL_NUM_FCNS", count); - - printf("typedef el_action_t (*el_func_t)(EditLine *, Int);"); - printf("\nprotected const el_func_t* func__get(void);\n"); - printf("#endif /* _h_fcns_c */\n"); - }' - ;; - -# generate fcns.c from various .h files -# --fc) - cat $FILES | $AWK '/el_action_t/ { print $3 }' | sort | $AWK ' - BEGIN { - printf("/* Automatically generated file, do not edit */\n"); - printf("#include \"config.h\"\n#include \"el.h\"\n"); - printf("private const el_func_t el_func[] = {"); - maxlen = 80; - needn = 1; - len = 0; - } - { - clen = 25 + 2; - len += clen; - if (len >= maxlen) - needn = 1; - if (needn) { - printf("\n "); - needn = 0; - len = 4 + clen; - } - s = $1 ","; - printf("%-26.26s ", s); - } - END { - printf("\n};\n"); - printf("\nprotected const el_func_t* func__get() { return el_func; }\n"); - }' - ;; - -# generate editline.c from various .c files -# --e) - echo "$FILES" | tr ' ' '\012' | $AWK ' - BEGIN { - printf("/* Automatically generated file, do not edit */\n"); - printf("#define protected static\n"); - printf("#define SCCSID\n"); - } - { - printf("#include \"%s\"\n", $1); - }' - ;; - -# generate man page fragment from various .c files -# --m) - cat $FILES | $AWK ' - BEGIN { - printf(".\\\" Section automatically generated with makelist\n"); - printf(".Bl -tag -width 4n\n"); - } - /\(\):/ { - pr = substr($2, 1, 2); - if (pr == "vi" || pr == "em" || pr == "ed") { - # XXXMYSQL: support CRLF - name = substr($2, 1, index($2, "(") - 1); - fname = ""; - for (i = 1; i <= length(name); i++) { - s = substr(name, i, 1); - if (s == "_") - s = "-"; - fname = fname s; - } - - printf(".It Ic %s\n", fname); - ok = 1; - } - } - /^ \*/ { - if (ok) { - for (i = 2; i < NF; i++) - printf("%s ", $i); - printf("%s.\n", $i); - ok = 0; - } - } - END { - printf(".El\n"); - printf(".\\\" End of section automatically generated with makelist\n"); - }' - ;; - -*) - echo $USAGE 1>&2 - exit 1 - ;; - -esac diff --git a/cmd-line-utils/libedit/map.c b/cmd-line-utils/libedit/map.c deleted file mode 100644 index 17b07391b69..00000000000 --- a/cmd-line-utils/libedit/map.c +++ /dev/null @@ -1,1420 +0,0 @@ -/* $NetBSD: map.c,v 1.30 2011/08/16 16:25:15 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)map.c 8.1 (Berkeley) 6/4/93"; -#else -#endif -#endif /* not lint && not SCCSID */ - -/* - * map.c: Editor function definitions - */ -#include -#include "el.h" - -private void map_print_key(EditLine *, el_action_t *, const Char *); -private void map_print_some_keys(EditLine *, el_action_t *, Int, Int); -private void map_print_all_keys(EditLine *); -private void map_init_nls(EditLine *); -private void map_init_meta(EditLine *); - -/* keymap tables ; should be N_KEYS*sizeof(KEYCMD) bytes long */ - - -private const el_action_t el_map_emacs[] = { - /* 0 */ EM_SET_MARK, /* ^@ */ - /* 1 */ ED_MOVE_TO_BEG, /* ^A */ - /* 2 */ ED_PREV_CHAR, /* ^B */ - /* 3 */ ED_TTY_SIGINT, /* ^C */ - /* 4 */ EM_DELETE_OR_LIST, /* ^D */ - /* 5 */ ED_MOVE_TO_END, /* ^E */ - /* 6 */ ED_NEXT_CHAR, /* ^F */ - /* 7 */ ED_UNASSIGNED, /* ^G */ - /* 8 */ EM_DELETE_PREV_CHAR, /* ^H */ - /* 9 */ ED_UNASSIGNED, /* ^I */ - /* 10 */ ED_NEWLINE, /* ^J */ - /* 11 */ ED_KILL_LINE, /* ^K */ - /* 12 */ ED_CLEAR_SCREEN, /* ^L */ - /* 13 */ ED_NEWLINE, /* ^M */ - /* 14 */ ED_NEXT_HISTORY, /* ^N */ - /* 15 */ ED_TTY_FLUSH_OUTPUT, /* ^O */ - /* 16 */ ED_PREV_HISTORY, /* ^P */ - /* 17 */ ED_TTY_START_OUTPUT, /* ^Q */ - /* 18 */ ED_REDISPLAY, /* ^R */ - /* 19 */ ED_TTY_STOP_OUTPUT, /* ^S */ - /* 20 */ ED_TRANSPOSE_CHARS, /* ^T */ - /* 21 */ EM_KILL_LINE, /* ^U */ - /* 22 */ ED_QUOTED_INSERT, /* ^V */ - /* 23 */ EM_KILL_REGION, /* ^W */ - /* 24 */ ED_SEQUENCE_LEAD_IN, /* ^X */ - /* 25 */ EM_YANK, /* ^Y */ - /* 26 */ ED_TTY_SIGTSTP, /* ^Z */ - /* 27 */ EM_META_NEXT, /* ^[ */ - /* 28 */ ED_TTY_SIGQUIT, /* ^\ */ - /* 29 */ ED_TTY_DSUSP, /* ^] */ - /* 30 */ ED_UNASSIGNED, /* ^^ */ - /* 31 */ ED_UNASSIGNED, /* ^_ */ - /* 32 */ ED_INSERT, /* SPACE */ - /* 33 */ ED_INSERT, /* ! */ - /* 34 */ ED_INSERT, /* " */ - /* 35 */ ED_INSERT, /* # */ - /* 36 */ ED_INSERT, /* $ */ - /* 37 */ ED_INSERT, /* % */ - /* 38 */ ED_INSERT, /* & */ - /* 39 */ ED_INSERT, /* ' */ - /* 40 */ ED_INSERT, /* ( */ - /* 41 */ ED_INSERT, /* ) */ - /* 42 */ ED_INSERT, /* * */ - /* 43 */ ED_INSERT, /* + */ - /* 44 */ ED_INSERT, /* , */ - /* 45 */ ED_INSERT, /* - */ - /* 46 */ ED_INSERT, /* . */ - /* 47 */ ED_INSERT, /* / */ - /* 48 */ ED_DIGIT, /* 0 */ - /* 49 */ ED_DIGIT, /* 1 */ - /* 50 */ ED_DIGIT, /* 2 */ - /* 51 */ ED_DIGIT, /* 3 */ - /* 52 */ ED_DIGIT, /* 4 */ - /* 53 */ ED_DIGIT, /* 5 */ - /* 54 */ ED_DIGIT, /* 6 */ - /* 55 */ ED_DIGIT, /* 7 */ - /* 56 */ ED_DIGIT, /* 8 */ - /* 57 */ ED_DIGIT, /* 9 */ - /* 58 */ ED_INSERT, /* : */ - /* 59 */ ED_INSERT, /* ; */ - /* 60 */ ED_INSERT, /* < */ - /* 61 */ ED_INSERT, /* = */ - /* 62 */ ED_INSERT, /* > */ - /* 63 */ ED_INSERT, /* ? */ - /* 64 */ ED_INSERT, /* @ */ - /* 65 */ ED_INSERT, /* A */ - /* 66 */ ED_INSERT, /* B */ - /* 67 */ ED_INSERT, /* C */ - /* 68 */ ED_INSERT, /* D */ - /* 69 */ ED_INSERT, /* E */ - /* 70 */ ED_INSERT, /* F */ - /* 71 */ ED_INSERT, /* G */ - /* 72 */ ED_INSERT, /* H */ - /* 73 */ ED_INSERT, /* I */ - /* 74 */ ED_INSERT, /* J */ - /* 75 */ ED_INSERT, /* K */ - /* 76 */ ED_INSERT, /* L */ - /* 77 */ ED_INSERT, /* M */ - /* 78 */ ED_INSERT, /* N */ - /* 79 */ ED_INSERT, /* O */ - /* 80 */ ED_INSERT, /* P */ - /* 81 */ ED_INSERT, /* Q */ - /* 82 */ ED_INSERT, /* R */ - /* 83 */ ED_INSERT, /* S */ - /* 84 */ ED_INSERT, /* T */ - /* 85 */ ED_INSERT, /* U */ - /* 86 */ ED_INSERT, /* V */ - /* 87 */ ED_INSERT, /* W */ - /* 88 */ ED_INSERT, /* X */ - /* 89 */ ED_INSERT, /* Y */ - /* 90 */ ED_INSERT, /* Z */ - /* 91 */ ED_INSERT, /* [ */ - /* 92 */ ED_INSERT, /* \ */ - /* 93 */ ED_INSERT, /* ] */ - /* 94 */ ED_INSERT, /* ^ */ - /* 95 */ ED_INSERT, /* _ */ - /* 96 */ ED_INSERT, /* ` */ - /* 97 */ ED_INSERT, /* a */ - /* 98 */ ED_INSERT, /* b */ - /* 99 */ ED_INSERT, /* c */ - /* 100 */ ED_INSERT, /* d */ - /* 101 */ ED_INSERT, /* e */ - /* 102 */ ED_INSERT, /* f */ - /* 103 */ ED_INSERT, /* g */ - /* 104 */ ED_INSERT, /* h */ - /* 105 */ ED_INSERT, /* i */ - /* 106 */ ED_INSERT, /* j */ - /* 107 */ ED_INSERT, /* k */ - /* 108 */ ED_INSERT, /* l */ - /* 109 */ ED_INSERT, /* m */ - /* 110 */ ED_INSERT, /* n */ - /* 111 */ ED_INSERT, /* o */ - /* 112 */ ED_INSERT, /* p */ - /* 113 */ ED_INSERT, /* q */ - /* 114 */ ED_INSERT, /* r */ - /* 115 */ ED_INSERT, /* s */ - /* 116 */ ED_INSERT, /* t */ - /* 117 */ ED_INSERT, /* u */ - /* 118 */ ED_INSERT, /* v */ - /* 119 */ ED_INSERT, /* w */ - /* 120 */ ED_INSERT, /* x */ - /* 121 */ ED_INSERT, /* y */ - /* 122 */ ED_INSERT, /* z */ - /* 123 */ ED_INSERT, /* { */ - /* 124 */ ED_INSERT, /* | */ - /* 125 */ ED_INSERT, /* } */ - /* 126 */ ED_INSERT, /* ~ */ - /* 127 */ EM_DELETE_PREV_CHAR, /* ^? */ - /* 128 */ ED_UNASSIGNED, /* M-^@ */ - /* 129 */ ED_UNASSIGNED, /* M-^A */ - /* 130 */ ED_UNASSIGNED, /* M-^B */ - /* 131 */ ED_UNASSIGNED, /* M-^C */ - /* 132 */ ED_UNASSIGNED, /* M-^D */ - /* 133 */ ED_UNASSIGNED, /* M-^E */ - /* 134 */ ED_UNASSIGNED, /* M-^F */ - /* 135 */ ED_UNASSIGNED, /* M-^G */ - /* 136 */ ED_DELETE_PREV_WORD, /* M-^H */ - /* 137 */ ED_UNASSIGNED, /* M-^I */ - /* 138 */ ED_UNASSIGNED, /* M-^J */ - /* 139 */ ED_UNASSIGNED, /* M-^K */ - /* 140 */ ED_CLEAR_SCREEN, /* M-^L */ - /* 141 */ ED_UNASSIGNED, /* M-^M */ - /* 142 */ ED_UNASSIGNED, /* M-^N */ - /* 143 */ ED_UNASSIGNED, /* M-^O */ - /* 144 */ ED_UNASSIGNED, /* M-^P */ - /* 145 */ ED_UNASSIGNED, /* M-^Q */ - /* 146 */ ED_UNASSIGNED, /* M-^R */ - /* 147 */ ED_UNASSIGNED, /* M-^S */ - /* 148 */ ED_UNASSIGNED, /* M-^T */ - /* 149 */ ED_UNASSIGNED, /* M-^U */ - /* 150 */ ED_UNASSIGNED, /* M-^V */ - /* 151 */ ED_UNASSIGNED, /* M-^W */ - /* 152 */ ED_UNASSIGNED, /* M-^X */ - /* 153 */ ED_UNASSIGNED, /* M-^Y */ - /* 154 */ ED_UNASSIGNED, /* M-^Z */ - /* 155 */ ED_UNASSIGNED, /* M-^[ */ - /* 156 */ ED_UNASSIGNED, /* M-^\ */ - /* 157 */ ED_UNASSIGNED, /* M-^] */ - /* 158 */ ED_UNASSIGNED, /* M-^^ */ - /* 159 */ EM_COPY_PREV_WORD, /* M-^_ */ - /* 160 */ ED_UNASSIGNED, /* M-SPACE */ - /* 161 */ ED_UNASSIGNED, /* M-! */ - /* 162 */ ED_UNASSIGNED, /* M-" */ - /* 163 */ ED_UNASSIGNED, /* M-# */ - /* 164 */ ED_UNASSIGNED, /* M-$ */ - /* 165 */ ED_UNASSIGNED, /* M-% */ - /* 166 */ ED_UNASSIGNED, /* M-& */ - /* 167 */ ED_UNASSIGNED, /* M-' */ - /* 168 */ ED_UNASSIGNED, /* M-( */ - /* 169 */ ED_UNASSIGNED, /* M-) */ - /* 170 */ ED_UNASSIGNED, /* M-* */ - /* 171 */ ED_UNASSIGNED, /* M-+ */ - /* 172 */ ED_UNASSIGNED, /* M-, */ - /* 173 */ ED_UNASSIGNED, /* M-- */ - /* 174 */ ED_UNASSIGNED, /* M-. */ - /* 175 */ ED_UNASSIGNED, /* M-/ */ - /* 176 */ ED_ARGUMENT_DIGIT, /* M-0 */ - /* 177 */ ED_ARGUMENT_DIGIT, /* M-1 */ - /* 178 */ ED_ARGUMENT_DIGIT, /* M-2 */ - /* 179 */ ED_ARGUMENT_DIGIT, /* M-3 */ - /* 180 */ ED_ARGUMENT_DIGIT, /* M-4 */ - /* 181 */ ED_ARGUMENT_DIGIT, /* M-5 */ - /* 182 */ ED_ARGUMENT_DIGIT, /* M-6 */ - /* 183 */ ED_ARGUMENT_DIGIT, /* M-7 */ - /* 184 */ ED_ARGUMENT_DIGIT, /* M-8 */ - /* 185 */ ED_ARGUMENT_DIGIT, /* M-9 */ - /* 186 */ ED_UNASSIGNED, /* M-: */ - /* 187 */ ED_UNASSIGNED, /* M-; */ - /* 188 */ ED_UNASSIGNED, /* M-< */ - /* 189 */ ED_UNASSIGNED, /* M-= */ - /* 190 */ ED_UNASSIGNED, /* M-> */ - /* 191 */ ED_UNASSIGNED, /* M-? */ - /* 192 */ ED_UNASSIGNED, /* M-@ */ - /* 193 */ ED_UNASSIGNED, /* M-A */ - /* 194 */ ED_PREV_WORD, /* M-B */ - /* 195 */ EM_CAPITOL_CASE, /* M-C */ - /* 196 */ EM_DELETE_NEXT_WORD, /* M-D */ - /* 197 */ ED_UNASSIGNED, /* M-E */ - /* 198 */ EM_NEXT_WORD, /* M-F */ - /* 199 */ ED_UNASSIGNED, /* M-G */ - /* 200 */ ED_UNASSIGNED, /* M-H */ - /* 201 */ ED_UNASSIGNED, /* M-I */ - /* 202 */ ED_UNASSIGNED, /* M-J */ - /* 203 */ ED_UNASSIGNED, /* M-K */ - /* 204 */ EM_LOWER_CASE, /* M-L */ - /* 205 */ ED_UNASSIGNED, /* M-M */ - /* 206 */ ED_SEARCH_NEXT_HISTORY, /* M-N */ - /* 207 */ ED_SEQUENCE_LEAD_IN, /* M-O */ - /* 208 */ ED_SEARCH_PREV_HISTORY, /* M-P */ - /* 209 */ ED_UNASSIGNED, /* M-Q */ - /* 210 */ ED_UNASSIGNED, /* M-R */ - /* 211 */ ED_UNASSIGNED, /* M-S */ - /* 212 */ ED_UNASSIGNED, /* M-T */ - /* 213 */ EM_UPPER_CASE, /* M-U */ - /* 214 */ ED_UNASSIGNED, /* M-V */ - /* 215 */ EM_COPY_REGION, /* M-W */ - /* 216 */ ED_COMMAND, /* M-X */ - /* 217 */ ED_UNASSIGNED, /* M-Y */ - /* 218 */ ED_UNASSIGNED, /* M-Z */ - /* 219 */ ED_SEQUENCE_LEAD_IN, /* M-[ */ - /* 220 */ ED_UNASSIGNED, /* M-\ */ - /* 221 */ ED_UNASSIGNED, /* M-] */ - /* 222 */ ED_UNASSIGNED, /* M-^ */ - /* 223 */ ED_UNASSIGNED, /* M-_ */ - /* 223 */ ED_UNASSIGNED, /* M-` */ - /* 224 */ ED_UNASSIGNED, /* M-a */ - /* 225 */ ED_PREV_WORD, /* M-b */ - /* 226 */ EM_CAPITOL_CASE, /* M-c */ - /* 227 */ EM_DELETE_NEXT_WORD, /* M-d */ - /* 228 */ ED_UNASSIGNED, /* M-e */ - /* 229 */ EM_NEXT_WORD, /* M-f */ - /* 230 */ ED_UNASSIGNED, /* M-g */ - /* 231 */ ED_UNASSIGNED, /* M-h */ - /* 232 */ ED_UNASSIGNED, /* M-i */ - /* 233 */ ED_UNASSIGNED, /* M-j */ - /* 234 */ ED_UNASSIGNED, /* M-k */ - /* 235 */ EM_LOWER_CASE, /* M-l */ - /* 236 */ ED_UNASSIGNED, /* M-m */ - /* 237 */ ED_SEARCH_NEXT_HISTORY, /* M-n */ - /* 238 */ ED_UNASSIGNED, /* M-o */ - /* 239 */ ED_SEARCH_PREV_HISTORY, /* M-p */ - /* 240 */ ED_UNASSIGNED, /* M-q */ - /* 241 */ ED_UNASSIGNED, /* M-r */ - /* 242 */ ED_UNASSIGNED, /* M-s */ - /* 243 */ ED_UNASSIGNED, /* M-t */ - /* 244 */ EM_UPPER_CASE, /* M-u */ - /* 245 */ ED_UNASSIGNED, /* M-v */ - /* 246 */ EM_COPY_REGION, /* M-w */ - /* 247 */ ED_COMMAND, /* M-x */ - /* 248 */ ED_UNASSIGNED, /* M-y */ - /* 249 */ ED_UNASSIGNED, /* M-z */ - /* 250 */ ED_UNASSIGNED, /* M-{ */ - /* 251 */ ED_UNASSIGNED, /* M-| */ - /* 252 */ ED_UNASSIGNED, /* M-} */ - /* 253 */ ED_UNASSIGNED, /* M-~ */ - /* 254 */ ED_DELETE_PREV_WORD /* M-^? */ - /* 255 */ -}; - - -/* - * keymap table for vi. Each index into above tbl; should be - * N_KEYS entries long. Vi mode uses a sticky-extend to do command mode: - * insert mode characters are in the normal keymap, and command mode - * in the extended keymap. - */ -private const el_action_t el_map_vi_insert[] = { -#ifdef KSHVI - /* 0 */ ED_UNASSIGNED, /* ^@ */ - /* 1 */ ED_INSERT, /* ^A */ - /* 2 */ ED_INSERT, /* ^B */ - /* 3 */ ED_INSERT, /* ^C */ - /* 4 */ VI_LIST_OR_EOF, /* ^D */ - /* 5 */ ED_INSERT, /* ^E */ - /* 6 */ ED_INSERT, /* ^F */ - /* 7 */ ED_INSERT, /* ^G */ - /* 8 */ VI_DELETE_PREV_CHAR, /* ^H */ /* BackSpace key */ - /* 9 */ ED_INSERT, /* ^I */ /* Tab Key */ - /* 10 */ ED_NEWLINE, /* ^J */ - /* 11 */ ED_INSERT, /* ^K */ - /* 12 */ ED_INSERT, /* ^L */ - /* 13 */ ED_NEWLINE, /* ^M */ - /* 14 */ ED_INSERT, /* ^N */ - /* 15 */ ED_INSERT, /* ^O */ - /* 16 */ ED_INSERT, /* ^P */ - /* 17 */ ED_TTY_START_OUTPUT, /* ^Q */ - /* 18 */ ED_INSERT, /* ^R */ - /* 19 */ ED_TTY_STOP_OUTPUT, /* ^S */ - /* 20 */ ED_INSERT, /* ^T */ - /* 21 */ VI_KILL_LINE_PREV, /* ^U */ - /* 22 */ ED_QUOTED_INSERT, /* ^V */ - /* 23 */ ED_DELETE_PREV_WORD, /* ^W */ - /* ED_DELETE_PREV_WORD: Only until strt edit pos */ - /* 24 */ ED_INSERT, /* ^X */ - /* 25 */ ED_INSERT, /* ^Y */ - /* 26 */ ED_INSERT, /* ^Z */ - /* 27 */ VI_COMMAND_MODE, /* ^[ */ /* [ Esc ] key */ - /* 28 */ ED_TTY_SIGQUIT, /* ^\ */ - /* 29 */ ED_INSERT, /* ^] */ - /* 30 */ ED_INSERT, /* ^^ */ - /* 31 */ ED_INSERT, /* ^_ */ -#else /* !KSHVI */ - /* - * NOTE: These mappings do NOT Correspond well - * to the KSH VI editing assignments. - * On the other and they are convenient and - * many people have have gotten used to them. - */ - /* 0 */ ED_UNASSIGNED, /* ^@ */ - /* 1 */ ED_MOVE_TO_BEG, /* ^A */ - /* 2 */ ED_PREV_CHAR, /* ^B */ - /* 3 */ ED_TTY_SIGINT, /* ^C */ - /* 4 */ VI_LIST_OR_EOF, /* ^D */ - /* 5 */ ED_MOVE_TO_END, /* ^E */ - /* 6 */ ED_NEXT_CHAR, /* ^F */ - /* 7 */ ED_UNASSIGNED, /* ^G */ - /* 8 */ VI_DELETE_PREV_CHAR, /* ^H */ /* BackSpace key */ - /* 9 */ ED_UNASSIGNED, /* ^I */ /* Tab Key */ - /* 10 */ ED_NEWLINE, /* ^J */ - /* 11 */ ED_KILL_LINE, /* ^K */ - /* 12 */ ED_CLEAR_SCREEN, /* ^L */ - /* 13 */ ED_NEWLINE, /* ^M */ - /* 14 */ ED_NEXT_HISTORY, /* ^N */ - /* 15 */ ED_TTY_FLUSH_OUTPUT, /* ^O */ - /* 16 */ ED_PREV_HISTORY, /* ^P */ - /* 17 */ ED_TTY_START_OUTPUT, /* ^Q */ - /* 18 */ ED_REDISPLAY, /* ^R */ - /* 19 */ ED_TTY_STOP_OUTPUT, /* ^S */ - /* 20 */ ED_TRANSPOSE_CHARS, /* ^T */ - /* 21 */ VI_KILL_LINE_PREV, /* ^U */ - /* 22 */ ED_QUOTED_INSERT, /* ^V */ - /* 23 */ ED_DELETE_PREV_WORD, /* ^W */ - /* 24 */ ED_UNASSIGNED, /* ^X */ - /* 25 */ ED_TTY_DSUSP, /* ^Y */ - /* 26 */ ED_TTY_SIGTSTP, /* ^Z */ - /* 27 */ VI_COMMAND_MODE, /* ^[ */ - /* 28 */ ED_TTY_SIGQUIT, /* ^\ */ - /* 29 */ ED_UNASSIGNED, /* ^] */ - /* 30 */ ED_UNASSIGNED, /* ^^ */ - /* 31 */ ED_UNASSIGNED, /* ^_ */ -#endif /* KSHVI */ - /* 32 */ ED_INSERT, /* SPACE */ - /* 33 */ ED_INSERT, /* ! */ - /* 34 */ ED_INSERT, /* " */ - /* 35 */ ED_INSERT, /* # */ - /* 36 */ ED_INSERT, /* $ */ - /* 37 */ ED_INSERT, /* % */ - /* 38 */ ED_INSERT, /* & */ - /* 39 */ ED_INSERT, /* ' */ - /* 40 */ ED_INSERT, /* ( */ - /* 41 */ ED_INSERT, /* ) */ - /* 42 */ ED_INSERT, /* * */ - /* 43 */ ED_INSERT, /* + */ - /* 44 */ ED_INSERT, /* , */ - /* 45 */ ED_INSERT, /* - */ - /* 46 */ ED_INSERT, /* . */ - /* 47 */ ED_INSERT, /* / */ - /* 48 */ ED_INSERT, /* 0 */ - /* 49 */ ED_INSERT, /* 1 */ - /* 50 */ ED_INSERT, /* 2 */ - /* 51 */ ED_INSERT, /* 3 */ - /* 52 */ ED_INSERT, /* 4 */ - /* 53 */ ED_INSERT, /* 5 */ - /* 54 */ ED_INSERT, /* 6 */ - /* 55 */ ED_INSERT, /* 7 */ - /* 56 */ ED_INSERT, /* 8 */ - /* 57 */ ED_INSERT, /* 9 */ - /* 58 */ ED_INSERT, /* : */ - /* 59 */ ED_INSERT, /* ; */ - /* 60 */ ED_INSERT, /* < */ - /* 61 */ ED_INSERT, /* = */ - /* 62 */ ED_INSERT, /* > */ - /* 63 */ ED_INSERT, /* ? */ - /* 64 */ ED_INSERT, /* @ */ - /* 65 */ ED_INSERT, /* A */ - /* 66 */ ED_INSERT, /* B */ - /* 67 */ ED_INSERT, /* C */ - /* 68 */ ED_INSERT, /* D */ - /* 69 */ ED_INSERT, /* E */ - /* 70 */ ED_INSERT, /* F */ - /* 71 */ ED_INSERT, /* G */ - /* 72 */ ED_INSERT, /* H */ - /* 73 */ ED_INSERT, /* I */ - /* 74 */ ED_INSERT, /* J */ - /* 75 */ ED_INSERT, /* K */ - /* 76 */ ED_INSERT, /* L */ - /* 77 */ ED_INSERT, /* M */ - /* 78 */ ED_INSERT, /* N */ - /* 79 */ ED_INSERT, /* O */ - /* 80 */ ED_INSERT, /* P */ - /* 81 */ ED_INSERT, /* Q */ - /* 82 */ ED_INSERT, /* R */ - /* 83 */ ED_INSERT, /* S */ - /* 84 */ ED_INSERT, /* T */ - /* 85 */ ED_INSERT, /* U */ - /* 86 */ ED_INSERT, /* V */ - /* 87 */ ED_INSERT, /* W */ - /* 88 */ ED_INSERT, /* X */ - /* 89 */ ED_INSERT, /* Y */ - /* 90 */ ED_INSERT, /* Z */ - /* 91 */ ED_INSERT, /* [ */ - /* 92 */ ED_INSERT, /* \ */ - /* 93 */ ED_INSERT, /* ] */ - /* 94 */ ED_INSERT, /* ^ */ - /* 95 */ ED_INSERT, /* _ */ - /* 96 */ ED_INSERT, /* ` */ - /* 97 */ ED_INSERT, /* a */ - /* 98 */ ED_INSERT, /* b */ - /* 99 */ ED_INSERT, /* c */ - /* 100 */ ED_INSERT, /* d */ - /* 101 */ ED_INSERT, /* e */ - /* 102 */ ED_INSERT, /* f */ - /* 103 */ ED_INSERT, /* g */ - /* 104 */ ED_INSERT, /* h */ - /* 105 */ ED_INSERT, /* i */ - /* 106 */ ED_INSERT, /* j */ - /* 107 */ ED_INSERT, /* k */ - /* 108 */ ED_INSERT, /* l */ - /* 109 */ ED_INSERT, /* m */ - /* 110 */ ED_INSERT, /* n */ - /* 111 */ ED_INSERT, /* o */ - /* 112 */ ED_INSERT, /* p */ - /* 113 */ ED_INSERT, /* q */ - /* 114 */ ED_INSERT, /* r */ - /* 115 */ ED_INSERT, /* s */ - /* 116 */ ED_INSERT, /* t */ - /* 117 */ ED_INSERT, /* u */ - /* 118 */ ED_INSERT, /* v */ - /* 119 */ ED_INSERT, /* w */ - /* 120 */ ED_INSERT, /* x */ - /* 121 */ ED_INSERT, /* y */ - /* 122 */ ED_INSERT, /* z */ - /* 123 */ ED_INSERT, /* { */ - /* 124 */ ED_INSERT, /* | */ - /* 125 */ ED_INSERT, /* } */ - /* 126 */ ED_INSERT, /* ~ */ - /* 127 */ VI_DELETE_PREV_CHAR, /* ^? */ - /* 128 */ ED_INSERT, /* M-^@ */ - /* 129 */ ED_INSERT, /* M-^A */ - /* 130 */ ED_INSERT, /* M-^B */ - /* 131 */ ED_INSERT, /* M-^C */ - /* 132 */ ED_INSERT, /* M-^D */ - /* 133 */ ED_INSERT, /* M-^E */ - /* 134 */ ED_INSERT, /* M-^F */ - /* 135 */ ED_INSERT, /* M-^G */ - /* 136 */ ED_INSERT, /* M-^H */ - /* 137 */ ED_INSERT, /* M-^I */ - /* 138 */ ED_INSERT, /* M-^J */ - /* 139 */ ED_INSERT, /* M-^K */ - /* 140 */ ED_INSERT, /* M-^L */ - /* 141 */ ED_INSERT, /* M-^M */ - /* 142 */ ED_INSERT, /* M-^N */ - /* 143 */ ED_INSERT, /* M-^O */ - /* 144 */ ED_INSERT, /* M-^P */ - /* 145 */ ED_INSERT, /* M-^Q */ - /* 146 */ ED_INSERT, /* M-^R */ - /* 147 */ ED_INSERT, /* M-^S */ - /* 148 */ ED_INSERT, /* M-^T */ - /* 149 */ ED_INSERT, /* M-^U */ - /* 150 */ ED_INSERT, /* M-^V */ - /* 151 */ ED_INSERT, /* M-^W */ - /* 152 */ ED_INSERT, /* M-^X */ - /* 153 */ ED_INSERT, /* M-^Y */ - /* 154 */ ED_INSERT, /* M-^Z */ - /* 155 */ ED_INSERT, /* M-^[ */ - /* 156 */ ED_INSERT, /* M-^\ */ - /* 157 */ ED_INSERT, /* M-^] */ - /* 158 */ ED_INSERT, /* M-^^ */ - /* 159 */ ED_INSERT, /* M-^_ */ - /* 160 */ ED_INSERT, /* M-SPACE */ - /* 161 */ ED_INSERT, /* M-! */ - /* 162 */ ED_INSERT, /* M-" */ - /* 163 */ ED_INSERT, /* M-# */ - /* 164 */ ED_INSERT, /* M-$ */ - /* 165 */ ED_INSERT, /* M-% */ - /* 166 */ ED_INSERT, /* M-& */ - /* 167 */ ED_INSERT, /* M-' */ - /* 168 */ ED_INSERT, /* M-( */ - /* 169 */ ED_INSERT, /* M-) */ - /* 170 */ ED_INSERT, /* M-* */ - /* 171 */ ED_INSERT, /* M-+ */ - /* 172 */ ED_INSERT, /* M-, */ - /* 173 */ ED_INSERT, /* M-- */ - /* 174 */ ED_INSERT, /* M-. */ - /* 175 */ ED_INSERT, /* M-/ */ - /* 176 */ ED_INSERT, /* M-0 */ - /* 177 */ ED_INSERT, /* M-1 */ - /* 178 */ ED_INSERT, /* M-2 */ - /* 179 */ ED_INSERT, /* M-3 */ - /* 180 */ ED_INSERT, /* M-4 */ - /* 181 */ ED_INSERT, /* M-5 */ - /* 182 */ ED_INSERT, /* M-6 */ - /* 183 */ ED_INSERT, /* M-7 */ - /* 184 */ ED_INSERT, /* M-8 */ - /* 185 */ ED_INSERT, /* M-9 */ - /* 186 */ ED_INSERT, /* M-: */ - /* 187 */ ED_INSERT, /* M-; */ - /* 188 */ ED_INSERT, /* M-< */ - /* 189 */ ED_INSERT, /* M-= */ - /* 190 */ ED_INSERT, /* M-> */ - /* 191 */ ED_INSERT, /* M-? */ - /* 192 */ ED_INSERT, /* M-@ */ - /* 193 */ ED_INSERT, /* M-A */ - /* 194 */ ED_INSERT, /* M-B */ - /* 195 */ ED_INSERT, /* M-C */ - /* 196 */ ED_INSERT, /* M-D */ - /* 197 */ ED_INSERT, /* M-E */ - /* 198 */ ED_INSERT, /* M-F */ - /* 199 */ ED_INSERT, /* M-G */ - /* 200 */ ED_INSERT, /* M-H */ - /* 201 */ ED_INSERT, /* M-I */ - /* 202 */ ED_INSERT, /* M-J */ - /* 203 */ ED_INSERT, /* M-K */ - /* 204 */ ED_INSERT, /* M-L */ - /* 205 */ ED_INSERT, /* M-M */ - /* 206 */ ED_INSERT, /* M-N */ - /* 207 */ ED_INSERT, /* M-O */ - /* 208 */ ED_INSERT, /* M-P */ - /* 209 */ ED_INSERT, /* M-Q */ - /* 210 */ ED_INSERT, /* M-R */ - /* 211 */ ED_INSERT, /* M-S */ - /* 212 */ ED_INSERT, /* M-T */ - /* 213 */ ED_INSERT, /* M-U */ - /* 214 */ ED_INSERT, /* M-V */ - /* 215 */ ED_INSERT, /* M-W */ - /* 216 */ ED_INSERT, /* M-X */ - /* 217 */ ED_INSERT, /* M-Y */ - /* 218 */ ED_INSERT, /* M-Z */ - /* 219 */ ED_INSERT, /* M-[ */ - /* 220 */ ED_INSERT, /* M-\ */ - /* 221 */ ED_INSERT, /* M-] */ - /* 222 */ ED_INSERT, /* M-^ */ - /* 223 */ ED_INSERT, /* M-_ */ - /* 224 */ ED_INSERT, /* M-` */ - /* 225 */ ED_INSERT, /* M-a */ - /* 226 */ ED_INSERT, /* M-b */ - /* 227 */ ED_INSERT, /* M-c */ - /* 228 */ ED_INSERT, /* M-d */ - /* 229 */ ED_INSERT, /* M-e */ - /* 230 */ ED_INSERT, /* M-f */ - /* 231 */ ED_INSERT, /* M-g */ - /* 232 */ ED_INSERT, /* M-h */ - /* 233 */ ED_INSERT, /* M-i */ - /* 234 */ ED_INSERT, /* M-j */ - /* 235 */ ED_INSERT, /* M-k */ - /* 236 */ ED_INSERT, /* M-l */ - /* 237 */ ED_INSERT, /* M-m */ - /* 238 */ ED_INSERT, /* M-n */ - /* 239 */ ED_INSERT, /* M-o */ - /* 240 */ ED_INSERT, /* M-p */ - /* 241 */ ED_INSERT, /* M-q */ - /* 242 */ ED_INSERT, /* M-r */ - /* 243 */ ED_INSERT, /* M-s */ - /* 244 */ ED_INSERT, /* M-t */ - /* 245 */ ED_INSERT, /* M-u */ - /* 246 */ ED_INSERT, /* M-v */ - /* 247 */ ED_INSERT, /* M-w */ - /* 248 */ ED_INSERT, /* M-x */ - /* 249 */ ED_INSERT, /* M-y */ - /* 250 */ ED_INSERT, /* M-z */ - /* 251 */ ED_INSERT, /* M-{ */ - /* 252 */ ED_INSERT, /* M-| */ - /* 253 */ ED_INSERT, /* M-} */ - /* 254 */ ED_INSERT, /* M-~ */ - /* 255 */ ED_INSERT /* M-^? */ -}; - -private const el_action_t el_map_vi_command[] = { - /* 0 */ ED_UNASSIGNED, /* ^@ */ - /* 1 */ ED_MOVE_TO_BEG, /* ^A */ - /* 2 */ ED_UNASSIGNED, /* ^B */ - /* 3 */ ED_TTY_SIGINT, /* ^C */ - /* 4 */ ED_UNASSIGNED, /* ^D */ - /* 5 */ ED_MOVE_TO_END, /* ^E */ - /* 6 */ ED_UNASSIGNED, /* ^F */ - /* 7 */ ED_UNASSIGNED, /* ^G */ - /* 8 */ ED_DELETE_PREV_CHAR, /* ^H */ - /* 9 */ ED_UNASSIGNED, /* ^I */ - /* 10 */ ED_NEWLINE, /* ^J */ - /* 11 */ ED_KILL_LINE, /* ^K */ - /* 12 */ ED_CLEAR_SCREEN, /* ^L */ - /* 13 */ ED_NEWLINE, /* ^M */ - /* 14 */ ED_NEXT_HISTORY, /* ^N */ - /* 15 */ ED_TTY_FLUSH_OUTPUT, /* ^O */ - /* 16 */ ED_PREV_HISTORY, /* ^P */ - /* 17 */ ED_TTY_START_OUTPUT, /* ^Q */ - /* 18 */ ED_REDISPLAY, /* ^R */ - /* 19 */ ED_TTY_STOP_OUTPUT, /* ^S */ - /* 20 */ ED_UNASSIGNED, /* ^T */ - /* 21 */ VI_KILL_LINE_PREV, /* ^U */ - /* 22 */ ED_UNASSIGNED, /* ^V */ - /* 23 */ ED_DELETE_PREV_WORD, /* ^W */ - /* 24 */ ED_UNASSIGNED, /* ^X */ - /* 25 */ ED_UNASSIGNED, /* ^Y */ - /* 26 */ ED_UNASSIGNED, /* ^Z */ - /* 27 */ EM_META_NEXT, /* ^[ */ - /* 28 */ ED_TTY_SIGQUIT, /* ^\ */ - /* 29 */ ED_UNASSIGNED, /* ^] */ - /* 30 */ ED_UNASSIGNED, /* ^^ */ - /* 31 */ ED_UNASSIGNED, /* ^_ */ - /* 32 */ ED_NEXT_CHAR, /* SPACE */ - /* 33 */ ED_UNASSIGNED, /* ! */ - /* 34 */ ED_UNASSIGNED, /* " */ - /* 35 */ VI_COMMENT_OUT, /* # */ - /* 36 */ ED_MOVE_TO_END, /* $ */ - /* 37 */ VI_MATCH, /* % */ - /* 38 */ ED_UNASSIGNED, /* & */ - /* 39 */ ED_UNASSIGNED, /* ' */ - /* 40 */ ED_UNASSIGNED, /* ( */ - /* 41 */ ED_UNASSIGNED, /* ) */ - /* 42 */ ED_UNASSIGNED, /* * */ - /* 43 */ ED_NEXT_HISTORY, /* + */ - /* 44 */ VI_REPEAT_PREV_CHAR, /* , */ - /* 45 */ ED_PREV_HISTORY, /* - */ - /* 46 */ VI_REDO, /* . */ - /* 47 */ VI_SEARCH_PREV, /* / */ - /* 48 */ VI_ZERO, /* 0 */ - /* 49 */ ED_ARGUMENT_DIGIT, /* 1 */ - /* 50 */ ED_ARGUMENT_DIGIT, /* 2 */ - /* 51 */ ED_ARGUMENT_DIGIT, /* 3 */ - /* 52 */ ED_ARGUMENT_DIGIT, /* 4 */ - /* 53 */ ED_ARGUMENT_DIGIT, /* 5 */ - /* 54 */ ED_ARGUMENT_DIGIT, /* 6 */ - /* 55 */ ED_ARGUMENT_DIGIT, /* 7 */ - /* 56 */ ED_ARGUMENT_DIGIT, /* 8 */ - /* 57 */ ED_ARGUMENT_DIGIT, /* 9 */ - /* 58 */ ED_COMMAND, /* : */ - /* 59 */ VI_REPEAT_NEXT_CHAR, /* ; */ - /* 60 */ ED_UNASSIGNED, /* < */ - /* 61 */ ED_UNASSIGNED, /* = */ - /* 62 */ ED_UNASSIGNED, /* > */ - /* 63 */ VI_SEARCH_NEXT, /* ? */ - /* 64 */ VI_ALIAS, /* @ */ - /* 65 */ VI_ADD_AT_EOL, /* A */ - /* 66 */ VI_PREV_BIG_WORD, /* B */ - /* 67 */ VI_CHANGE_TO_EOL, /* C */ - /* 68 */ ED_KILL_LINE, /* D */ - /* 69 */ VI_END_BIG_WORD, /* E */ - /* 70 */ VI_PREV_CHAR, /* F */ - /* 71 */ VI_TO_HISTORY_LINE, /* G */ - /* 72 */ ED_UNASSIGNED, /* H */ - /* 73 */ VI_INSERT_AT_BOL, /* I */ - /* 74 */ ED_SEARCH_NEXT_HISTORY, /* J */ - /* 75 */ ED_SEARCH_PREV_HISTORY, /* K */ - /* 76 */ ED_UNASSIGNED, /* L */ - /* 77 */ ED_UNASSIGNED, /* M */ - /* 78 */ VI_REPEAT_SEARCH_PREV, /* N */ - /* 79 */ ED_SEQUENCE_LEAD_IN, /* O */ - /* 80 */ VI_PASTE_PREV, /* P */ - /* 81 */ ED_UNASSIGNED, /* Q */ - /* 82 */ VI_REPLACE_MODE, /* R */ - /* 83 */ VI_SUBSTITUTE_LINE, /* S */ - /* 84 */ VI_TO_PREV_CHAR, /* T */ - /* 85 */ VI_UNDO_LINE, /* U */ - /* 86 */ ED_UNASSIGNED, /* V */ - /* 87 */ VI_NEXT_BIG_WORD, /* W */ - /* 88 */ ED_DELETE_PREV_CHAR, /* X */ - /* 89 */ VI_YANK_END, /* Y */ - /* 90 */ ED_UNASSIGNED, /* Z */ - /* 91 */ ED_SEQUENCE_LEAD_IN, /* [ */ - /* 92 */ ED_UNASSIGNED, /* \ */ - /* 93 */ ED_UNASSIGNED, /* ] */ - /* 94 */ ED_MOVE_TO_BEG, /* ^ */ - /* 95 */ VI_HISTORY_WORD, /* _ */ - /* 96 */ ED_UNASSIGNED, /* ` */ - /* 97 */ VI_ADD, /* a */ - /* 98 */ VI_PREV_WORD, /* b */ - /* 99 */ VI_CHANGE_META, /* c */ - /* 100 */ VI_DELETE_META, /* d */ - /* 101 */ VI_END_WORD, /* e */ - /* 102 */ VI_NEXT_CHAR, /* f */ - /* 103 */ ED_UNASSIGNED, /* g */ - /* 104 */ ED_PREV_CHAR, /* h */ - /* 105 */ VI_INSERT, /* i */ - /* 106 */ ED_NEXT_HISTORY, /* j */ - /* 107 */ ED_PREV_HISTORY, /* k */ - /* 108 */ ED_NEXT_CHAR, /* l */ - /* 109 */ ED_UNASSIGNED, /* m */ - /* 110 */ VI_REPEAT_SEARCH_NEXT, /* n */ - /* 111 */ ED_UNASSIGNED, /* o */ - /* 112 */ VI_PASTE_NEXT, /* p */ - /* 113 */ ED_UNASSIGNED, /* q */ - /* 114 */ VI_REPLACE_CHAR, /* r */ - /* 115 */ VI_SUBSTITUTE_CHAR, /* s */ - /* 116 */ VI_TO_NEXT_CHAR, /* t */ - /* 117 */ VI_UNDO, /* u */ - /* 118 */ VI_HISTEDIT, /* v */ - /* 119 */ VI_NEXT_WORD, /* w */ - /* 120 */ ED_DELETE_NEXT_CHAR, /* x */ - /* 121 */ VI_YANK, /* y */ - /* 122 */ ED_UNASSIGNED, /* z */ - /* 123 */ ED_UNASSIGNED, /* { */ - /* 124 */ VI_TO_COLUMN, /* | */ - /* 125 */ ED_UNASSIGNED, /* } */ - /* 126 */ VI_CHANGE_CASE, /* ~ */ - /* 127 */ ED_DELETE_PREV_CHAR, /* ^? */ - /* 128 */ ED_UNASSIGNED, /* M-^@ */ - /* 129 */ ED_UNASSIGNED, /* M-^A */ - /* 130 */ ED_UNASSIGNED, /* M-^B */ - /* 131 */ ED_UNASSIGNED, /* M-^C */ - /* 132 */ ED_UNASSIGNED, /* M-^D */ - /* 133 */ ED_UNASSIGNED, /* M-^E */ - /* 134 */ ED_UNASSIGNED, /* M-^F */ - /* 135 */ ED_UNASSIGNED, /* M-^G */ - /* 136 */ ED_UNASSIGNED, /* M-^H */ - /* 137 */ ED_UNASSIGNED, /* M-^I */ - /* 138 */ ED_UNASSIGNED, /* M-^J */ - /* 139 */ ED_UNASSIGNED, /* M-^K */ - /* 140 */ ED_UNASSIGNED, /* M-^L */ - /* 141 */ ED_UNASSIGNED, /* M-^M */ - /* 142 */ ED_UNASSIGNED, /* M-^N */ - /* 143 */ ED_UNASSIGNED, /* M-^O */ - /* 144 */ ED_UNASSIGNED, /* M-^P */ - /* 145 */ ED_UNASSIGNED, /* M-^Q */ - /* 146 */ ED_UNASSIGNED, /* M-^R */ - /* 147 */ ED_UNASSIGNED, /* M-^S */ - /* 148 */ ED_UNASSIGNED, /* M-^T */ - /* 149 */ ED_UNASSIGNED, /* M-^U */ - /* 150 */ ED_UNASSIGNED, /* M-^V */ - /* 151 */ ED_UNASSIGNED, /* M-^W */ - /* 152 */ ED_UNASSIGNED, /* M-^X */ - /* 153 */ ED_UNASSIGNED, /* M-^Y */ - /* 154 */ ED_UNASSIGNED, /* M-^Z */ - /* 155 */ ED_UNASSIGNED, /* M-^[ */ - /* 156 */ ED_UNASSIGNED, /* M-^\ */ - /* 157 */ ED_UNASSIGNED, /* M-^] */ - /* 158 */ ED_UNASSIGNED, /* M-^^ */ - /* 159 */ ED_UNASSIGNED, /* M-^_ */ - /* 160 */ ED_UNASSIGNED, /* M-SPACE */ - /* 161 */ ED_UNASSIGNED, /* M-! */ - /* 162 */ ED_UNASSIGNED, /* M-" */ - /* 163 */ ED_UNASSIGNED, /* M-# */ - /* 164 */ ED_UNASSIGNED, /* M-$ */ - /* 165 */ ED_UNASSIGNED, /* M-% */ - /* 166 */ ED_UNASSIGNED, /* M-& */ - /* 167 */ ED_UNASSIGNED, /* M-' */ - /* 168 */ ED_UNASSIGNED, /* M-( */ - /* 169 */ ED_UNASSIGNED, /* M-) */ - /* 170 */ ED_UNASSIGNED, /* M-* */ - /* 171 */ ED_UNASSIGNED, /* M-+ */ - /* 172 */ ED_UNASSIGNED, /* M-, */ - /* 173 */ ED_UNASSIGNED, /* M-- */ - /* 174 */ ED_UNASSIGNED, /* M-. */ - /* 175 */ ED_UNASSIGNED, /* M-/ */ - /* 176 */ ED_UNASSIGNED, /* M-0 */ - /* 177 */ ED_UNASSIGNED, /* M-1 */ - /* 178 */ ED_UNASSIGNED, /* M-2 */ - /* 179 */ ED_UNASSIGNED, /* M-3 */ - /* 180 */ ED_UNASSIGNED, /* M-4 */ - /* 181 */ ED_UNASSIGNED, /* M-5 */ - /* 182 */ ED_UNASSIGNED, /* M-6 */ - /* 183 */ ED_UNASSIGNED, /* M-7 */ - /* 184 */ ED_UNASSIGNED, /* M-8 */ - /* 185 */ ED_UNASSIGNED, /* M-9 */ - /* 186 */ ED_UNASSIGNED, /* M-: */ - /* 187 */ ED_UNASSIGNED, /* M-; */ - /* 188 */ ED_UNASSIGNED, /* M-< */ - /* 189 */ ED_UNASSIGNED, /* M-= */ - /* 190 */ ED_UNASSIGNED, /* M-> */ - /* 191 */ ED_UNASSIGNED, /* M-? */ - /* 192 */ ED_UNASSIGNED, /* M-@ */ - /* 193 */ ED_UNASSIGNED, /* M-A */ - /* 194 */ ED_UNASSIGNED, /* M-B */ - /* 195 */ ED_UNASSIGNED, /* M-C */ - /* 196 */ ED_UNASSIGNED, /* M-D */ - /* 197 */ ED_UNASSIGNED, /* M-E */ - /* 198 */ ED_UNASSIGNED, /* M-F */ - /* 199 */ ED_UNASSIGNED, /* M-G */ - /* 200 */ ED_UNASSIGNED, /* M-H */ - /* 201 */ ED_UNASSIGNED, /* M-I */ - /* 202 */ ED_UNASSIGNED, /* M-J */ - /* 203 */ ED_UNASSIGNED, /* M-K */ - /* 204 */ ED_UNASSIGNED, /* M-L */ - /* 205 */ ED_UNASSIGNED, /* M-M */ - /* 206 */ ED_UNASSIGNED, /* M-N */ - /* 207 */ ED_SEQUENCE_LEAD_IN, /* M-O */ - /* 208 */ ED_UNASSIGNED, /* M-P */ - /* 209 */ ED_UNASSIGNED, /* M-Q */ - /* 210 */ ED_UNASSIGNED, /* M-R */ - /* 211 */ ED_UNASSIGNED, /* M-S */ - /* 212 */ ED_UNASSIGNED, /* M-T */ - /* 213 */ ED_UNASSIGNED, /* M-U */ - /* 214 */ ED_UNASSIGNED, /* M-V */ - /* 215 */ ED_UNASSIGNED, /* M-W */ - /* 216 */ ED_UNASSIGNED, /* M-X */ - /* 217 */ ED_UNASSIGNED, /* M-Y */ - /* 218 */ ED_UNASSIGNED, /* M-Z */ - /* 219 */ ED_SEQUENCE_LEAD_IN, /* M-[ */ - /* 220 */ ED_UNASSIGNED, /* M-\ */ - /* 221 */ ED_UNASSIGNED, /* M-] */ - /* 222 */ ED_UNASSIGNED, /* M-^ */ - /* 223 */ ED_UNASSIGNED, /* M-_ */ - /* 224 */ ED_UNASSIGNED, /* M-` */ - /* 225 */ ED_UNASSIGNED, /* M-a */ - /* 226 */ ED_UNASSIGNED, /* M-b */ - /* 227 */ ED_UNASSIGNED, /* M-c */ - /* 228 */ ED_UNASSIGNED, /* M-d */ - /* 229 */ ED_UNASSIGNED, /* M-e */ - /* 230 */ ED_UNASSIGNED, /* M-f */ - /* 231 */ ED_UNASSIGNED, /* M-g */ - /* 232 */ ED_UNASSIGNED, /* M-h */ - /* 233 */ ED_UNASSIGNED, /* M-i */ - /* 234 */ ED_UNASSIGNED, /* M-j */ - /* 235 */ ED_UNASSIGNED, /* M-k */ - /* 236 */ ED_UNASSIGNED, /* M-l */ - /* 237 */ ED_UNASSIGNED, /* M-m */ - /* 238 */ ED_UNASSIGNED, /* M-n */ - /* 239 */ ED_UNASSIGNED, /* M-o */ - /* 240 */ ED_UNASSIGNED, /* M-p */ - /* 241 */ ED_UNASSIGNED, /* M-q */ - /* 242 */ ED_UNASSIGNED, /* M-r */ - /* 243 */ ED_UNASSIGNED, /* M-s */ - /* 244 */ ED_UNASSIGNED, /* M-t */ - /* 245 */ ED_UNASSIGNED, /* M-u */ - /* 246 */ ED_UNASSIGNED, /* M-v */ - /* 247 */ ED_UNASSIGNED, /* M-w */ - /* 248 */ ED_UNASSIGNED, /* M-x */ - /* 249 */ ED_UNASSIGNED, /* M-y */ - /* 250 */ ED_UNASSIGNED, /* M-z */ - /* 251 */ ED_UNASSIGNED, /* M-{ */ - /* 252 */ ED_UNASSIGNED, /* M-| */ - /* 253 */ ED_UNASSIGNED, /* M-} */ - /* 254 */ ED_UNASSIGNED, /* M-~ */ - /* 255 */ ED_UNASSIGNED /* M-^? */ -}; - - -/* map_init(): - * Initialize and allocate the maps - */ -protected int -map_init(EditLine *el) -{ - - /* - * Make sure those are correct before starting. - */ -#ifdef MAP_DEBUG - if (sizeof(el_map_emacs) != N_KEYS * sizeof(el_action_t)) - EL_ABORT((el->errfile, "Emacs map incorrect\n")); - if (sizeof(el_map_vi_command) != N_KEYS * sizeof(el_action_t)) - EL_ABORT((el->errfile, "Vi command map incorrect\n")); - if (sizeof(el_map_vi_insert) != N_KEYS * sizeof(el_action_t)) - EL_ABORT((el->errfile, "Vi insert map incorrect\n")); -#endif - - el->el_map.alt = el_malloc(sizeof(*el->el_map.alt) * N_KEYS); - if (el->el_map.alt == NULL) - return -1; - el->el_map.key = el_malloc(sizeof(*el->el_map.key) * N_KEYS); - if (el->el_map.key == NULL) - return -1; - el->el_map.emacs = el_map_emacs; - el->el_map.vic = el_map_vi_command; - el->el_map.vii = el_map_vi_insert; - el->el_map.help = el_malloc(sizeof(*el->el_map.help) * EL_NUM_FCNS); - if (el->el_map.help == NULL) - return -1; - (void) memcpy(el->el_map.help, help__get(), - sizeof(*el->el_map.help) * EL_NUM_FCNS); - el->el_map.func = el_malloc(sizeof(*el->el_map.func) * EL_NUM_FCNS); - if (el->el_map.func == NULL) - return -1; - memcpy(el->el_map.func, func__get(), sizeof(*el->el_map.func) - * EL_NUM_FCNS); - el->el_map.nfunc = EL_NUM_FCNS; - -#ifdef VIDEFAULT - map_init_vi(el); -#else - map_init_emacs(el); -#endif /* VIDEFAULT */ - return 0; -} - - -/* map_end(): - * Free the space taken by the editor maps - */ -protected void -map_end(EditLine *el) -{ - - el_free(el->el_map.alt); - el->el_map.alt = NULL; - el_free(el->el_map.key); - el->el_map.key = NULL; - el->el_map.emacs = NULL; - el->el_map.vic = NULL; - el->el_map.vii = NULL; - el_free(el->el_map.help); - el->el_map.help = NULL; - el_free(el->el_map.func); - el->el_map.func = NULL; -} - - -/* map_init_nls(): - * Find all the printable keys and bind them to self insert - */ -private void -map_init_nls(EditLine *el) -{ - int i; - - el_action_t *map = el->el_map.key; - - for (i = 0200; i <= 0377; i++) - if (Isprint(i)) - map[i] = ED_INSERT; -} - - -/* map_init_meta(): - * Bind all the meta keys to the appropriate ESC- sequence - */ -private void -map_init_meta(EditLine *el) -{ - Char buf[3]; - int i; - el_action_t *map = el->el_map.key; - el_action_t *alt = el->el_map.alt; - - for (i = 0; i <= 0377 && map[i] != EM_META_NEXT; i++) - continue; - - if (i > 0377) { - for (i = 0; i <= 0377 && alt[i] != EM_META_NEXT; i++) - continue; - if (i > 0377) { - i = 033; - if (el->el_map.type == MAP_VI) - map = alt; - } else - map = alt; - } - buf[0] = (Char) i; - buf[2] = 0; - for (i = 0200; i <= 0377; i++) - switch (map[i]) { - case ED_INSERT: - case ED_UNASSIGNED: - case ED_SEQUENCE_LEAD_IN: - break; - default: - buf[1] = i & 0177; - keymacro_add(el, buf, keymacro_map_cmd(el, (int) map[i]), XK_CMD); - break; - } - map[(int) buf[0]] = ED_SEQUENCE_LEAD_IN; -} - - -/* map_init_vi(): - * Initialize the vi bindings - */ -protected void -map_init_vi(EditLine *el) -{ - int i; - el_action_t *key = el->el_map.key; - el_action_t *alt = el->el_map.alt; - const el_action_t *vii = el->el_map.vii; - const el_action_t *vic = el->el_map.vic; - - el->el_map.type = MAP_VI; - el->el_map.current = el->el_map.key; - - keymacro_reset(el); - - for (i = 0; i < N_KEYS; i++) { - key[i] = vii[i]; - alt[i] = vic[i]; - } - - map_init_meta(el); - map_init_nls(el); - - tty_bind_char(el, 1); - terminal_bind_arrow(el); -} - - -/* map_init_emacs(): - * Initialize the emacs bindings - */ -protected void -map_init_emacs(EditLine *el) -{ - int i; - Char buf[3]; - el_action_t *key = el->el_map.key; - el_action_t *alt = el->el_map.alt; - const el_action_t *emacs = el->el_map.emacs; - - el->el_map.type = MAP_EMACS; - el->el_map.current = el->el_map.key; - keymacro_reset(el); - - for (i = 0; i < N_KEYS; i++) { - key[i] = emacs[i]; - alt[i] = ED_UNASSIGNED; - } - - map_init_meta(el); - map_init_nls(el); - - buf[0] = CONTROL('X'); - buf[1] = CONTROL('X'); - buf[2] = 0; - keymacro_add(el, buf, keymacro_map_cmd(el, EM_EXCHANGE_MARK), XK_CMD); - - tty_bind_char(el, 1); - terminal_bind_arrow(el); -} - - -/* map_set_editor(): - * Set the editor - */ -protected int -map_set_editor(EditLine *el, Char *editor) -{ - - if (Strcmp(editor, STR("emacs")) == 0) { - map_init_emacs(el); - return 0; - } - if (Strcmp(editor, STR("vi")) == 0) { - map_init_vi(el); - return 0; - } - return -1; -} - - -/* map_get_editor(): - * Retrieve the editor - */ -protected int -map_get_editor(EditLine *el, const Char **editor) -{ - - if (editor == NULL) - return -1; - switch (el->el_map.type) { - case MAP_EMACS: - *editor = STR("emacs"); - return 0; - case MAP_VI: - *editor = STR("vi"); - return 0; - } - return -1; -} - - -/* map_print_key(): - * Print the function description for 1 key - */ -private void -map_print_key(EditLine *el, el_action_t *map, const Char *in) -{ - char outbuf[EL_BUFSIZ]; - el_bindings_t *bp, *ep; - - if (in[0] == '\0' || in[1] == '\0') { - (void) keymacro__decode_str(in, outbuf, sizeof(outbuf), ""); - ep = &el->el_map.help[el->el_map.nfunc]; - for (bp = el->el_map.help; bp < ep; bp++) - if (bp->func == map[(unsigned char) *in]) { - (void) fprintf(el->el_outfile, - "%s\t->\t" FSTR "\n", outbuf, bp->name); - return; - } - } else - keymacro_print(el, in); -} - - -/* map_print_some_keys(): - * Print keys from first to last - */ -private void -map_print_some_keys(EditLine *el, el_action_t *map, Int first, Int last) -{ - el_bindings_t *bp, *ep; - Char firstbuf[2], lastbuf[2]; - char unparsbuf[EL_BUFSIZ], extrabuf[EL_BUFSIZ]; - - firstbuf[0] = first; - firstbuf[1] = 0; - lastbuf[0] = last; - lastbuf[1] = 0; - if (map[first] == ED_UNASSIGNED) { - if (first == last) { - (void) keymacro__decode_str(firstbuf, unparsbuf, - sizeof(unparsbuf), STRQQ); - (void) fprintf(el->el_outfile, - "%-15s-> is undefined\n", unparsbuf); - } - return; - } - ep = &el->el_map.help[el->el_map.nfunc]; - for (bp = el->el_map.help; bp < ep; bp++) { - if (bp->func == map[first]) { - if (first == last) { - (void) keymacro__decode_str(firstbuf, unparsbuf, - sizeof(unparsbuf), STRQQ); - (void) fprintf(el->el_outfile, "%-15s-> " FSTR "\n", - unparsbuf, bp->name); - } else { - (void) keymacro__decode_str(firstbuf, unparsbuf, - sizeof(unparsbuf), STRQQ); - (void) keymacro__decode_str(lastbuf, extrabuf, - sizeof(extrabuf), STRQQ); - (void) fprintf(el->el_outfile, - "%-4s to %-7s-> " FSTR "\n", - unparsbuf, extrabuf, bp->name); - } - return; - } - } -#ifdef MAP_DEBUG - if (map == el->el_map.key) { - (void) keymacro__decode_str(firstbuf, unparsbuf, - sizeof(unparsbuf), STRQQ); - (void) fprintf(el->el_outfile, - "BUG!!! %s isn't bound to anything.\n", unparsbuf); - (void) fprintf(el->el_outfile, "el->el_map.key[%d] == %d\n", - first, el->el_map.key[first]); - } else { - (void) keymacro__decode_str(firstbuf, unparsbuf, - sizeof(unparsbuf), STRQQ); - (void) fprintf(el->el_outfile, - "BUG!!! %s isn't bound to anything.\n", unparsbuf); - (void) fprintf(el->el_outfile, "el->el_map.alt[%d] == %d\n", - first, el->el_map.alt[first]); - } -#endif - EL_ABORT((el->el_errfile, "Error printing keys\n")); -} - - -/* map_print_all_keys(): - * Print the function description for all keys. - */ -private void -map_print_all_keys(EditLine *el) -{ - int prev, i; - - (void) fprintf(el->el_outfile, "Standard key bindings\n"); - prev = 0; - for (i = 0; i < N_KEYS; i++) { - if (el->el_map.key[prev] == el->el_map.key[i]) - continue; - map_print_some_keys(el, el->el_map.key, prev, i - 1); - prev = i; - } - map_print_some_keys(el, el->el_map.key, prev, i - 1); - - (void) fprintf(el->el_outfile, "Alternative key bindings\n"); - prev = 0; - for (i = 0; i < N_KEYS; i++) { - if (el->el_map.alt[prev] == el->el_map.alt[i]) - continue; - map_print_some_keys(el, el->el_map.alt, prev, i - 1); - prev = i; - } - map_print_some_keys(el, el->el_map.alt, prev, i - 1); - - (void) fprintf(el->el_outfile, "Multi-character bindings\n"); - keymacro_print(el, STR("")); - (void) fprintf(el->el_outfile, "Arrow key bindings\n"); - terminal_print_arrow(el, STR("")); -} - - -/* map_bind(): - * Add/remove/change bindings - */ -protected int -map_bind(EditLine *el, int argc, const Char **argv) -{ - el_action_t *map; - int ntype, rem; - const Char *p; - Char inbuf[EL_BUFSIZ]; - Char outbuf[EL_BUFSIZ]; - const Char *in = NULL; - Char *out = NULL; - el_bindings_t *bp, *ep; - int cmd; - int key; - - if (argv == NULL) - return -1; - - map = el->el_map.key; - ntype = XK_CMD; - key = rem = 0; - for (argc = 1; (p = argv[argc]) != NULL; argc++) - if (p[0] == '-') - switch (p[1]) { - case 'a': - map = el->el_map.alt; - break; - - case 's': - ntype = XK_STR; - break; -#ifdef notyet - case 'c': - ntype = XK_EXE; - break; -#endif - case 'k': - key = 1; - break; - - case 'r': - rem = 1; - break; - - case 'v': - map_init_vi(el); - return 0; - - case 'e': - map_init_emacs(el); - return 0; - - case 'l': - ep = &el->el_map.help[el->el_map.nfunc]; - for (bp = el->el_map.help; bp < ep; bp++) - (void) fprintf(el->el_outfile, - "" FSTR "\n\t" FSTR "\n", - bp->name, bp->description); - return 0; - default: - (void) fprintf(el->el_errfile, - "" FSTR ": Invalid switch `%c'.\n", - argv[0], (int) p[1]); - } - else - break; - - if (argv[argc] == NULL) { - map_print_all_keys(el); - return 0; - } - if (key) - in = argv[argc++]; - else if ((in = parse__string(inbuf, argv[argc++])) == NULL) { - (void) fprintf(el->el_errfile, - "" FSTR ": Invalid \\ or ^ in instring.\n", - argv[0]); - return -1; - } - if (rem) { - if (key) { - (void) terminal_clear_arrow(el, in); - return -1; - } - if (in[1]) - (void) keymacro_delete(el, in); - else if (map[(unsigned char) *in] == ED_SEQUENCE_LEAD_IN) - (void) keymacro_delete(el, in); - else - map[(unsigned char) *in] = ED_UNASSIGNED; - return 0; - } - if (argv[argc] == NULL) { - if (key) - terminal_print_arrow(el, in); - else - map_print_key(el, map, in); - return 0; - } -#ifdef notyet - if (argv[argc + 1] != NULL) { - bindkeymacro_usage(); - return -1; - } -#endif - - switch (ntype) { - case XK_STR: - case XK_EXE: - if ((out = parse__string(outbuf, argv[argc])) == NULL) { - (void) fprintf(el->el_errfile, - "" FSTR ": Invalid \\ or ^ in outstring.\n", argv[0]); - return -1; - } - if (key) - terminal_set_arrow(el, in, keymacro_map_str(el, out), ntype); - else - keymacro_add(el, in, keymacro_map_str(el, out), ntype); - map[(unsigned char) *in] = ED_SEQUENCE_LEAD_IN; - break; - - case XK_CMD: - if ((cmd = parse_cmd(el, argv[argc])) == -1) { - (void) fprintf(el->el_errfile, - "" FSTR ": Invalid command `" FSTR "'.\n", - argv[0], argv[argc]); - return -1; - } - if (key) - terminal_set_arrow(el, in, keymacro_map_str(el, out), ntype); - else { - if (in[1]) { - keymacro_add(el, in, keymacro_map_cmd(el, cmd), ntype); - map[(unsigned char) *in] = ED_SEQUENCE_LEAD_IN; - } else { - keymacro_clear(el, map, in); - map[(unsigned char) *in] = (el_action_t)cmd; - } - } - break; - - default: - EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype)); - break; - } - return 0; -} - - -/* map_addfunc(): - * add a user defined function - */ -protected int -map_addfunc(EditLine *el, const Char *name, const Char *help, el_func_t func) -{ - void *p; - size_t nf = (size_t)el->el_map.nfunc + 1; - - if (name == NULL || help == NULL || func == NULL) - return -1; - - if ((p = el_realloc(el->el_map.func, nf * - sizeof(*el->el_map.func))) == NULL) - return -1; - el->el_map.func = p; - if ((p = el_realloc(el->el_map.help, nf * sizeof(*el->el_map.help))) - == NULL) - return -1; - el->el_map.help = p; - - nf = (size_t)el->el_map.nfunc; - el->el_map.func[nf] = func; - - el->el_map.help[nf].name = name; - el->el_map.help[nf].func = (int)nf; - el->el_map.help[nf].description = help; - el->el_map.nfunc++; - - return 0; -} diff --git a/cmd-line-utils/libedit/map.h b/cmd-line-utils/libedit/map.h deleted file mode 100644 index 8e0c7e4eaa1..00000000000 --- a/cmd-line-utils/libedit/map.h +++ /dev/null @@ -1,77 +0,0 @@ -/* $NetBSD: map.h,v 1.9 2009/12/30 22:37:40 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)map.h 8.1 (Berkeley) 6/4/93 - */ - -/* - * el.map.h: Editor maps - */ -#ifndef _h_el_map -#define _h_el_map - -typedef struct el_bindings_t { /* for the "bind" shell command */ - const Char *name; /* function name for bind command */ - int func; /* function numeric value */ - const Char *description; /* description of function */ -} el_bindings_t; - - -typedef struct el_map_t { - el_action_t *alt; /* The current alternate key map */ - el_action_t *key; /* The current normal key map */ - el_action_t *current; /* The keymap we are using */ - const el_action_t *emacs; /* The default emacs key map */ - const el_action_t *vic; /* The vi command mode key map */ - const el_action_t *vii; /* The vi insert mode key map */ - int type; /* Emacs or vi */ - el_bindings_t *help; /* The help for the editor functions */ - el_func_t *func; /* List of available functions */ - int nfunc; /* The number of functions/help items */ -} el_map_t; - -#define MAP_EMACS 0 -#define MAP_VI 1 - -#define N_KEYS 256 - -protected int map_bind(EditLine *, int, const Char **); -protected int map_init(EditLine *); -protected void map_end(EditLine *); -protected void map_init_vi(EditLine *); -protected void map_init_emacs(EditLine *); -protected int map_set_editor(EditLine *, Char *); -protected int map_get_editor(EditLine *, const Char **); -protected int map_addfunc(EditLine *, const Char *, const Char *, el_func_t); - -#endif /* _h_el_map */ diff --git a/cmd-line-utils/libedit/np/fgetln.c b/cmd-line-utils/libedit/np/fgetln.c deleted file mode 100644 index 898abc758dc..00000000000 --- a/cmd-line-utils/libedit/np/fgetln.c +++ /dev/null @@ -1,108 +0,0 @@ -/* $NetBSD: fgetln.c,v 1.9 2008/04/29 06:53:03 martin Exp $ */ - -/*- - * Copyright (c) 1998 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Christos Zoulas. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_NBTOOL_CONFIG_H -#include "nbtool_config.h" -#else -#include "config.h" -#endif - -#if !HAVE_FGETLN -#include -#ifndef HAVE_NBTOOL_CONFIG_H -/* These headers are required, but included from nbtool_config.h */ -#include -#include -#include -#include -#endif - -char * -fgetln(FILE *fp, size_t *len) -{ - static char *buf = NULL; - static size_t bufsiz = 0; - char *ptr; - - - if (buf == NULL) { - bufsiz = BUFSIZ; - if ((buf = malloc(bufsiz)) == NULL) - return NULL; - } - - if (fgets(buf, bufsiz, fp) == NULL) - return NULL; - - *len = 0; - while ((ptr = strchr(&buf[*len], '\n')) == NULL) { - size_t nbufsiz = bufsiz + BUFSIZ; - char *nbuf = realloc(buf, nbufsiz); - - if (nbuf == NULL) { - int oerrno = errno; - free(buf); - errno = oerrno; - buf = NULL; - return NULL; - } else - buf = nbuf; - - if (fgets(&buf[bufsiz], BUFSIZ, fp) == NULL) { - buf[bufsiz] = '\0'; - *len = strlen(buf); - return buf; - } - - *len = bufsiz; - bufsiz = nbufsiz; - } - - *len = (ptr - buf) + 1; - return buf; -} - -#endif - -#ifdef TEST -int -main(int argc, char *argv[]) -{ - char *p; - size_t len; - - while ((p = fgetln(stdin, &len)) != NULL) { - (void)printf("%zu %s", len, p); - free(p); - } - return 0; -} -#endif diff --git a/cmd-line-utils/libedit/np/strlcat.c b/cmd-line-utils/libedit/np/strlcat.c deleted file mode 100644 index 4e2897d8f35..00000000000 --- a/cmd-line-utils/libedit/np/strlcat.c +++ /dev/null @@ -1,85 +0,0 @@ -/* $NetBSD: strlcat.c,v 1.3 2007/06/04 18:19:27 christos Exp $ */ -/* $OpenBSD: strlcat.c,v 1.10 2003/04/12 21:56:39 millert Exp $ */ - -/* - * Copyright (c) 1998 Todd C. Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE - * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#if !defined(_KERNEL) && !defined(_STANDALONE) -#if HAVE_NBTOOL_CONFIG_H -#include "nbtool_config.h" -#else -#include "config.h" -#endif - -#if defined(LIBC_SCCS) && !defined(lint) -#endif /* LIBC_SCCS and not lint */ - -#ifdef _LIBC -#include "namespace.h" -#endif -#include -#include -#include - -#ifdef _LIBC -# ifdef __weak_alias -__weak_alias(strlcat, _strlcat) -# endif -#endif - -#else -#include -#endif /* !_KERNEL && !_STANDALONE */ - -#if !HAVE_STRLCAT -/* - * Appends src to string dst of size siz (unlike strncat, siz is the - * full size of dst, not space left). At most siz-1 characters - * will be copied. Always NUL terminates (unless siz <= strlen(dst)). - * Returns strlen(src) + MIN(siz, strlen(initial dst)). - * If retval >= siz, truncation occurred. - */ -size_t -strlcat(char *dst, const char *src, size_t siz) -{ - char *d = dst; - const char *s = src; - size_t n = siz; - size_t dlen; - - _DIAGASSERT(dst != NULL); - _DIAGASSERT(src != NULL); - - /* Find the end of dst and adjust bytes left but don't go past end */ - while (n-- != 0 && *d != '\0') - d++; - dlen = d - dst; - n = siz - dlen; - - if (n == 0) - return(dlen + strlen(s)); - while (*s != '\0') { - if (n != 1) { - *d++ = *s; - n--; - } - s++; - } - *d = '\0'; - - return(dlen + (s - src)); /* count does not include NUL */ -} -#endif diff --git a/cmd-line-utils/libedit/np/strlcpy.c b/cmd-line-utils/libedit/np/strlcpy.c deleted file mode 100644 index ccbe6812dfc..00000000000 --- a/cmd-line-utils/libedit/np/strlcpy.c +++ /dev/null @@ -1,81 +0,0 @@ -/* $NetBSD: strlcpy.c,v 1.3 2007/06/04 18:19:27 christos Exp $ */ -/* $OpenBSD: strlcpy.c,v 1.7 2003/04/12 21:56:39 millert Exp $ */ - -/* - * Copyright (c) 1998 Todd C. Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE - * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#if !defined(_KERNEL) && !defined(_STANDALONE) -#if HAVE_NBTOOL_CONFIG_H -#include "nbtool_config.h" -#else -#include "config.h" -#endif - -#if defined(LIBC_SCCS) && !defined(lint) -#endif /* LIBC_SCCS and not lint */ - -#ifdef _LIBC -#include "namespace.h" -#endif -#include -#include -#include - -#ifdef _LIBC -# ifdef __weak_alias -__weak_alias(strlcpy, _strlcpy) -# endif -#endif -#else -#include -#endif /* !_KERNEL && !_STANDALONE */ - - -#if !HAVE_STRLCPY -/* - * Copy src to string dst of size siz. At most siz-1 characters - * will be copied. Always NUL terminates (unless siz == 0). - * Returns strlen(src); if retval >= siz, truncation occurred. - */ -size_t -strlcpy(char *dst, const char *src, size_t siz) -{ - char *d = dst; - const char *s = src; - size_t n = siz; - - _DIAGASSERT(dst != NULL); - _DIAGASSERT(src != NULL); - - /* Copy as many bytes as will fit */ - if (n != 0 && --n != 0) { - do { - if ((*d++ = *s++) == 0) - break; - } while (--n != 0); - } - - /* Not enough room in dst, add NUL and traverse rest of src */ - if (n == 0) { - if (siz != 0) - *d = '\0'; /* NUL-terminate dst */ - while (*s++) - ; - } - - return(s - src - 1); /* count does not include NUL */ -} -#endif diff --git a/cmd-line-utils/libedit/np/unvis.c b/cmd-line-utils/libedit/np/unvis.c deleted file mode 100644 index a911720ad35..00000000000 --- a/cmd-line-utils/libedit/np/unvis.c +++ /dev/null @@ -1,560 +0,0 @@ -/* $NetBSD: unvis.c,v 1.36 2011/03/18 09:07:20 martin Exp $ */ - -/*- - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" - -#if defined(LIBC_SCCS) && !defined(lint) -#if 0 -static char sccsid[] = "@(#)unvis.c 8.1 (Berkeley) 6/4/93"; -#else -#endif -#endif /* LIBC_SCCS and not lint */ - -/* XXXMYSQL : Make compiler happy. */ -#ifdef _LIBC -#include "namespace.h" -#endif - -#include - -#include -#include - -/* XXXMYSQL : stdint.h might not be available on older Solaris platforms. */ -#if defined(__sun) || defined(__sun__) -#include -#else -#include -#endif - -#include -#include -/* - XXXMYSQL : Due to different versions of vis.h available, - use the one bundled with libedit. -*/ -#include "np/vis.h" - -#ifdef __weak_alias -__weak_alias(strnunvisx,_strnunvisx); -#endif - -#if !HAVE_VIS -/* - * decode driven by state machine - */ -#define S_GROUND 0 /* haven't seen escape char */ -#define S_START 1 /* start decoding special sequence */ -#define S_META 2 /* metachar started (M) */ -#define S_META1 3 /* metachar more, regular char (-) */ -#define S_CTRL 4 /* control char started (^) */ -#define S_OCTAL2 5 /* octal digit 2 */ -#define S_OCTAL3 6 /* octal digit 3 */ -#define S_HEX1 7 /* http hex digit */ -#define S_HEX2 8 /* http hex digit 2 */ -#define S_MIME1 9 /* mime hex digit 1 */ -#define S_MIME2 10 /* mime hex digit 2 */ -#define S_EATCRNL 11 /* mime eating CRNL */ -#define S_AMP 12 /* seen & */ -#define S_NUMBER 13 /* collecting number */ -#define S_STRING 14 /* collecting string */ - -#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') -#define xtod(c) (isdigit(c) ? (c - '0') : ((tolower(c) - 'a') + 10)) -#define XTOD(c) (isdigit(c) ? (c - '0') : ((c - 'A') + 10)) - -/* - * RFC 1866 - */ -static const struct nv { - const char *name; - uint8_t value; -} nv[] = { - { "AElig", 198 }, /* capital AE diphthong (ligature) */ - { "Aacute", 193 }, /* capital A, acute accent */ - { "Acirc", 194 }, /* capital A, circumflex accent */ - { "Agrave", 192 }, /* capital A, grave accent */ - { "Aring", 197 }, /* capital A, ring */ - { "Atilde", 195 }, /* capital A, tilde */ - { "Auml", 196 }, /* capital A, dieresis or umlaut mark */ - { "Ccedil", 199 }, /* capital C, cedilla */ - { "ETH", 208 }, /* capital Eth, Icelandic */ - { "Eacute", 201 }, /* capital E, acute accent */ - { "Ecirc", 202 }, /* capital E, circumflex accent */ - { "Egrave", 200 }, /* capital E, grave accent */ - { "Euml", 203 }, /* capital E, dieresis or umlaut mark */ - { "Iacute", 205 }, /* capital I, acute accent */ - { "Icirc", 206 }, /* capital I, circumflex accent */ - { "Igrave", 204 }, /* capital I, grave accent */ - { "Iuml", 207 }, /* capital I, dieresis or umlaut mark */ - { "Ntilde", 209 }, /* capital N, tilde */ - { "Oacute", 211 }, /* capital O, acute accent */ - { "Ocirc", 212 }, /* capital O, circumflex accent */ - { "Ograve", 210 }, /* capital O, grave accent */ - { "Oslash", 216 }, /* capital O, slash */ - { "Otilde", 213 }, /* capital O, tilde */ - { "Ouml", 214 }, /* capital O, dieresis or umlaut mark */ - { "THORN", 222 }, /* capital THORN, Icelandic */ - { "Uacute", 218 }, /* capital U, acute accent */ - { "Ucirc", 219 }, /* capital U, circumflex accent */ - { "Ugrave", 217 }, /* capital U, grave accent */ - { "Uuml", 220 }, /* capital U, dieresis or umlaut mark */ - { "Yacute", 221 }, /* capital Y, acute accent */ - { "aacute", 225 }, /* small a, acute accent */ - { "acirc", 226 }, /* small a, circumflex accent */ - { "acute", 180 }, /* acute accent */ - { "aelig", 230 }, /* small ae diphthong (ligature) */ - { "agrave", 224 }, /* small a, grave accent */ - { "amp", 38 }, /* ampersand */ - { "aring", 229 }, /* small a, ring */ - { "atilde", 227 }, /* small a, tilde */ - { "auml", 228 }, /* small a, dieresis or umlaut mark */ - { "brvbar", 166 }, /* broken (vertical) bar */ - { "ccedil", 231 }, /* small c, cedilla */ - { "cedil", 184 }, /* cedilla */ - { "cent", 162 }, /* cent sign */ - { "copy", 169 }, /* copyright sign */ - { "curren", 164 }, /* general currency sign */ - { "deg", 176 }, /* degree sign */ - { "divide", 247 }, /* divide sign */ - { "eacute", 233 }, /* small e, acute accent */ - { "ecirc", 234 }, /* small e, circumflex accent */ - { "egrave", 232 }, /* small e, grave accent */ - { "eth", 240 }, /* small eth, Icelandic */ - { "euml", 235 }, /* small e, dieresis or umlaut mark */ - { "frac12", 189 }, /* fraction one-half */ - { "frac14", 188 }, /* fraction one-quarter */ - { "frac34", 190 }, /* fraction three-quarters */ - { "gt", 62 }, /* greater than */ - { "iacute", 237 }, /* small i, acute accent */ - { "icirc", 238 }, /* small i, circumflex accent */ - { "iexcl", 161 }, /* inverted exclamation mark */ - { "igrave", 236 }, /* small i, grave accent */ - { "iquest", 191 }, /* inverted question mark */ - { "iuml", 239 }, /* small i, dieresis or umlaut mark */ - { "laquo", 171 }, /* angle quotation mark, left */ - { "lt", 60 }, /* less than */ - { "macr", 175 }, /* macron */ - { "micro", 181 }, /* micro sign */ - { "middot", 183 }, /* middle dot */ - { "nbsp", 160 }, /* no-break space */ - { "not", 172 }, /* not sign */ - { "ntilde", 241 }, /* small n, tilde */ - { "oacute", 243 }, /* small o, acute accent */ - { "ocirc", 244 }, /* small o, circumflex accent */ - { "ograve", 242 }, /* small o, grave accent */ - { "ordf", 170 }, /* ordinal indicator, feminine */ - { "ordm", 186 }, /* ordinal indicator, masculine */ - { "oslash", 248 }, /* small o, slash */ - { "otilde", 245 }, /* small o, tilde */ - { "ouml", 246 }, /* small o, dieresis or umlaut mark */ - { "para", 182 }, /* pilcrow (paragraph sign) */ - { "plusmn", 177 }, /* plus-or-minus sign */ - { "pound", 163 }, /* pound sterling sign */ - { "quot", 34 }, /* double quote */ - { "raquo", 187 }, /* angle quotation mark, right */ - { "reg", 174 }, /* registered sign */ - { "sect", 167 }, /* section sign */ - { "shy", 173 }, /* soft hyphen */ - { "sup1", 185 }, /* superscript one */ - { "sup2", 178 }, /* superscript two */ - { "sup3", 179 }, /* superscript three */ - { "szlig", 223 }, /* small sharp s, German (sz ligature) */ - { "thorn", 254 }, /* small thorn, Icelandic */ - { "times", 215 }, /* multiply sign */ - { "uacute", 250 }, /* small u, acute accent */ - { "ucirc", 251 }, /* small u, circumflex accent */ - { "ugrave", 249 }, /* small u, grave accent */ - { "uml", 168 }, /* umlaut (dieresis) */ - { "uuml", 252 }, /* small u, dieresis or umlaut mark */ - { "yacute", 253 }, /* small y, acute accent */ - { "yen", 165 }, /* yen sign */ - { "yuml", 255 }, /* small y, dieresis or umlaut mark */ -}; - -/* - * unvis - decode characters previously encoded by vis - */ -int -unvis(char *cp, int c, int *astate, int flag) -{ - unsigned char uc = (unsigned char)c; - unsigned char st, ia, is, lc; - -/* - * Bottom 8 bits of astate hold the state machine state. - * Top 8 bits hold the current character in the http 1866 nv string decoding - */ -#define GS(a) ((a) & 0xff) -#define SS(a, b) (((uint32_t)(a) << 24) | (b)) -#define GI(a) ((uint32_t)(a) >> 24) - - _DIAGASSERT(cp != NULL); - _DIAGASSERT(astate != NULL); - st = GS(*astate); - - if (flag & UNVIS_END) { - switch (st) { - case S_OCTAL2: - case S_OCTAL3: - case S_HEX2: - *astate = SS(0, S_GROUND); - return UNVIS_VALID; - case S_GROUND: - return UNVIS_NOCHAR; - default: - return UNVIS_SYNBAD; - } - } - - switch (st) { - - case S_GROUND: - *cp = 0; - if ((flag & VIS_NOESCAPE) == 0 && c == '\\') { - *astate = SS(0, S_START); - return UNVIS_NOCHAR; - } - if ((flag & VIS_HTTP1808) && c == '%') { - *astate = SS(0, S_HEX1); - return UNVIS_NOCHAR; - } - if ((flag & VIS_HTTP1866) && c == '&') { - *astate = SS(0, S_AMP); - return UNVIS_NOCHAR; - } - if ((flag & VIS_MIMESTYLE) && c == '=') { - *astate = SS(0, S_MIME1); - return UNVIS_NOCHAR; - } - *cp = c; - return UNVIS_VALID; - - case S_START: - switch(c) { - case '\\': - *cp = c; - *astate = SS(0, S_GROUND); - return UNVIS_VALID; - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - *cp = (c - '0'); - *astate = SS(0, S_OCTAL2); - return UNVIS_NOCHAR; - case 'M': - *cp = (char)0200; - *astate = SS(0, S_META); - return UNVIS_NOCHAR; - case '^': - *astate = SS(0, S_CTRL); - return UNVIS_NOCHAR; - case 'n': - *cp = '\n'; - *astate = SS(0, S_GROUND); - return UNVIS_VALID; - case 'r': - *cp = '\r'; - *astate = SS(0, S_GROUND); - return UNVIS_VALID; - case 'b': - *cp = '\b'; - *astate = SS(0, S_GROUND); - return UNVIS_VALID; - case 'a': - *cp = '\007'; - *astate = SS(0, S_GROUND); - return UNVIS_VALID; - case 'v': - *cp = '\v'; - *astate = SS(0, S_GROUND); - return UNVIS_VALID; - case 't': - *cp = '\t'; - *astate = SS(0, S_GROUND); - return UNVIS_VALID; - case 'f': - *cp = '\f'; - *astate = SS(0, S_GROUND); - return UNVIS_VALID; - case 's': - *cp = ' '; - *astate = SS(0, S_GROUND); - return UNVIS_VALID; - case 'E': - *cp = '\033'; - *astate = SS(0, S_GROUND); - return UNVIS_VALID; - case '\n': - /* - * hidden newline - */ - *astate = SS(0, S_GROUND); - return UNVIS_NOCHAR; - case '$': - /* - * hidden marker - */ - *astate = SS(0, S_GROUND); - return UNVIS_NOCHAR; - } - goto bad; - - case S_META: - if (c == '-') - *astate = SS(0, S_META1); - else if (c == '^') - *astate = SS(0, S_CTRL); - else - goto bad; - return UNVIS_NOCHAR; - - case S_META1: - *astate = SS(0, S_GROUND); - *cp |= c; - return UNVIS_VALID; - - case S_CTRL: - if (c == '?') - *cp |= 0177; - else - *cp |= c & 037; - *astate = SS(0, S_GROUND); - return UNVIS_VALID; - - case S_OCTAL2: /* second possible octal digit */ - if (isoctal(uc)) { - /* - * yes - and maybe a third - */ - *cp = (*cp << 3) + (c - '0'); - *astate = SS(0, S_OCTAL3); - return UNVIS_NOCHAR; - } - /* - * no - done with current sequence, push back passed char - */ - *astate = SS(0, S_GROUND); - return UNVIS_VALIDPUSH; - - case S_OCTAL3: /* third possible octal digit */ - *astate = SS(0, S_GROUND); - if (isoctal(uc)) { - *cp = (*cp << 3) + (c - '0'); - return UNVIS_VALID; - } - /* - * we were done, push back passed char - */ - return UNVIS_VALIDPUSH; - - case S_HEX1: - if (isxdigit(uc)) { - *cp = xtod(uc); - *astate = SS(0, S_HEX2); - return UNVIS_NOCHAR; - } - /* - * no - done with current sequence, push back passed char - */ - *astate = SS(0, S_GROUND); - return UNVIS_VALIDPUSH; - - case S_HEX2: - *astate = S_GROUND; - if (isxdigit(uc)) { - *cp = xtod(uc) | (*cp << 4); - return UNVIS_VALID; - } - return UNVIS_VALIDPUSH; - - case S_MIME1: - if (uc == '\n' || uc == '\r') { - *astate = SS(0, S_EATCRNL); - return UNVIS_NOCHAR; - } - if (isxdigit(uc) && (isdigit(uc) || isupper(uc))) { - *cp = XTOD(uc); - *astate = SS(0, S_MIME2); - return UNVIS_NOCHAR; - } - goto bad; - - case S_MIME2: - if (isxdigit(uc) && (isdigit(uc) || isupper(uc))) { - *astate = SS(0, S_GROUND); - *cp = XTOD(uc) | (*cp << 4); - return UNVIS_VALID; - } - goto bad; - - case S_EATCRNL: - switch (uc) { - case '\r': - case '\n': - return UNVIS_NOCHAR; - case '=': - *astate = SS(0, S_MIME1); - return UNVIS_NOCHAR; - default: - *cp = uc; - *astate = SS(0, S_GROUND); - return UNVIS_VALID; - } - - case S_AMP: - *cp = 0; - if (uc == '#') { - *astate = SS(0, S_NUMBER); - return UNVIS_NOCHAR; - } - *astate = SS(0, S_STRING); - /*FALLTHROUGH*/ - - case S_STRING: - ia = *cp; /* index in the array */ - is = GI(*astate); /* index in the string */ - lc = is == 0 ? 0 : nv[ia].name[is - 1]; /* last character */ - - if (uc == ';') - uc = '\0'; - - for (; ia < __arraycount(nv); ia++) { - if (is != 0 && nv[ia].name[is - 1] != lc) - goto bad; - if (nv[ia].name[is] == uc) - break; - } - - if (ia == __arraycount(nv)) - goto bad; - - if (uc != 0) { - *cp = ia; - *astate = SS(is + 1, S_STRING); - return UNVIS_NOCHAR; - } - - *cp = nv[ia].value; - *astate = SS(0, S_GROUND); - return UNVIS_VALID; - - case S_NUMBER: - if (uc == ';') - return UNVIS_VALID; - if (!isdigit(uc)) - goto bad; - *cp += (*cp * 10) + uc - '0'; - return UNVIS_NOCHAR; - - default: - bad: - /* - * decoder in unknown state - (probably uninitialized) - */ - *astate = SS(0, S_GROUND); - return UNVIS_SYNBAD; - } -} - -/* - * strnunvisx - decode src into dst - * - * Number of chars decoded into dst is returned, -1 on error. - * Dst is null terminated. - */ - -int -strnunvisx(char *dst, size_t dlen, const char *src, int flag) -{ - char c; - char t, *start = dst; - int state = 0; - - _DIAGASSERT(src != NULL); - _DIAGASSERT(dst != NULL); -#define CHECKSPACE() \ - do { \ - if (dlen-- == 0) { \ - errno = ENOSPC; \ - return -1; \ - } \ - } while (/*CONSTCOND*/0) - - while ((c = *src++) != '\0') { - again: - switch (unvis(&t, c, &state, flag)) { - case UNVIS_VALID: - CHECKSPACE(); - *dst++ = t; - break; - case UNVIS_VALIDPUSH: - CHECKSPACE(); - *dst++ = t; - goto again; - case 0: - case UNVIS_NOCHAR: - break; - case UNVIS_SYNBAD: - errno = EINVAL; - return -1; - default: - _DIAGASSERT(0); - errno = EINVAL; - return -1; - } - } - if (unvis(&t, c, &state, UNVIS_END) == UNVIS_VALID) { - CHECKSPACE(); - *dst++ = t; - } - CHECKSPACE(); - *dst = '\0'; - return (int)(dst - start); -} - -int -strunvisx(char *dst, const char *src, int flag) -{ - return strnunvisx(dst, (size_t)~0, src, flag); -} - -int -strunvis(char *dst, const char *src) -{ - return strnunvisx(dst, (size_t)~0, src, 0); -} - -int -strnunvis(char *dst, size_t dlen, const char *src) -{ - return strnunvisx(dst, dlen, src, 0); -} -#endif diff --git a/cmd-line-utils/libedit/np/vis.c b/cmd-line-utils/libedit/np/vis.c deleted file mode 100644 index 884a7894332..00000000000 --- a/cmd-line-utils/libedit/np/vis.c +++ /dev/null @@ -1,582 +0,0 @@ -/* $NetBSD: vis.c,v 1.44 2011/03/12 19:52:48 christos Exp $ */ - -/*- - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/*- - * Copyright (c) 1999, 2005 The NetBSD Foundation, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#if defined(LIBC_SCCS) && !defined(lint) -#endif /* LIBC_SCCS and not lint */ - -/* XXXMYSQL : Make compiler happy. */ -#ifdef _LIBC -#include "namespace.h" -#endif - -#include - -#include -/* - XXXMYSQL : Due to different versions of vis.h available, - use the one bundled with libedit. -*/ -#include "np/vis.h" -#include -#include - -#ifdef __weak_alias -__weak_alias(strvisx,_strvisx); -#endif - -#if !HAVE_VIS || !HAVE_SVIS -#include -#include -#include -#include - -static char *do_svis(char *, size_t *, int, int, int, const char *); - -#undef BELL -#define BELL '\a' - -#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') -#define iswhite(c) (c == ' ' || c == '\t' || c == '\n') -#define issafe(c) (c == '\b' || c == BELL || c == '\r') -#define xtoa(c) "0123456789abcdef"[c] -#define XTOA(c) "0123456789ABCDEF"[c] - -#define MAXEXTRAS 5 - -#define MAKEEXTRALIST(flag, extra, orig_str) \ -do { \ - const char *orig = orig_str; \ - const char *o = orig; \ - char *e; \ - while (*o++) \ - continue; \ - extra = malloc((size_t)((o - orig) + MAXEXTRAS)); \ - if (!extra) break; \ - for (o = orig, e = extra; (*e++ = *o++) != '\0';) \ - continue; \ - e--; \ - if (flag & VIS_SP) *e++ = ' '; \ - if (flag & VIS_TAB) *e++ = '\t'; \ - if (flag & VIS_NL) *e++ = '\n'; \ - if ((flag & VIS_NOSLASH) == 0) *e++ = '\\'; \ - *e = '\0'; \ -} while (/*CONSTCOND*/0) - -/* - * This is do_hvis, for HTTP style (RFC 1808) - */ -static char * -do_hvis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra) -{ - - if ((isascii(c) && isalnum(c)) - /* safe */ - || c == '$' || c == '-' || c == '_' || c == '.' || c == '+' - /* extra */ - || c == '!' || c == '*' || c == '\'' || c == '(' || c == ')' - || c == ',') { - dst = do_svis(dst, dlen, c, flag, nextc, extra); - } else { - if (dlen) { - if (*dlen < 3) - return NULL; - *dlen -= 3; - } - *dst++ = '%'; - *dst++ = xtoa(((unsigned int)c >> 4) & 0xf); - *dst++ = xtoa((unsigned int)c & 0xf); - } - - return dst; -} - -/* - * This is do_mvis, for Quoted-Printable MIME (RFC 2045) - * NB: No handling of long lines or CRLF. - */ -static char * -do_mvis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra) -{ - if ((c != '\n') && - /* Space at the end of the line */ - ((isspace(c) && (nextc == '\r' || nextc == '\n')) || - /* Out of range */ - (!isspace(c) && (c < 33 || (c > 60 && c < 62) || c > 126)) || - /* Specific char to be escaped */ - strchr("#$@[\\]^`{|}~", c) != NULL)) { - if (dlen) { - if (*dlen < 3) - return NULL; - *dlen -= 3; - } - *dst++ = '='; - *dst++ = XTOA(((unsigned int)c >> 4) & 0xf); - *dst++ = XTOA((unsigned int)c & 0xf); - } else { - dst = do_svis(dst, dlen, c, flag, nextc, extra); - } - return dst; -} - -/* - * This is do_vis, the central code of vis. - * dst: Pointer to the destination buffer - * c: Character to encode - * flag: Flag word - * nextc: The character following 'c' - * extra: Pointer to the list of extra characters to be - * backslash-protected. - */ -static char * -do_svis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra) -{ - int isextra; - size_t odlen = dlen ? *dlen : 0; - - isextra = strchr(extra, c) != NULL; -#define HAVE(x) \ - do { \ - if (dlen) { \ - if (*dlen < (x)) \ - goto out; \ - *dlen -= (x); \ - } \ - } while (/*CONSTCOND*/0) - if (!isextra && isascii(c) && (isgraph(c) || iswhite(c) || - ((flag & VIS_SAFE) && issafe(c)))) { - HAVE(1); - *dst++ = c; - return dst; - } - if (flag & VIS_CSTYLE) { - HAVE(2); - switch (c) { - case '\n': - *dst++ = '\\'; *dst++ = 'n'; - return dst; - case '\r': - *dst++ = '\\'; *dst++ = 'r'; - return dst; - case '\b': - *dst++ = '\\'; *dst++ = 'b'; - return dst; - case BELL: - *dst++ = '\\'; *dst++ = 'a'; - return dst; - case '\v': - *dst++ = '\\'; *dst++ = 'v'; - return dst; - case '\t': - *dst++ = '\\'; *dst++ = 't'; - return dst; - case '\f': - *dst++ = '\\'; *dst++ = 'f'; - return dst; - case ' ': - *dst++ = '\\'; *dst++ = 's'; - return dst; - case '\0': - *dst++ = '\\'; *dst++ = '0'; - if (isoctal(nextc)) { - HAVE(2); - *dst++ = '0'; - *dst++ = '0'; - } - return dst; - default: - if (isgraph(c)) { - *dst++ = '\\'; *dst++ = c; - return dst; - } - if (dlen) - *dlen = odlen; - } - } - if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) { - HAVE(4); - *dst++ = '\\'; - *dst++ = (u_char)(((u_int32_t)(u_char)c >> 6) & 03) + '0'; - *dst++ = (u_char)(((u_int32_t)(u_char)c >> 3) & 07) + '0'; - *dst++ = (c & 07) + '0'; - } else { - if ((flag & VIS_NOSLASH) == 0) { - HAVE(1); - *dst++ = '\\'; - } - - if (c & 0200) { - HAVE(1); - c &= 0177; *dst++ = 'M'; - } - - if (iscntrl(c)) { - HAVE(2); - *dst++ = '^'; - if (c == 0177) - *dst++ = '?'; - else - *dst++ = c + '@'; - } else { - HAVE(2); - *dst++ = '-'; *dst++ = c; - } - } - return dst; -out: - *dlen = odlen; - return NULL; -} - -typedef char *(*visfun_t)(char *, size_t *, int, int, int, const char *); - -/* - * Return the appropriate encoding function depending on the flags given. - */ -static visfun_t -getvisfun(int flag) -{ - if (flag & VIS_HTTPSTYLE) - return do_hvis; - if (flag & VIS_MIMESTYLE) - return do_mvis; - return do_svis; -} - -/* - * isnvis - visually encode characters, also encoding the characters - * pointed to by `extra' - */ -static char * -isnvis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra) -{ - char *nextra = NULL; - visfun_t f; - - _DIAGASSERT(dst != NULL); - _DIAGASSERT(extra != NULL); - MAKEEXTRALIST(flag, nextra, extra); - if (!nextra) { - if (dlen && *dlen == 0) { - errno = ENOSPC; - return NULL; - } - *dst = '\0'; /* can't create nextra, return "" */ - return dst; - } - f = getvisfun(flag); - dst = (*f)(dst, dlen, c, flag, nextc, nextra); - free(nextra); - if (dst == NULL || (dlen && *dlen == 0)) { - errno = ENOSPC; - return NULL; - } - *dst = '\0'; - return dst; -} - -char * -svis(char *dst, int c, int flag, int nextc, const char *extra) -{ - return isnvis(dst, NULL, c, flag, nextc, extra); -} - -char * -snvis(char *dst, size_t dlen, int c, int flag, int nextc, const char *extra) -{ - return isnvis(dst, &dlen, c, flag, nextc, extra); -} - - -/* - * strsvis, strsvisx - visually encode characters from src into dst - * - * Extra is a pointer to a \0-terminated list of characters to - * be encoded, too. These functions are useful e. g. to - * encode strings in such a way so that they are not interpreted - * by a shell. - * - * Dst must be 4 times the size of src to account for possible - * expansion. The length of dst, not including the trailing NULL, - * is returned. - * - * Strsvisx encodes exactly len bytes from src into dst. - * This is useful for encoding a block of data. - */ -static int -istrsnvis(char *dst, size_t *dlen, const char *csrc, int flag, const char *extra) -{ - int c; - char *start; - char *nextra = NULL; - const unsigned char *src = (const unsigned char *)csrc; - visfun_t f; - - _DIAGASSERT(dst != NULL); - _DIAGASSERT(src != NULL); - _DIAGASSERT(extra != NULL); - MAKEEXTRALIST(flag, nextra, extra); - if (!nextra) { - *dst = '\0'; /* can't create nextra, return "" */ - return 0; - } - f = getvisfun(flag); - for (start = dst; (c = *src++) != '\0'; /* empty */) { - dst = (*f)(dst, dlen, c, flag, *src, nextra); - if (dst == NULL) { - errno = ENOSPC; - return -1; - } - } - free(nextra); - if (dlen && *dlen == 0) { - errno = ENOSPC; - return -1; - } - *dst = '\0'; - return (int)(dst - start); -} - -int -strsvis(char *dst, const char *csrc, int flag, const char *extra) -{ - return istrsnvis(dst, NULL, csrc, flag, extra); -} - -int -strsnvis(char *dst, size_t dlen, const char *csrc, int flag, const char *extra) -{ - return istrsnvis(dst, &dlen, csrc, flag, extra); -} - -static int -istrsnvisx(char *dst, size_t *dlen, const char *csrc, size_t len, int flag, - const char *extra) -{ - unsigned char c; - char *start; - char *nextra = NULL; - const unsigned char *src = (const unsigned char *)csrc; - visfun_t f; - - _DIAGASSERT(dst != NULL); - _DIAGASSERT(src != NULL); - _DIAGASSERT(extra != NULL); - MAKEEXTRALIST(flag, nextra, extra); - if (! nextra) { - if (dlen && *dlen == 0) { - errno = ENOSPC; - return -1; - } - *dst = '\0'; /* can't create nextra, return "" */ - return 0; - } - - f = getvisfun(flag); - for (start = dst; len > 0; len--) { - c = *src++; - dst = (*f)(dst, dlen, c, flag, len > 1 ? *src : '\0', nextra); - if (dst == NULL) { - errno = ENOSPC; - return -1; - } - } - free(nextra); - if (dlen && *dlen == 0) { - errno = ENOSPC; - return -1; - } - *dst = '\0'; - return (int)(dst - start); -} - -int -strsvisx(char *dst, const char *csrc, size_t len, int flag, const char *extra) -{ - return istrsnvisx(dst, NULL, csrc, len, flag, extra); -} - -int -strsnvisx(char *dst, size_t dlen, const char *csrc, size_t len, int flag, - const char *extra) -{ - return istrsnvisx(dst, &dlen, csrc, len, flag, extra); -} -#endif - -#if !HAVE_VIS -/* - * vis - visually encode characters - */ -static char * -invis(char *dst, size_t *dlen, int c, int flag, int nextc) -{ - char *extra = NULL; - unsigned char uc = (unsigned char)c; - visfun_t f; - - _DIAGASSERT(dst != NULL); - - MAKEEXTRALIST(flag, extra, ""); - if (! extra) { - if (dlen && *dlen == 0) { - errno = ENOSPC; - return NULL; - } - *dst = '\0'; /* can't create extra, return "" */ - return dst; - } - f = getvisfun(flag); - dst = (*f)(dst, dlen, uc, flag, nextc, extra); - free(extra); - if (dst == NULL || (dlen && *dlen == 0)) { - errno = ENOSPC; - return NULL; - } - *dst = '\0'; - return dst; -} - -char * -vis(char *dst, int c, int flag, int nextc) -{ - return invis(dst, NULL, c, flag, nextc); -} - -char * -nvis(char *dst, size_t dlen, int c, int flag, int nextc) -{ - return invis(dst, &dlen, c, flag, nextc); -} - - -/* - * strvis, strvisx - visually encode characters from src into dst - * - * Dst must be 4 times the size of src to account for possible - * expansion. The length of dst, not including the trailing NULL, - * is returned. - * - * Strvisx encodes exactly len bytes from src into dst. - * This is useful for encoding a block of data. - */ -static int -istrnvis(char *dst, size_t *dlen, const char *src, int flag) -{ - char *extra = NULL; - int rv; - - MAKEEXTRALIST(flag, extra, ""); - if (!extra) { - if (dlen && *dlen == 0) { - errno = ENOSPC; - return -1; - } - *dst = '\0'; /* can't create extra, return "" */ - return 0; - } - rv = istrsnvis(dst, dlen, src, flag, extra); - free(extra); - return rv; -} - -int -strvis(char *dst, const char *src, int flag) -{ - return istrnvis(dst, NULL, src, flag); -} - -int -strnvis(char *dst, size_t dlen, const char *src, int flag) -{ - return istrnvis(dst, &dlen, src, flag); -} - -static int -istrnvisx(char *dst, size_t *dlen, const char *src, size_t len, int flag) -{ - char *extra = NULL; - int rv; - - MAKEEXTRALIST(flag, extra, ""); - if (!extra) { - if (dlen && *dlen == 0) { - errno = ENOSPC; - return -1; - } - *dst = '\0'; /* can't create extra, return "" */ - return 0; - } - rv = istrsnvisx(dst, dlen, src, len, flag, extra); - free(extra); - return rv; -} - -int -strvisx(char *dst, const char *src, size_t len, int flag) -{ - return istrnvisx(dst, NULL, src, len, flag); -} - -int -strnvisx(char *dst, size_t dlen, const char *src, size_t len, int flag) -{ - return istrnvisx(dst, &dlen, src, len, flag); -} - -#endif diff --git a/cmd-line-utils/libedit/np/vis.h b/cmd-line-utils/libedit/np/vis.h deleted file mode 100644 index 54a76e9108f..00000000000 --- a/cmd-line-utils/libedit/np/vis.h +++ /dev/null @@ -1,114 +0,0 @@ -/* $NetBSD: vis.h,v 1.19 2011/03/12 19:52:45 christos Exp $ */ - -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)vis.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _VIS_H_ -#define _VIS_H_ - -#include - -/* - * to select alternate encoding format - */ -#define VIS_OCTAL 0x001 /* use octal \ddd format */ -#define VIS_CSTYLE 0x002 /* use \[nrft0..] where appropiate */ - -/* - * to alter set of characters encoded (default is to encode all - * non-graphic except space, tab, and newline). - */ -#define VIS_SP 0x004 /* also encode space */ -#define VIS_TAB 0x008 /* also encode tab */ -#define VIS_NL 0x010 /* also encode newline */ -#define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL) -#define VIS_SAFE 0x020 /* only encode "unsafe" characters */ - -/* - * other - */ -#define VIS_NOSLASH 0x040 /* inhibit printing '\' */ -#define VIS_HTTP1808 0x080 /* http-style escape % hex hex */ -#define VIS_HTTPSTYLE 0x080 /* http-style escape % hex hex */ -#define VIS_MIMESTYLE 0x100 /* mime-style escape = HEX HEX */ -#define VIS_HTTP1866 0x200 /* http-style &#num; or &string; */ -#define VIS_NOESCAPE 0x400 /* don't decode `\' */ -#define _VIS_END 0x800 /* for unvis */ - -/* - * unvis return codes - */ -#define UNVIS_VALID 1 /* character valid */ -#define UNVIS_VALIDPUSH 2 /* character valid, push back passed char */ -#define UNVIS_NOCHAR 3 /* valid sequence, no character produced */ -#define UNVIS_SYNBAD -1 /* unrecognized escape sequence */ -#define UNVIS_ERROR -2 /* decoder in unknown state (unrecoverable) */ - -/* - * unvis flags - */ -#define UNVIS_END _VIS_END /* no more characters */ -/* XXXMYSQL */ -#ifndef __RENAME -#define __RENAME(x) -#endif - -__BEGIN_DECLS -char *vis(char *, int, int, int); -char *nvis(char *, size_t, int, int, int); - -char *svis(char *, int, int, int, const char *); -char *snvis(char *, size_t, int, int, int, const char *); - -int strvis(char *, const char *, int); -int strnvis(char *, size_t, const char *, int); - -int strsvis(char *, const char *, int, const char *); -int strsnvis(char *, size_t, const char *, int, const char *); - -int strvisx(char *, const char *, size_t, int); -int strnvisx(char *, size_t, const char *, size_t, int); - -int strsvisx(char *, const char *, size_t, int, const char *); -int strsnvisx(char *, size_t, const char *, size_t, int, const char *); - -int strunvis(char *, const char *); -int strnunvis(char *, size_t, const char *); - -int strunvisx(char *, const char *, int); -int strnunvisx(char *, size_t, const char *, int); - -#ifndef __LIBC12_SOURCE__ -int unvis(char *, int, int *, int) __RENAME(__unvis50); -#endif -__END_DECLS - -#endif /* !_VIS_H_ */ diff --git a/cmd-line-utils/libedit/np/wcsdup.c b/cmd-line-utils/libedit/np/wcsdup.c deleted file mode 100644 index 2a77375e0b7..00000000000 --- a/cmd-line-utils/libedit/np/wcsdup.c +++ /dev/null @@ -1,43 +0,0 @@ -/* $NetBSD: wcsdup.c,v 1.3 2008/05/26 13:17:48 haad Exp $ */ - -/* - * Copyright (C) 2006 Aleksey Cheusov - * - * This material is provided "as is", with absolutely no warranty expressed - * or implied. Any use is at your own risk. - * - * Permission to use or copy this software for any purpose is hereby granted - * without fee. Permission to modify the code and to distribute modified - * code is also granted without any restrictions. - */ - -#ifndef HAVE_WCSDUP - -#include "config.h" - -#if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: wcsdup.c,v 1.3 2008/05/26 13:17:48 haad Exp $"); -#endif /* LIBC_SCCS and not lint */ - -#include -#include -#include - -wchar_t * -wcsdup(const wchar_t *str) -{ - wchar_t *copy; - size_t len; - - _DIAGASSERT(str != NULL); - - len = wcslen(str) + 1; - copy = malloc(len * sizeof (wchar_t)); - - if (!copy) - return NULL; - - return wmemcpy(copy, str, len); -} - -#endif diff --git a/cmd-line-utils/libedit/parse.c b/cmd-line-utils/libedit/parse.c deleted file mode 100644 index b14e4ae7165..00000000000 --- a/cmd-line-utils/libedit/parse.c +++ /dev/null @@ -1,284 +0,0 @@ -/* $NetBSD: parse.c,v 1.26 2011/08/16 16:25:15 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)parse.c 8.1 (Berkeley) 6/4/93"; -#else -#endif -#endif /* not lint && not SCCSID */ - -/* - * parse.c: parse an editline extended command - * - * commands are: - * - * bind - * echotc - * edit - * gettc - * history - * settc - * setty - */ -#include "el.h" -#include - -private const struct { - const Char *name; - int (*func)(EditLine *, int, const Char **); -} cmds[] = { - { STR("bind"), map_bind }, - { STR("echotc"), terminal_echotc }, - { STR("edit"), el_editmode }, - { STR("history"), hist_command }, - { STR("telltc"), terminal_telltc }, - { STR("settc"), terminal_settc }, - { STR("setty"), tty_stty }, - { NULL, NULL } -}; - - -/* parse_line(): - * Parse a line and dispatch it - */ -protected int -parse_line(EditLine *el, const Char *line) -{ - const Char **argv; - int argc; - TYPE(Tokenizer) *tok; - - tok = FUN(tok,init)(NULL); - FUN(tok,str)(tok, line, &argc, &argv); - argc = FUN(el,parse)(el, argc, argv); - FUN(tok,end)(tok); - return argc; -} - - -/* el_parse(): - * Command dispatcher - */ -public int -FUN(el,parse)(EditLine *el, int argc, const Char *argv[]) -{ - const Char *ptr; - int i; - - if (argc < 1) - return -1; - ptr = Strchr(argv[0], ':'); - if (ptr != NULL) { - Char *tprog; - size_t l; - - if (ptr == argv[0]) - return 0; - l = (size_t)(ptr - argv[0] - 1); - tprog = el_malloc((l + 1) * sizeof(*tprog)); - if (tprog == NULL) - return 0; - (void) Strncpy(tprog, argv[0], l); - tprog[l] = '\0'; - ptr++; - l = (size_t)el_match(el->el_prog, tprog); - el_free(tprog); - if (!l) - return 0; - } else - ptr = argv[0]; - - for (i = 0; cmds[i].name != NULL; i++) - if (Strcmp(cmds[i].name, ptr) == 0) { - i = (*cmds[i].func) (el, argc, argv); - return -i; - } - return -1; -} - - -/* parse__escape(): - * Parse a string of the form ^ \ \ \U+xxxx and return - * the appropriate character or -1 if the escape is not valid - */ -protected int -parse__escape(const Char **ptr) -{ - const Char *p; - Int c; - - p = *ptr; - - if (p[1] == 0) - return -1; - - if (*p == '\\') { - p++; - switch (*p) { - case 'a': - c = '\007'; /* Bell */ - break; - case 'b': - c = '\010'; /* Backspace */ - break; - case 't': - c = '\011'; /* Horizontal Tab */ - break; - case 'n': - c = '\012'; /* New Line */ - break; - case 'v': - c = '\013'; /* Vertical Tab */ - break; - case 'f': - c = '\014'; /* Form Feed */ - break; - case 'r': - c = '\015'; /* Carriage Return */ - break; - case 'e': - c = '\033'; /* Escape */ - break; - case 'U': /* Unicode \U+xxxx or \U+xxxxx format */ - { - int i; - const Char hex[] = STR("0123456789ABCDEF"); - const Char *h; - ++p; - if (*p++ != '+') - return -1; - c = 0; - for (i = 0; i < 5; ++i) { - h = Strchr(hex, *p++); - if (!h && i < 4) - return -1; - else if (h) - c = (c << 4) | ((int)(h - hex)); - else - --p; - } - if (c > 0x10FFFF) /* outside valid character range */ - return -1; - break; - } - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - { - int cnt, ch; - - for (cnt = 0, c = 0; cnt < 3; cnt++) { - ch = *p++; - if (ch < '0' || ch > '7') { - p--; - break; - } - c = (c << 3) | (ch - '0'); - } - if ((c & (wint_t)0xffffff00) != (wint_t)0) - return -1; - --p; - break; - } - default: - c = *p; - break; - } - } else if (*p == '^') { - p++; - c = (*p == '?') ? '\177' : (*p & 0237); - } else - c = *p; - *ptr = ++p; - return c; -} - -/* parse__string(): - * Parse the escapes from in and put the raw string out - */ -protected Char * -parse__string(Char *out, const Char *in) -{ - Char *rv = out; - int n; - - for (;;) - switch (*in) { - case '\0': - *out = '\0'; - return rv; - - case '\\': - case '^': - if ((n = parse__escape(&in)) == -1) - return NULL; - *out++ = n; - break; - - case 'M': - if (in[1] == '-' && in[2] != '\0') { - *out++ = '\033'; - in += 2; - break; - } - /*FALLTHROUGH*/ - - default: - *out++ = *in++; - break; - } -} - - -/* parse_cmd(): - * Return the command number for the command string given - * or -1 if one is not found - */ -protected int -parse_cmd(EditLine *el, const Char *cmd) -{ - el_bindings_t *b; - - for (b = el->el_map.help; b->name != NULL; b++) - if (Strcmp(b->name, cmd) == 0) - return b->func; - return -1; -} diff --git a/cmd-line-utils/libedit/parse.h b/cmd-line-utils/libedit/parse.h deleted file mode 100644 index ec04051bc27..00000000000 --- a/cmd-line-utils/libedit/parse.h +++ /dev/null @@ -1,48 +0,0 @@ -/* $NetBSD: parse.h,v 1.7 2009/12/30 22:37:40 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)parse.h 8.1 (Berkeley) 6/4/93 - */ - -/* - * el.parse.h: Parser functions - */ -#ifndef _h_el_parse -#define _h_el_parse - -protected int parse_line(EditLine *, const Char *); -protected int parse__escape(const Char **); -protected Char *parse__string(Char *, const Char *); -protected int parse_cmd(EditLine *, const Char *); - -#endif /* _h_el_parse */ diff --git a/cmd-line-utils/libedit/prompt.c b/cmd-line-utils/libedit/prompt.c deleted file mode 100644 index 3f8d73303ec..00000000000 --- a/cmd-line-utils/libedit/prompt.c +++ /dev/null @@ -1,198 +0,0 @@ -/* $NetBSD: prompt.c,v 1.20 2011/07/29 15:16:33 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)prompt.c 8.1 (Berkeley) 6/4/93"; -#else -#endif -#endif /* not lint && not SCCSID */ - -/* - * prompt.c: Prompt printing functions - */ -#include -#include "el.h" - -private Char *prompt_default(EditLine *); -private Char *prompt_default_r(EditLine *); - -/* prompt_default(): - * Just a default prompt, in case the user did not provide one - */ -private Char * -/*ARGSUSED*/ -prompt_default(EditLine *el __attribute__((__unused__))) -{ - static Char a[3] = {'?', ' ', '\0'}; - - return a; -} - - -/* prompt_default_r(): - * Just a default rprompt, in case the user did not provide one - */ -private Char * -/*ARGSUSED*/ -prompt_default_r(EditLine *el __attribute__((__unused__))) -{ - static Char a[1] = {'\0'}; - - return a; -} - - -/* prompt_print(): - * Print the prompt and update the prompt position. - */ -protected void -prompt_print(EditLine *el, int op) -{ - el_prompt_t *elp; - Char *p; - int ignore = 0; - - if (op == EL_PROMPT) - elp = &el->el_prompt; - else - elp = &el->el_rprompt; - - if (elp->p_wide) - p = (*elp->p_func)(el); - else - p = ct_decode_string((char *)(void *)(*elp->p_func)(el), - &el->el_scratch); - - for (; *p; p++) { - if (elp->p_ignore == *p) { - ignore = !ignore; - continue; - } - if (ignore) - terminal__putc(el, *p); - else - re_putc(el, *p, 1); - } - - elp->p_pos.v = el->el_refresh.r_cursor.v; - elp->p_pos.h = el->el_refresh.r_cursor.h; -} - - -/* prompt_init(): - * Initialize the prompt stuff - */ -protected int -prompt_init(EditLine *el) -{ - - el->el_prompt.p_func = prompt_default; - el->el_prompt.p_pos.v = 0; - el->el_prompt.p_pos.h = 0; - el->el_prompt.p_ignore = '\0'; - el->el_rprompt.p_func = prompt_default_r; - el->el_rprompt.p_pos.v = 0; - el->el_rprompt.p_pos.h = 0; - el->el_rprompt.p_ignore = '\0'; - return 0; -} - - -/* prompt_end(): - * Clean up the prompt stuff - */ -protected void -/*ARGSUSED*/ -prompt_end(EditLine *el __attribute__((__unused__))) -{ -} - - -/* prompt_set(): - * Install a prompt printing function - */ -protected int -prompt_set(EditLine *el, el_pfunc_t prf, Char c, int op, int wide) -{ - el_prompt_t *p; - - if (op == EL_PROMPT || op == EL_PROMPT_ESC) - p = &el->el_prompt; - else - p = &el->el_rprompt; - - if (prf == NULL) { - if (op == EL_PROMPT || op == EL_PROMPT_ESC) - p->p_func = prompt_default; - else - p->p_func = prompt_default_r; - } else { - p->p_func = prf; - } - - p->p_ignore = c; - - p->p_pos.v = 0; - p->p_pos.h = 0; - p->p_wide = wide; - - return 0; -} - - -/* prompt_get(): - * Retrieve the prompt printing function - */ -protected int -prompt_get(EditLine *el, el_pfunc_t *prf, Char *c, int op) -{ - el_prompt_t *p; - - if (prf == NULL) - return -1; - - if (op == EL_PROMPT) - p = &el->el_prompt; - else - p = &el->el_rprompt; - - if (prf) - *prf = p->p_func; - if (c) - *c = p->p_ignore; - - return 0; -} diff --git a/cmd-line-utils/libedit/prompt.h b/cmd-line-utils/libedit/prompt.h deleted file mode 100644 index af63b82b684..00000000000 --- a/cmd-line-utils/libedit/prompt.h +++ /dev/null @@ -1,60 +0,0 @@ -/* $NetBSD: prompt.h,v 1.10 2009/12/30 22:37:40 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)prompt.h 8.1 (Berkeley) 6/4/93 - */ - -/* - * el.prompt.h: Prompt printing stuff - */ -#ifndef _h_el_prompt -#define _h_el_prompt - -#include "histedit.h" - -typedef Char *(*el_pfunc_t)(EditLine *); - -typedef struct el_prompt_t { - el_pfunc_t p_func; /* Function to return the prompt */ - coord_t p_pos; /* position in the line after prompt */ - Char p_ignore; /* character to start/end literal */ - int p_wide; -} el_prompt_t; - -protected void prompt_print(EditLine *, int); -protected int prompt_set(EditLine *, el_pfunc_t, Char, int, int); -protected int prompt_get(EditLine *, el_pfunc_t *, Char *, int); -protected int prompt_init(EditLine *); -protected void prompt_end(EditLine *); - -#endif /* _h_el_prompt */ diff --git a/cmd-line-utils/libedit/read.c b/cmd-line-utils/libedit/read.c deleted file mode 100644 index a919b888965..00000000000 --- a/cmd-line-utils/libedit/read.c +++ /dev/null @@ -1,722 +0,0 @@ -/* $NetBSD: read.c,v 1.67 2011/08/16 16:25:15 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)read.c 8.1 (Berkeley) 6/4/93"; -#else -#endif -#endif /* not lint && not SCCSID */ - -/* - * read.c: Clean this junk up! This is horrible code. - * Terminal read functions - */ -#include -#include -#include -#include -#include -#include "el.h" - -#define OKCMD -1 /* must be -1! */ - -private int read__fixio(int, int); -private int read_preread(EditLine *); -private int read_char(EditLine *, Char *); -private int read_getcmd(EditLine *, el_action_t *, Char *); -private void read_pop(c_macro_t *); - -/* read_init(): - * Initialize the read stuff - */ -protected int -read_init(EditLine *el) -{ - /* builtin read_char */ - el->el_read.read_char = read_char; - return 0; -} - - -/* el_read_setfn(): - * Set the read char function to the one provided. - * If it is set to EL_BUILTIN_GETCFN, then reset to the builtin one. - */ -protected int -el_read_setfn(EditLine *el, el_rfunc_t rc) -{ - el->el_read.read_char = (rc == EL_BUILTIN_GETCFN) ? read_char : rc; - return 0; -} - - -/* el_read_getfn(): - * return the current read char function, or EL_BUILTIN_GETCFN - * if it is the default one - */ -protected el_rfunc_t -el_read_getfn(EditLine *el) -{ - return el->el_read.read_char == read_char ? - EL_BUILTIN_GETCFN : el->el_read.read_char; -} - - -#ifndef MIN -#define MIN(A,B) ((A) < (B) ? (A) : (B)) -#endif - -#ifdef DEBUG_EDIT -private void -read_debug(EditLine *el) -{ - - if (el->el_line.cursor > el->el_line.lastchar) - (void) fprintf(el->el_errfile, "cursor > lastchar\r\n"); - if (el->el_line.cursor < el->el_line.buffer) - (void) fprintf(el->el_errfile, "cursor < buffer\r\n"); - if (el->el_line.cursor > el->el_line.limit) - (void) fprintf(el->el_errfile, "cursor > limit\r\n"); - if (el->el_line.lastchar > el->el_line.limit) - (void) fprintf(el->el_errfile, "lastchar > limit\r\n"); - if (el->el_line.limit != &el->el_line.buffer[EL_BUFSIZ - 2]) - (void) fprintf(el->el_errfile, "limit != &buffer[EL_BUFSIZ-2]\r\n"); -} -#endif /* DEBUG_EDIT */ - - -/* read__fixio(): - * Try to recover from a read error - */ -/* ARGSUSED */ -private int -read__fixio(int fd __attribute__((__unused__)), int e) -{ - - switch (e) { - case -1: /* Make sure that the code is reachable */ - -#ifdef EWOULDBLOCK - case EWOULDBLOCK: -#ifndef TRY_AGAIN -#define TRY_AGAIN -#endif -#endif /* EWOULDBLOCK */ - -#if defined(POSIX) && defined(EAGAIN) -#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN - case EAGAIN: -#ifndef TRY_AGAIN -#define TRY_AGAIN -#endif -#endif /* EWOULDBLOCK && EWOULDBLOCK != EAGAIN */ -#endif /* POSIX && EAGAIN */ - - e = 0; -#ifdef TRY_AGAIN -#if defined(F_SETFL) && defined(O_NDELAY) - if ((e = fcntl(fd, F_GETFL, 0)) == -1) - return -1; - - if (fcntl(fd, F_SETFL, e & ~O_NDELAY) == -1) - return -1; - else - e = 1; -#endif /* F_SETFL && O_NDELAY */ - -#ifdef FIONBIO - { - int zero = 0; - - if (ioctl(fd, FIONBIO, &zero) == -1) - return -1; - else - e = 1; - } -#endif /* FIONBIO */ - -#endif /* TRY_AGAIN */ - return e ? 0 : -1; - - case EINTR: - return 0; - - default: - return -1; - } -} - - -/* read_preread(): - * Try to read the stuff in the input queue; - */ -private int -read_preread(EditLine *el) -{ - int chrs = 0; - - if (el->el_tty.t_mode == ED_IO) - return 0; - -#ifndef WIDECHAR -/* FIONREAD attempts to buffer up multiple bytes, and to make that work - * properly with partial wide/UTF-8 characters would need some careful work. */ -#ifdef FIONREAD - (void) ioctl(el->el_infd, FIONREAD, &chrs); - if (chrs > 0) { - char buf[EL_BUFSIZ]; - - chrs = read(el->el_infd, buf, - (size_t) MIN(chrs, EL_BUFSIZ - 1)); - if (chrs > 0) { - buf[chrs] = '\0'; - el_push(el, buf); - } - } -#endif /* FIONREAD */ -#endif - return chrs > 0; -} - - -/* el_push(): - * Push a macro - */ -public void -FUN(el,push)(EditLine *el, const Char *str) -{ - c_macro_t *ma = &el->el_chared.c_macro; - - if (str != NULL && ma->level + 1 < EL_MAXMACRO) { - ma->level++; - if ((ma->macro[ma->level] = Strdup(str)) != NULL) - return; - ma->level--; - } - terminal_beep(el); - terminal__flush(el); -} - - -/* read_getcmd(): - * Return next command from the input stream. - * Character values > 255 are not looked up in the map, but inserted. - */ -private int -read_getcmd(EditLine *el, el_action_t *cmdnum, Char *ch) -{ - el_action_t cmd; - int num; - - el->el_errno = 0; - do { - if ((num = FUN(el,getc)(el, ch)) != 1) {/* if EOF or error */ - el->el_errno = num == 0 ? 0 : errno; - return num; - } - -#ifdef KANJI - if ((*ch & 0200)) { - el->el_state.metanext = 0; - cmd = CcViMap[' ']; - break; - } else -#endif /* KANJI */ - - if (el->el_state.metanext) { - el->el_state.metanext = 0; - *ch |= 0200; - } -#ifdef WIDECHAR - if (*ch >= N_KEYS) - cmd = ED_INSERT; - else -#endif - cmd = el->el_map.current[(unsigned char) *ch]; - if (cmd == ED_SEQUENCE_LEAD_IN) { - keymacro_value_t val; - switch (keymacro_get(el, ch, &val)) { - case XK_CMD: - cmd = val.cmd; - break; - case XK_STR: - FUN(el,push)(el, val.str); - break; -#ifdef notyet - case XK_EXE: - /* XXX: In the future to run a user function */ - RunCommand(val.str); - break; -#endif - default: - EL_ABORT((el->el_errfile, "Bad XK_ type \n")); - break; - } - } - if (el->el_map.alt == NULL) - el->el_map.current = el->el_map.key; - } while (cmd == ED_SEQUENCE_LEAD_IN); - *cmdnum = cmd; - return OKCMD; -} - -/* read_char(): - * Read a character from the tty. - */ -private int -read_char(EditLine *el, Char *cp) -{ - ssize_t num_read; - int tried = 0; - char cbuf[MB_LEN_MAX]; - size_t cbp = 0; - int bytes = 0; - -#ifdef WIDECHAR -static mbstate_t state, temp_state; -memset(&state, 0, sizeof(mbstate_t)); -#endif - - again: - el->el_signal->sig_no = 0; - while ((num_read = read(el->el_infd, cbuf + cbp, (size_t)1)) == -1) { - switch (el->el_signal->sig_no) { - case SIGCONT: - FUN(el,set)(el, EL_REFRESH); - /*FALLTHROUGH*/ - case SIGWINCH: - sig_set(el); - goto again; - default: - break; - } - if (!tried && read__fixio(el->el_infd, errno) == 0) - tried = 1; - else { - *cp = '\0'; - return -1; - } - } - -#ifdef WIDECHAR - ++cbp; - if (cbp > (size_t) MB_CUR_MAX) { /* "shouldn't happen" */ - *cp = '\0'; - return (-1); - } - - temp_state= state; - - if ((bytes = mbrtowc(cp, cbuf, cbp, &state)) == -2) - { - /* Incomplete sequence, restore the state and scan more bytes. */ - state= temp_state; - goto again; - } - else if (bytes == -1) - { - /* Invalid sequence, reset the state and continue. */ - cbp= 0; - memset(&state, 0, sizeof(mbstate_t)); - goto again; - } - /* We successfully read one single or multi-byte character */ -#else - *cp = (unsigned char)cbuf[0]; -#endif - -#if 0 - if ((el->el_flags & IGNORE_EXTCHARS) && bytes > 1) { - cbp = 0; /* skip this character */ - goto again; - } -#endif - - return (int)num_read; -} - -/* read_pop(): - * Pop a macro from the stack - */ -private void -read_pop(c_macro_t *ma) -{ - int i; - - el_free(ma->macro[0]); - for (i = 0; i < ma->level; i++) - ma->macro[i] = ma->macro[i + 1]; - ma->level--; - ma->offset = 0; -} - -/* el_getc(): - * Read a character - */ -public int -FUN(el,getc)(EditLine *el, Char *cp) -{ - int num_read; - c_macro_t *ma = &el->el_chared.c_macro; - - terminal__flush(el); - for (;;) { - if (ma->level < 0) { - if (!read_preread(el)) - break; - } - - if (ma->level < 0) - break; - - if (ma->macro[0][ma->offset] == '\0') { - read_pop(ma); - continue; - } - - *cp = ma->macro[0][ma->offset++]; - - if (ma->macro[0][ma->offset] == '\0') { - /* Needed for QuoteMode On */ - read_pop(ma); - } - - return 1; - } - -#ifdef DEBUG_READ - (void) fprintf(el->el_errfile, "Turning raw mode on\n"); -#endif /* DEBUG_READ */ - if (tty_rawmode(el) < 0)/* make sure the tty is set up correctly */ - return 0; - -#ifdef DEBUG_READ - (void) fprintf(el->el_errfile, "Reading a character\n"); -#endif /* DEBUG_READ */ - num_read = (*el->el_read.read_char)(el, cp); -#ifdef WIDECHAR - if (el->el_flags & NARROW_READ) - *cp = *(char *)(void *)cp; -#endif -#ifdef DEBUG_READ - (void) fprintf(el->el_errfile, "Got it %c\n", *cp); -#endif /* DEBUG_READ */ - return num_read; -} - -protected void -read_prepare(EditLine *el) -{ - if (el->el_flags & HANDLE_SIGNALS) - sig_set(el); - if (el->el_flags & NO_TTY) - return; - if ((el->el_flags & (UNBUFFERED|EDIT_DISABLED)) == UNBUFFERED) - tty_rawmode(el); - - /* This is relatively cheap, and things go terribly wrong if - we have the wrong size. */ - el_resize(el); - re_clear_display(el); /* reset the display stuff */ - ch_reset(el, 0); - re_refresh(el); /* print the prompt */ - - if (el->el_flags & UNBUFFERED) - terminal__flush(el); -} - -protected void -read_finish(EditLine *el) -{ - if ((el->el_flags & UNBUFFERED) == 0) - (void) tty_cookedmode(el); - if (el->el_flags & HANDLE_SIGNALS) - sig_clr(el); -} - -public const Char * -FUN(el,gets)(EditLine *el, int *nread) -{ - int retval; - el_action_t cmdnum = 0; - int num; /* how many chars we have read at NL */ - Char ch, *cp; - int crlf = 0; - int nrb; -#ifdef FIONREAD - c_macro_t *ma = &el->el_chared.c_macro; -#endif /* FIONREAD */ - - if (nread == NULL) - nread = &nrb; - *nread = 0; - - if (el->el_flags & NO_TTY) { - size_t idx; - - cp = el->el_line.buffer; - while ((num = (*el->el_read.read_char)(el, cp)) == 1) { - /* make sure there is space for next character */ - if (cp + 1 >= el->el_line.limit) { - idx = (size_t)(cp - el->el_line.buffer); - if (!ch_enlargebufs(el, (size_t)2)) - break; - cp = &el->el_line.buffer[idx]; - } - cp++; - if (el->el_flags & UNBUFFERED) - break; - if (cp[-1] == '\r' || cp[-1] == '\n') - break; - } - if (num == -1) { - if (errno == EINTR) - cp = el->el_line.buffer; - el->el_errno = errno; - } - - goto noedit; - } - - -#ifdef FIONREAD - if (el->el_tty.t_mode == EX_IO && ma->level < 0) { - long chrs = 0; - - (void) ioctl(el->el_infd, FIONREAD, &chrs); - if (chrs == 0) { - if (tty_rawmode(el) < 0) { - errno = 0; - *nread = 0; - return NULL; - } - } - } -#endif /* FIONREAD */ - - if ((el->el_flags & UNBUFFERED) == 0) - read_prepare(el); - - if (el->el_flags & EDIT_DISABLED) { - size_t idx; - - if ((el->el_flags & UNBUFFERED) == 0) - cp = el->el_line.buffer; - else - cp = el->el_line.lastchar; - - terminal__flush(el); - - while ((num = (*el->el_read.read_char)(el, cp)) == 1) { - /* make sure there is space next character */ - if (cp + 1 >= el->el_line.limit) { - idx = (size_t)(cp - el->el_line.buffer); - if (!ch_enlargebufs(el, (size_t)2)) - break; - cp = &el->el_line.buffer[idx]; - } - cp++; - crlf = cp[-1] == '\r' || cp[-1] == '\n'; - if (el->el_flags & UNBUFFERED) - break; - if (crlf) - break; - } - - if (num == -1) { - if (errno == EINTR) - cp = el->el_line.buffer; - el->el_errno = errno; - } - - goto noedit; - } - - for (num = OKCMD; num == OKCMD;) { /* while still editing this - * line */ -#ifdef DEBUG_EDIT - read_debug(el); -#endif /* DEBUG_EDIT */ - /* if EOF or error */ - if ((num = read_getcmd(el, &cmdnum, &ch)) != OKCMD) { -#ifdef DEBUG_READ - (void) fprintf(el->el_errfile, - "Returning from el_gets %d\n", num); -#endif /* DEBUG_READ */ - break; - } - if (el->el_errno == EINTR) { - el->el_line.buffer[0] = '\0'; - el->el_line.lastchar = - el->el_line.cursor = el->el_line.buffer; - break; - } - if ((unsigned int)cmdnum >= (unsigned int)el->el_map.nfunc) { /* BUG CHECK command */ -#ifdef DEBUG_EDIT - (void) fprintf(el->el_errfile, - "ERROR: illegal command from key 0%o\r\n", ch); -#endif /* DEBUG_EDIT */ - continue; /* try again */ - } - /* now do the real command */ -#ifdef DEBUG_READ - { - el_bindings_t *b; - for (b = el->el_map.help; b->name; b++) - if (b->func == cmdnum) - break; - if (b->name) - (void) fprintf(el->el_errfile, - "Executing %s\n", b->name); - else - (void) fprintf(el->el_errfile, - "Error command = %d\n", cmdnum); - } -#endif /* DEBUG_READ */ - /* vi redo needs these way down the levels... */ - el->el_state.thiscmd = cmdnum; - el->el_state.thisch = ch; - if (el->el_map.type == MAP_VI && - el->el_map.current == el->el_map.key && - el->el_chared.c_redo.pos < el->el_chared.c_redo.lim) { - if (cmdnum == VI_DELETE_PREV_CHAR && - el->el_chared.c_redo.pos != el->el_chared.c_redo.buf - && Isprint(el->el_chared.c_redo.pos[-1])) - el->el_chared.c_redo.pos--; - else - *el->el_chared.c_redo.pos++ = ch; - } - retval = (*el->el_map.func[cmdnum]) (el, ch); -#ifdef DEBUG_READ - (void) fprintf(el->el_errfile, - "Returned state %d\n", retval ); -#endif /* DEBUG_READ */ - - /* save the last command here */ - el->el_state.lastcmd = cmdnum; - - /* use any return value */ - switch (retval) { - case CC_CURSOR: - re_refresh_cursor(el); - break; - - case CC_REDISPLAY: - re_clear_lines(el); - re_clear_display(el); - /* FALLTHROUGH */ - - case CC_REFRESH: - re_refresh(el); - break; - - case CC_REFRESH_BEEP: - re_refresh(el); - terminal_beep(el); - break; - - case CC_NORM: /* normal char */ - break; - - case CC_ARGHACK: /* Suggested by Rich Salz */ - /* */ - continue; /* keep going... */ - - case CC_EOF: /* end of file typed */ - if ((el->el_flags & UNBUFFERED) == 0) - num = 0; - else if (num == -1) { - *el->el_line.lastchar++ = CONTROL('d'); - el->el_line.cursor = el->el_line.lastchar; - num = 1; - } - break; - - case CC_NEWLINE: /* normal end of line */ - num = (int)(el->el_line.lastchar - el->el_line.buffer); - break; - - case CC_FATAL: /* fatal error, reset to known state */ -#ifdef DEBUG_READ - (void) fprintf(el->el_errfile, - "*** editor fatal ERROR ***\r\n\n"); -#endif /* DEBUG_READ */ - /* put (real) cursor in a known place */ - re_clear_display(el); /* reset the display stuff */ - ch_reset(el, 1); /* reset the input pointers */ - re_refresh(el); /* print the prompt again */ - break; - - case CC_ERROR: - default: /* functions we don't know about */ -#ifdef DEBUG_READ - (void) fprintf(el->el_errfile, - "*** editor ERROR ***\r\n\n"); -#endif /* DEBUG_READ */ - terminal_beep(el); - terminal__flush(el); - break; - } - el->el_state.argument = 1; - el->el_state.doingarg = 0; - el->el_chared.c_vcmd.action = NOP; - if (el->el_flags & UNBUFFERED) - break; - } - - terminal__flush(el); /* flush any buffered output */ - /* make sure the tty is set up correctly */ - if ((el->el_flags & UNBUFFERED) == 0) { - read_finish(el); - *nread = num != -1 ? num : 0; - } else { - *nread = (int)(el->el_line.lastchar - el->el_line.buffer); - } - goto done; -noedit: - el->el_line.cursor = el->el_line.lastchar = cp; - *cp = '\0'; - *nread = (int)(el->el_line.cursor - el->el_line.buffer); -done: - if (*nread == 0) { - if (num == -1) { - *nread = -1; - errno = el->el_errno; - } - return NULL; - } else - return el->el_line.buffer; -} diff --git a/cmd-line-utils/libedit/read.h b/cmd-line-utils/libedit/read.h deleted file mode 100644 index 852606a9c17..00000000000 --- a/cmd-line-utils/libedit/read.h +++ /dev/null @@ -1,50 +0,0 @@ -/* $NetBSD: read.h,v 1.7 2009/12/30 22:37:40 christos Exp $ */ - -/*- - * Copyright (c) 2001 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Anthony Mallet. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * el.read.h: Character reading functions - */ -#ifndef _h_el_read -#define _h_el_read - -typedef int (*el_rfunc_t)(EditLine *, Char *); - -typedef struct el_read_t { - el_rfunc_t read_char; /* Function to read a character */ -} el_read_t; - -protected int read_init(EditLine *); -protected void read_prepare(EditLine *); -protected void read_finish(EditLine *); -protected int el_read_setfn(EditLine *, el_rfunc_t); -protected el_rfunc_t el_read_getfn(EditLine *); - -#endif /* _h_el_read */ diff --git a/cmd-line-utils/libedit/readline.c b/cmd-line-utils/libedit/readline.c deleted file mode 100644 index a2a92edc1b4..00000000000 --- a/cmd-line-utils/libedit/readline.c +++ /dev/null @@ -1,2294 +0,0 @@ -/* $NetBSD: readline.c,v 1.99 2011/08/16 16:25:15 christos Exp $ */ - -/*- - * Copyright (c) 1997 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Jaromir Dolecek. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#endif /* not lint && not SCCSID */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_VIS_H -#include -#else -#include "np/vis.h" -#endif -#include "readline/readline.h" -#include "el.h" -#include "fcns.h" /* for EL_NUM_FCNS */ -#include "histedit.h" -#include "filecomplete.h" - -void rl_prep_terminal(int); -void rl_deprep_terminal(void); - -/* for rl_complete() */ -#define TAB '\r' - -/* see comment at the #ifdef for sense of this */ -/* #define GDB_411_HACK */ - -/* readline compatibility stuff - look at readline sources/documentation */ -/* to see what these variables mean */ -const char *rl_library_version = "EditLine wrapper"; -int rl_readline_version = RL_READLINE_VERSION; -static char empty[] = { '\0' }; -static char expand_chars[] = { ' ', '\t', '\n', '=', '(', '\0' }; -static char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', '$', - '>', '<', '=', ';', '|', '&', '{', '(', '\0' }; -char *rl_readline_name = empty; -FILE *rl_instream = NULL; -FILE *rl_outstream = NULL; -int rl_point = 0; -int rl_end = 0; -char *rl_line_buffer = NULL; -VCPFunction *rl_linefunc = NULL; -int rl_done = 0; -VFunction *rl_event_hook = NULL; -KEYMAP_ENTRY_ARRAY emacs_standard_keymap, - emacs_meta_keymap, - emacs_ctlx_keymap; - -int history_base = 1; /* probably never subject to change */ -int history_length = 0; -int max_input_history = 0; -char history_expansion_char = '!'; -char history_subst_char = '^'; -char *history_no_expand_chars = expand_chars; -Function *history_inhibit_expansion_function = NULL; -char *history_arg_extract(int start, int end, const char *str); - -int rl_inhibit_completion = 0; -int rl_attempted_completion_over = 0; -char *rl_basic_word_break_characters = break_chars; -char *rl_completer_word_break_characters = NULL; -char *rl_completer_quote_characters = NULL; -Function *rl_completion_entry_function = NULL; -CPPFunction *rl_attempted_completion_function = NULL; -Function *rl_pre_input_hook = NULL; -Function *rl_startup1_hook = NULL; -int (*rl_getc_function)(FILE *) = NULL; -char *rl_terminal_name = NULL; -int rl_already_prompted = 0; -int rl_filename_completion_desired = 0; -int rl_ignore_completion_duplicates = 0; -int rl_catch_signals = 1; -int readline_echoing_p = 1; -int _rl_print_completions_horizontally = 0; -VFunction *rl_redisplay_function = NULL; -Function *rl_startup_hook = NULL; -VFunction *rl_completion_display_matches_hook = NULL; -VFunction *rl_prep_term_function = (VFunction *)rl_prep_terminal; -VFunction *rl_deprep_term_function = (VFunction *)rl_deprep_terminal; -KEYMAP_ENTRY_ARRAY emacs_meta_keymap; - -/* - * The current prompt string. - */ -char *rl_prompt = NULL; -/* - * This is set to character indicating type of completion being done by - * rl_complete_internal(); this is available for application completion - * functions. - */ -int rl_completion_type = 0; - -/* - * If more than this number of items results from query for possible - * completions, we ask user if they are sure to really display the list. - */ -int rl_completion_query_items = 100; - -/* - * List of characters which are word break characters, but should be left - * in the parsed text when it is passed to the completion function. - * Shell uses this to help determine what kind of completing to do. - */ -char *rl_special_prefixes = NULL; - -/* - * This is the character appended to the completed words if at the end of - * the line. Default is ' ' (a space). - */ -int rl_completion_append_character = ' '; - -/* stuff below is used internally by libedit for readline emulation */ - -static History *h = NULL; -static EditLine *e = NULL; -static Function *map[256]; -static jmp_buf topbuf; - -/* internal functions */ -static unsigned char _el_rl_complete(EditLine *, int); -static unsigned char _el_rl_tstp(EditLine *, int); -static char *_get_prompt(EditLine *); -static int _getc_function(EditLine *, char *); -static HIST_ENTRY *_move_history(int); -static int _history_expand_command(const char *, size_t, size_t, - char **); -static char *_rl_compat_sub(const char *, const char *, - const char *, int); -static int _rl_event_read_char(EditLine *, char *); -static void _rl_update_pos(void); - - -/* ARGSUSED */ -static char * -_get_prompt(EditLine *el __attribute__((__unused__))) -{ - rl_already_prompted = 1; - return rl_prompt; -} - - -/* - * generic function for moving around history - */ -static HIST_ENTRY * -_move_history(int op) -{ - HistEvent ev; - static HIST_ENTRY rl_he; - - if (history(h, &ev, op) != 0) - return NULL; - - rl_he.line = ev.str; - rl_he.data = NULL; - - return &rl_he; -} - - -/* - * read one key from user defined input function - */ -static int -/*ARGSUSED*/ -_getc_function(EditLine *el __attribute__((__unused__)), char *c) -{ - int i; - - i = (*rl_getc_function)(NULL); - if (i == -1) - return 0; - *c = (char)i; - return 1; -} - -static void -_resize_fun(EditLine *el, void *a) -{ - const LineInfo *li; - char **ap = a; - - li = el_line(el); - /* a cheesy way to get rid of const cast. */ - *ap = memchr(li->buffer, *li->buffer, (size_t)1); -} - -static const char * -_default_history_file(void) -{ - struct passwd *p; - static char path[PATH_MAX]; - - if (*path) - return path; - if ((p = getpwuid(getuid())) == NULL) - return NULL; - (void)snprintf(path, sizeof(path), "%s/.history", p->pw_dir); - return path; -} - -/* - * READLINE compatibility stuff - */ - -/* - * Set the prompt - */ -int -rl_set_prompt(const char *prompt) -{ - char *p; - - if (!prompt) - prompt = ""; - if (rl_prompt != NULL && strcmp(rl_prompt, prompt) == 0) - return 0; - if (rl_prompt) - el_free(rl_prompt); - rl_prompt = strdup(prompt); - if (rl_prompt == NULL) - return -1; - - while ((p = strchr(rl_prompt, RL_PROMPT_END_IGNORE)) != NULL) - *p = RL_PROMPT_START_IGNORE; - - return 0; -} - -/* - * initialize rl compat stuff - */ -int -rl_initialize(void) -{ - HistEvent ev; - int editmode = 1; - struct termios t; - - if (e != NULL) - el_end(e); - if (h != NULL) - history_end(h); - - if (!rl_instream) - rl_instream = stdin; - if (!rl_outstream) - rl_outstream = stdout; - - /* - * See if we don't really want to run the editor - */ - if (tcgetattr(fileno(rl_instream), &t) != -1 && (t.c_lflag & ECHO) == 0) - editmode = 0; - - e = el_init(rl_readline_name, rl_instream, rl_outstream, stderr); - - if (!editmode) - el_set(e, EL_EDITMODE, 0); - - h = history_init(); - if (!e || !h) - return -1; - - history(h, &ev, H_SETSIZE, INT_MAX); /* unlimited */ - history_length = 0; - max_input_history = INT_MAX; - el_set(e, EL_HIST, history, h); - - /* Setup resize function */ - el_set(e, EL_RESIZE, _resize_fun, &rl_line_buffer); - - /* setup getc function if valid */ - if (rl_getc_function) - el_set(e, EL_GETCFN, _getc_function); - - /* for proper prompt printing in readline() */ - if (rl_set_prompt("") == -1) { - history_end(h); - el_end(e); - return -1; - } - el_set(e, EL_PROMPT, _get_prompt, RL_PROMPT_START_IGNORE); - el_set(e, EL_SIGNAL, rl_catch_signals); - - /* set default mode to "emacs"-style and read setting afterwards */ - /* so this can be overriden */ - el_set(e, EL_EDITOR, "emacs"); - if (rl_terminal_name != NULL) - el_set(e, EL_TERMINAL, rl_terminal_name); - else - el_get(e, EL_TERMINAL, &rl_terminal_name); - - /* - * Word completion - this has to go AFTER rebinding keys - * to emacs-style. - */ - el_set(e, EL_ADDFN, "rl_complete", - "ReadLine compatible completion function", - _el_rl_complete); - el_set(e, EL_BIND, "^I", "rl_complete", NULL); - - /* - * Send TSTP when ^Z is pressed. - */ - el_set(e, EL_ADDFN, "rl_tstp", - "ReadLine compatible suspend function", - _el_rl_tstp); - el_set(e, EL_BIND, "^Z", "rl_tstp", NULL); - - /* - * Set some readline compatible key-bindings. - */ - el_set(e, EL_BIND, "^R", "em-inc-search-prev", NULL); - - /* - * Allow the use of Home/End keys. - */ - el_set(e, EL_BIND, "\\e[1~", "ed-move-to-beg", NULL); - el_set(e, EL_BIND, "\\e[4~", "ed-move-to-end", NULL); - el_set(e, EL_BIND, "\\e[7~", "ed-move-to-beg", NULL); - el_set(e, EL_BIND, "\\e[8~", "ed-move-to-end", NULL); - el_set(e, EL_BIND, "\\e[H", "ed-move-to-beg", NULL); - el_set(e, EL_BIND, "\\e[F", "ed-move-to-end", NULL); - - /* - * Allow the use of the Delete/Insert keys. - */ - el_set(e, EL_BIND, "\\e[3~", "ed-delete-next-char", NULL); - el_set(e, EL_BIND, "\\e[2~", "ed-quoted-insert", NULL); - - /* - * Ctrl-left-arrow and Ctrl-right-arrow for word moving. - */ - el_set(e, EL_BIND, "\\e[1;5C", "em-next-word", NULL); - el_set(e, EL_BIND, "\\e[1;5D", "ed-prev-word", NULL); - el_set(e, EL_BIND, "\\e[5C", "em-next-word", NULL); - el_set(e, EL_BIND, "\\e[5D", "ed-prev-word", NULL); - el_set(e, EL_BIND, "\\e\\e[C", "em-next-word", NULL); - el_set(e, EL_BIND, "\\e\\e[D", "ed-prev-word", NULL); - - /* read settings from configuration file */ - el_source(e, NULL); - - /* - * Unfortunately, some applications really do use rl_point - * and rl_line_buffer directly. - */ - _resize_fun(e, &rl_line_buffer); - _rl_update_pos(); - - if (rl_startup_hook) - (*rl_startup_hook)(NULL, 0); - - return 0; -} - - -/* - * read one line from input stream and return it, chomping - * trailing newline (if there is any) - */ -char * -readline(const char *p) -{ - HistEvent ev; - const char * volatile prompt = p; - int count; - const char *ret; - char *buf; - static int used_event_hook; - - if (e == NULL || h == NULL) - rl_initialize(); - - rl_done = 0; - - (void)setjmp(topbuf); - - /* update prompt accordingly to what has been passed */ - if (rl_set_prompt(prompt) == -1) - return NULL; - - if (rl_pre_input_hook) - (*rl_pre_input_hook)(NULL, 0); - - if (rl_event_hook && !(e->el_flags&NO_TTY)) { - el_set(e, EL_GETCFN, _rl_event_read_char); - used_event_hook = 1; - } - - if (!rl_event_hook && used_event_hook) { - el_set(e, EL_GETCFN, EL_BUILTIN_GETCFN); - used_event_hook = 0; - } - - rl_already_prompted = 0; - - /* get one line from input stream */ - ret = el_gets(e, &count); - - if (ret && count > 0) { - int lastidx; - - buf = strdup(ret); - if (buf == NULL) - return NULL; - lastidx = count - 1; - if (buf[lastidx] == '\n') - buf[lastidx] = '\0'; - } else - buf = NULL; - - history(h, &ev, H_GETSIZE); - history_length = ev.num; - - return buf; -} - -/* - * history functions - */ - -/* - * is normally called before application starts to use - * history expansion functions - */ -void -using_history(void) -{ - if (h == NULL || e == NULL) - rl_initialize(); -} - - -/* - * substitute ``what'' with ``with'', returning resulting string; if - * globally == 1, substitutes all occurrences of what, otherwise only the - * first one - */ -static char * -_rl_compat_sub(const char *str, const char *what, const char *with, - int globally) -{ - const char *s; - char *r, *result; - size_t len, with_len, what_len; - - len = strlen(str); - with_len = strlen(with); - what_len = strlen(what); - - /* calculate length we need for result */ - s = str; - while (*s) { - if (*s == *what && !strncmp(s, what, what_len)) { - len += with_len - what_len; - if (!globally) - break; - s += what_len; - } else - s++; - } - r = result = el_malloc((len + 1) * sizeof(*r)); - if (result == NULL) - return NULL; - s = str; - while (*s) { - if (*s == *what && !strncmp(s, what, what_len)) { - (void)strncpy(r, with, with_len); - r += with_len; - s += what_len; - if (!globally) { - (void)strcpy(r, s); - return result; - } - } else - *r++ = *s++; - } - *r = '\0'; - return result; -} - -static char *last_search_pat; /* last !?pat[?] search pattern */ -static char *last_search_match; /* last !?pat[?] that matched */ - -const char * -get_history_event(const char *cmd, int *cindex, int qchar) -{ - int idx, sign, sub, num, begin, ret; - size_t len; - char *pat; - const char *rptr; - HistEvent ev; - - idx = *cindex; - if (cmd[idx++] != history_expansion_char) - return NULL; - - /* find out which event to take */ - if (cmd[idx] == history_expansion_char || cmd[idx] == '\0') { - if (history(h, &ev, H_FIRST) != 0) - return NULL; - *cindex = cmd[idx]? (idx + 1):idx; - return ev.str; - } - sign = 0; - if (cmd[idx] == '-') { - sign = 1; - idx++; - } - - if ('0' <= cmd[idx] && cmd[idx] <= '9') { - HIST_ENTRY *rl_he; - - num = 0; - while (cmd[idx] && '0' <= cmd[idx] && cmd[idx] <= '9') { - num = num * 10 + cmd[idx] - '0'; - idx++; - } - if (sign) - num = history_length - num + 1; - - if (!(rl_he = history_get(num))) - return NULL; - - *cindex = idx; - return rl_he->line; - } - sub = 0; - if (cmd[idx] == '?') { - sub = 1; - idx++; - } - begin = idx; - while (cmd[idx]) { - if (cmd[idx] == '\n') - break; - if (sub && cmd[idx] == '?') - break; - if (!sub && (cmd[idx] == ':' || cmd[idx] == ' ' - || cmd[idx] == '\t' || cmd[idx] == qchar)) - break; - idx++; - } - len = (size_t)idx - (size_t)begin; - if (sub && cmd[idx] == '?') - idx++; - if (sub && len == 0 && last_search_pat && *last_search_pat) - pat = last_search_pat; - else if (len == 0) - return NULL; - else { - if ((pat = el_malloc((len + 1) * sizeof(*pat))) == NULL) - return NULL; - (void)strncpy(pat, cmd + begin, len); - pat[len] = '\0'; - } - - if (history(h, &ev, H_CURR) != 0) { - if (pat != last_search_pat) - el_free(pat); - return NULL; - } - num = ev.num; - - if (sub) { - if (pat != last_search_pat) { - if (last_search_pat) - el_free(last_search_pat); - last_search_pat = pat; - } - ret = history_search(pat, -1); - } else - ret = history_search_prefix(pat, -1); - - if (ret == -1) { - /* restore to end of list on failed search */ - history(h, &ev, H_FIRST); - (void)fprintf(rl_outstream, "%s: Event not found\n", pat); - if (pat != last_search_pat) - el_free(pat); - return NULL; - } - - if (sub && len) { - if (last_search_match && last_search_match != pat) - el_free(last_search_match); - last_search_match = pat; - } - - if (pat != last_search_pat) - el_free(pat); - - if (history(h, &ev, H_CURR) != 0) - return NULL; - *cindex = idx; - rptr = ev.str; - - /* roll back to original position */ - (void)history(h, &ev, H_SET, num); - - return rptr; -} - -/* - * the real function doing history expansion - takes as argument command - * to do and data upon which the command should be executed - * does expansion the way I've understood readline documentation - * - * returns 0 if data was not modified, 1 if it was and 2 if the string - * should be only printed and not executed; in case of error, - * returns -1 and *result points to NULL - * it's callers responsibility to free() string returned in *result - */ -static int -_history_expand_command(const char *command, size_t offs, size_t cmdlen, - char **result) -{ - char *tmp, *search = NULL, *aptr; - const char *ptr, *cmd; - static char *from = NULL, *to = NULL; - int start, end, idx, has_mods = 0; - int p_on = 0, g_on = 0; - - *result = NULL; - aptr = NULL; - ptr = NULL; - - /* First get event specifier */ - idx = 0; - - if (strchr(":^*$", command[offs + 1])) { - char str[4]; - /* - * "!:" is shorthand for "!!:". - * "!^", "!*" and "!$" are shorthand for - * "!!:^", "!!:*" and "!!:$" respectively. - */ - str[0] = str[1] = '!'; - str[2] = '0'; - ptr = get_history_event(str, &idx, 0); - idx = (command[offs + 1] == ':')? 1:0; - has_mods = 1; - } else { - if (command[offs + 1] == '#') { - /* use command so far */ - if ((aptr = el_malloc((offs + 1) * sizeof(*aptr))) - == NULL) - return -1; - (void)strncpy(aptr, command, offs); - aptr[offs] = '\0'; - idx = 1; - } else { - int qchar; - - qchar = (offs > 0 && command[offs - 1] == '"')? '"':0; - ptr = get_history_event(command + offs, &idx, qchar); - } - has_mods = command[offs + (size_t)idx] == ':'; - } - - if (ptr == NULL && aptr == NULL) - return -1; - - if (!has_mods) { - *result = strdup(aptr ? aptr : ptr); - if (aptr) - el_free(aptr); - if (*result == NULL) - return -1; - return 1; - } - - cmd = command + offs + idx + 1; - - /* Now parse any word designators */ - - if (*cmd == '%') /* last word matched by ?pat? */ - tmp = strdup(last_search_match? last_search_match:""); - else if (strchr("^*$-0123456789", *cmd)) { - start = end = -1; - if (*cmd == '^') - start = end = 1, cmd++; - else if (*cmd == '$') - start = -1, cmd++; - else if (*cmd == '*') - start = 1, cmd++; - else if (*cmd == '-' || isdigit((unsigned char) *cmd)) { - start = 0; - while (*cmd && '0' <= *cmd && *cmd <= '9') - start = start * 10 + *cmd++ - '0'; - - if (*cmd == '-') { - if (isdigit((unsigned char) cmd[1])) { - cmd++; - end = 0; - while (*cmd && '0' <= *cmd && *cmd <= '9') - end = end * 10 + *cmd++ - '0'; - } else if (cmd[1] == '$') { - cmd += 2; - end = -1; - } else { - cmd++; - end = -2; - } - } else if (*cmd == '*') - end = -1, cmd++; - else - end = start; - } - tmp = history_arg_extract(start, end, aptr? aptr:ptr); - if (tmp == NULL) { - (void)fprintf(rl_outstream, "%s: Bad word specifier", - command + offs + idx); - if (aptr) - el_free(aptr); - return -1; - } - } else - tmp = strdup(aptr? aptr:ptr); - - if (aptr) - el_free(aptr); - - if (*cmd == '\0' || ((size_t)(cmd - (command + offs)) >= cmdlen)) { - *result = tmp; - return 1; - } - - for (; *cmd; cmd++) { - if (*cmd == ':') - continue; - else if (*cmd == 'h') { /* remove trailing path */ - if ((aptr = strrchr(tmp, '/')) != NULL) - *aptr = '\0'; - } else if (*cmd == 't') { /* remove leading path */ - if ((aptr = strrchr(tmp, '/')) != NULL) { - aptr = strdup(aptr + 1); - el_free(tmp); - tmp = aptr; - } - } else if (*cmd == 'r') { /* remove trailing suffix */ - if ((aptr = strrchr(tmp, '.')) != NULL) - *aptr = '\0'; - } else if (*cmd == 'e') { /* remove all but suffix */ - if ((aptr = strrchr(tmp, '.')) != NULL) { - aptr = strdup(aptr); - el_free(tmp); - tmp = aptr; - } - } else if (*cmd == 'p') /* print only */ - p_on = 1; - else if (*cmd == 'g') - g_on = 2; - else if (*cmd == 's' || *cmd == '&') { - char *what, *with, delim; - size_t len, from_len; - size_t size; - - if (*cmd == '&' && (from == NULL || to == NULL)) - continue; - else if (*cmd == 's') { - delim = *(++cmd), cmd++; - size = 16; - what = el_realloc(from, size * sizeof(*what)); - if (what == NULL) { - el_free(from); - el_free(tmp); - return 0; - } - len = 0; - for (; *cmd && *cmd != delim; cmd++) { - if (*cmd == '\\' && cmd[1] == delim) - cmd++; - if (len >= size) { - char *nwhat; - nwhat = el_realloc(what, - (size <<= 1) * - sizeof(*nwhat)); - if (nwhat == NULL) { - el_free(what); - el_free(tmp); - return 0; - } - what = nwhat; - } - what[len++] = *cmd; - } - what[len] = '\0'; - from = what; - if (*what == '\0') { - el_free(what); - if (search) { - from = strdup(search); - if (from == NULL) { - el_free(tmp); - return 0; - } - } else { - from = NULL; - el_free(tmp); - return -1; - } - } - cmd++; /* shift after delim */ - if (!*cmd) - continue; - - size = 16; - with = el_realloc(to, size * sizeof(*with)); - if (with == NULL) { - el_free(to); - el_free(tmp); - return -1; - } - len = 0; - from_len = strlen(from); - for (; *cmd && *cmd != delim; cmd++) { - if (len + from_len + 1 >= size) { - char *nwith; - size += from_len + 1; - nwith = el_realloc(with, - size * sizeof(*nwith)); - if (nwith == NULL) { - el_free(with); - el_free(tmp); - return -1; - } - with = nwith; - } - if (*cmd == '&') { - /* safe */ - (void)strcpy(&with[len], from); - len += from_len; - continue; - } - if (*cmd == '\\' - && (*(cmd + 1) == delim - || *(cmd + 1) == '&')) - cmd++; - with[len++] = *cmd; - } - with[len] = '\0'; - to = with; - } - - aptr = _rl_compat_sub(tmp, from, to, g_on); - if (aptr) { - el_free(tmp); - tmp = aptr; - } - g_on = 0; - } - } - *result = tmp; - return p_on? 2:1; -} - - -/* - * csh-style history expansion - */ -int -history_expand(char *str, char **output) -{ - int ret = 0; - size_t idx, i, size; - char *tmp, *result; - - if (h == NULL || e == NULL) - rl_initialize(); - - if (history_expansion_char == 0) { - *output = strdup(str); - return 0; - } - - *output = NULL; - if (str[0] == history_subst_char) { - /* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */ - *output = el_malloc((strlen(str) + 4 + 1) * sizeof(*output)); - if (*output == NULL) - return 0; - (*output)[0] = (*output)[1] = history_expansion_char; - (*output)[2] = ':'; - (*output)[3] = 's'; - (void)strcpy((*output) + 4, str); - str = *output; - } else { - *output = strdup(str); - if (*output == NULL) - return 0; - } - -#define ADD_STRING(what, len, fr) \ - { \ - if (idx + len + 1 > size) { \ - char *nresult = el_realloc(result, \ - (size += len + 1) * sizeof(*nresult)); \ - if (nresult == NULL) { \ - el_free(*output); \ - if (/*CONSTCOND*/fr) \ - el_free(tmp); \ - return 0; \ - } \ - result = nresult; \ - } \ - (void)strncpy(&result[idx], what, len); \ - idx += len; \ - result[idx] = '\0'; \ - } - - result = NULL; - size = idx = 0; - tmp = NULL; - for (i = 0; str[i];) { - int qchar, loop_again; - size_t len, start, j; - - qchar = 0; - loop_again = 1; - start = j = i; -loop: - for (; str[j]; j++) { - if (str[j] == '\\' && - str[j + 1] == history_expansion_char) { - (void)strcpy(&str[j], &str[j + 1]); - continue; - } - if (!loop_again) { - if (isspace((unsigned char) str[j]) - || str[j] == qchar) - break; - } - if (str[j] == history_expansion_char - && !strchr(history_no_expand_chars, str[j + 1]) - && (!history_inhibit_expansion_function || - (*history_inhibit_expansion_function)(str, - (int)j) == 0)) - break; - } - - if (str[j] && loop_again) { - i = j; - qchar = (j > 0 && str[j - 1] == '"' )? '"':0; - j++; - if (str[j] == history_expansion_char) - j++; - loop_again = 0; - goto loop; - } - len = i - start; - ADD_STRING(&str[start], len, 0); - - if (str[i] == '\0' || str[i] != history_expansion_char) { - len = j - i; - ADD_STRING(&str[i], len, 0); - if (start == 0) - ret = 0; - else - ret = 1; - break; - } - ret = _history_expand_command (str, i, (j - i), &tmp); - if (ret > 0 && tmp) { - len = strlen(tmp); - ADD_STRING(tmp, len, 1); - } - if (tmp) { - el_free(tmp); - tmp = NULL; - } - i = j; - } - - /* ret is 2 for "print only" option */ - if (ret == 2) { - add_history(result); -#ifdef GDB_411_HACK - /* gdb 4.11 has been shipped with readline, where */ - /* history_expand() returned -1 when the line */ - /* should not be executed; in readline 2.1+ */ - /* it should return 2 in such a case */ - ret = -1; -#endif - } - el_free(*output); - *output = result; - - return ret; -} - -/* -* Return a string consisting of arguments of "str" from "start" to "end". -*/ -char * -history_arg_extract(int start, int end, const char *str) -{ - size_t i, len, max; - char **arr, *result = NULL; - - arr = history_tokenize(str); - if (!arr) - return NULL; - if (arr && *arr == NULL) - goto out; - - for (max = 0; arr[max]; max++) - continue; - max--; - - if (start == '$') - start = (int)max; - if (end == '$') - end = (int)max; - if (end < 0) - end = (int)max + end + 1; - if (start < 0) - start = end; - - if (start < 0 || end < 0 || (size_t)start > max || - (size_t)end > max || start > end) - goto out; - - for (i = (size_t)start, len = 0; i <= (size_t)end; i++) - len += strlen(arr[i]) + 1; - len++; - result = el_malloc(len * sizeof(*result)); - if (result == NULL) - goto out; - - for (i = (size_t)start, len = 0; i <= (size_t)end; i++) { - (void)strcpy(result + len, arr[i]); - len += strlen(arr[i]); - if (i < (size_t)end) - result[len++] = ' '; - } - result[len] = '\0'; - -out: - for (i = 0; arr[i]; i++) - el_free(arr[i]); - el_free(arr); - - return result; -} - -/* - * Parse the string into individual tokens, - * similar to how shell would do it. - */ -char ** -history_tokenize(const char *str) -{ - int size = 1, idx = 0, i, start; - size_t len; - char **result = NULL, *temp, delim = '\0'; - - for (i = 0; str[i];) { - while (isspace((unsigned char) str[i])) - i++; - start = i; - for (; str[i];) { - if (str[i] == '\\') { - if (str[i+1] != '\0') - i++; - } else if (str[i] == delim) - delim = '\0'; - else if (!delim && - (isspace((unsigned char) str[i]) || - strchr("()<>;&|$", str[i]))) - break; - else if (!delim && strchr("'`\"", str[i])) - delim = str[i]; - if (str[i]) - i++; - } - - if (idx + 2 >= size) { - char **nresult; - size <<= 1; - nresult = el_realloc(result, (size_t)size * sizeof(*nresult)); - if (nresult == NULL) { - el_free(result); - return NULL; - } - result = nresult; - } - len = (size_t)i - (size_t)start; - temp = el_malloc((size_t)(len + 1) * sizeof(*temp)); - if (temp == NULL) { - for (i = 0; i < idx; i++) - el_free(result[i]); - el_free(result); - return NULL; - } - (void)strncpy(temp, &str[start], len); - temp[len] = '\0'; - result[idx++] = temp; - result[idx] = NULL; - if (str[i]) - i++; - } - return result; -} - - -/* - * limit size of history record to ``max'' events - */ -void -stifle_history(int max) -{ - HistEvent ev; - - if (h == NULL || e == NULL) - rl_initialize(); - - if (history(h, &ev, H_SETSIZE, max) == 0) - max_input_history = max; -} - - -/* - * "unlimit" size of history - set the limit to maximum allowed int value - */ -int -unstifle_history(void) -{ - HistEvent ev; - int omax; - - history(h, &ev, H_SETSIZE, INT_MAX); - omax = max_input_history; - max_input_history = INT_MAX; - return omax; /* some value _must_ be returned */ -} - - -int -history_is_stifled(void) -{ - - /* cannot return true answer */ - return max_input_history != INT_MAX; -} - -static const char _history_tmp_template[] = "/tmp/.historyXXXXXX"; - -int -history_truncate_file (const char *filename, int nlines) -{ - int ret = 0; - FILE *fp, *tp; - char template[sizeof(_history_tmp_template)]; - char buf[4096]; - int fd; - char *cp; - off_t off; - int count = 0; - ssize_t left = 0; - - if (filename == NULL && (filename = _default_history_file()) == NULL) - return errno; - if ((fp = fopen(filename, "r+")) == NULL) - return errno; - strcpy(template, _history_tmp_template); - if ((fd = mkstemp(template)) == -1) { - ret = errno; - goto out1; - } - - if ((tp = fdopen(fd, "r+")) == NULL) { - close(fd); - ret = errno; - goto out2; - } - - for(;;) { - if (fread(buf, sizeof(buf), (size_t)1, fp) != 1) { - if (ferror(fp)) { - ret = errno; - break; - } - if (fseeko(fp, (off_t)sizeof(buf) * count, SEEK_SET) == - (off_t)-1) { - ret = errno; - break; - } - left = (ssize_t)fread(buf, (size_t)1, sizeof(buf), fp); - if (ferror(fp)) { - ret = errno; - break; - } - if (left == 0) { - count--; - left = sizeof(buf); - } else if (fwrite(buf, (size_t)left, (size_t)1, tp) - != 1) { - ret = errno; - break; - } - fflush(tp); - break; - } - if (fwrite(buf, sizeof(buf), (size_t)1, tp) != 1) { - ret = errno; - break; - } - count++; - } - if (ret) - goto out3; - cp = buf + left - 1; - if(*cp != '\n') - cp++; - for(;;) { - while (--cp >= buf) { - if (*cp == '\n') { - if (--nlines == 0) { - if (++cp >= buf + sizeof(buf)) { - count++; - cp = buf; - } - break; - } - } - } - if (nlines <= 0 || count == 0) - break; - count--; - if (fseeko(tp, (off_t)sizeof(buf) * count, SEEK_SET) < 0) { - ret = errno; - break; - } - if (fread(buf, sizeof(buf), (size_t)1, tp) != 1) { - if (ferror(tp)) { - ret = errno; - break; - } - ret = EAGAIN; - break; - } - cp = buf + sizeof(buf); - } - - if (ret || nlines > 0) - goto out3; - - if (fseeko(fp, (off_t)0, SEEK_SET) == (off_t)-1) { - ret = errno; - goto out3; - } - - if (fseeko(tp, (off_t)sizeof(buf) * count + (cp - buf), SEEK_SET) == - (off_t)-1) { - ret = errno; - goto out3; - } - - for(;;) { - if ((left = (ssize_t)fread(buf, (size_t)1, sizeof(buf), tp)) == 0) { - if (ferror(fp)) - ret = errno; - break; - } - if (fwrite(buf, (size_t)left, (size_t)1, fp) != 1) { - ret = errno; - break; - } - } - fflush(fp); - if((off = ftello(fp)) > 0) { - if (ftruncate(fileno(fp), off) == -1) - ret = errno; - } -out3: - fclose(tp); -out2: - unlink(template); -out1: - fclose(fp); - - return ret; -} - - -/* - * read history from a file given - */ -int -read_history(const char *filename) -{ - HistEvent ev; - - if (h == NULL || e == NULL) - rl_initialize(); - if (filename == NULL && (filename = _default_history_file()) == NULL) - return errno; - return history(h, &ev, H_LOAD, filename) == -1 ? - (errno ? errno : EINVAL) : 0; -} - - -/* - * write history to a file given - */ -int -write_history(const char *filename) -{ - HistEvent ev; - - if (h == NULL || e == NULL) - rl_initialize(); - if (filename == NULL && (filename = _default_history_file()) == NULL) - return errno; - return history(h, &ev, H_SAVE, filename) == -1 ? - (errno ? errno : EINVAL) : 0; -} - - -/* - * returns history ``num''th event - * - * returned pointer points to static variable - */ -HIST_ENTRY * -history_get(int num) -{ - static HIST_ENTRY she; - HistEvent ev; - int curr_num; - - if (h == NULL || e == NULL) - rl_initialize(); - - /* save current position */ - if (history(h, &ev, H_CURR) != 0) - return NULL; - curr_num = ev.num; - - /* start from the oldest */ - if (history(h, &ev, H_LAST) != 0) - return NULL; /* error */ - - /* look forwards for event matching specified offset */ - if (history(h, &ev, H_NEXT_EVDATA, num, &she.data)) - return NULL; - - she.line = ev.str; - - /* restore pointer to where it was */ - (void)history(h, &ev, H_SET, curr_num); - - return &she; -} - - -/* - * add the line to history table - */ -int -add_history(const char *line) -{ - HistEvent ev; - - if (h == NULL || e == NULL) - rl_initialize(); - - (void)history(h, &ev, H_ENTER, line); - if (history(h, &ev, H_GETSIZE) == 0) - history_length = ev.num; - - return !(history_length > 0); /* return 0 if all is okay */ -} - - -/* - * remove the specified entry from the history list and return it. - */ -HIST_ENTRY * -remove_history(int num) -{ - HIST_ENTRY *he; - HistEvent ev; - - if (h == NULL || e == NULL) - rl_initialize(); - - if ((he = el_malloc(sizeof(*he))) == NULL) - return NULL; - - if (history(h, &ev, H_DELDATA, num, &he->data) != 0) { - el_free(he); - return NULL; - } - - he->line = ev.str; - if (history(h, &ev, H_GETSIZE) == 0) - history_length = ev.num; - - return he; -} - - -/* - * replace the line and data of the num-th entry - */ -HIST_ENTRY * -replace_history_entry(int num, const char *line, histdata_t data) -{ - HIST_ENTRY *he; - HistEvent ev; - int curr_num; - - if (h == NULL || e == NULL) - rl_initialize(); - - /* save current position */ - if (history(h, &ev, H_CURR) != 0) - return NULL; - curr_num = ev.num; - - /* start from the oldest */ - if (history(h, &ev, H_LAST) != 0) - return NULL; /* error */ - - if ((he = el_malloc(sizeof(*he))) == NULL) - return NULL; - - /* look forwards for event matching specified offset */ - if (history(h, &ev, H_NEXT_EVDATA, num, &he->data)) - goto out; - - he->line = strdup(ev.str); - if (he->line == NULL) - goto out; - - if (history(h, &ev, H_REPLACE, line, data)) - goto out; - - /* restore pointer to where it was */ - if (history(h, &ev, H_SET, curr_num)) - goto out; - - return he; -out: - el_free(he); - return NULL; -} - -/* - * clear the history list - delete all entries - */ -void -clear_history(void) -{ - HistEvent ev; - - (void)history(h, &ev, H_CLEAR); - history_length = 0; -} - - -/* - * returns offset of the current history event - */ -int -where_history(void) -{ - HistEvent ev; - int curr_num, off; - - if (history(h, &ev, H_CURR) != 0) - return 0; - curr_num = ev.num; - - (void)history(h, &ev, H_FIRST); - off = 1; - while (ev.num != curr_num && history(h, &ev, H_NEXT) == 0) - off++; - - return off; -} - - -/* - * returns current history event or NULL if there is no such event - */ -HIST_ENTRY * -current_history(void) -{ - - return _move_history(H_CURR); -} - - -/* - * returns total number of bytes history events' data are using - */ -int -history_total_bytes(void) -{ - HistEvent ev; - int curr_num; - size_t size; - - if (history(h, &ev, H_CURR) != 0) - return -1; - curr_num = ev.num; - - (void)history(h, &ev, H_FIRST); - size = 0; - do - size += strlen(ev.str) * sizeof(*ev.str); - while (history(h, &ev, H_NEXT) == 0); - - /* get to the same position as before */ - history(h, &ev, H_PREV_EVENT, curr_num); - - return (int)size; -} - - -/* - * sets the position in the history list to ``pos'' - */ -int -history_set_pos(int pos) -{ - HistEvent ev; - int curr_num; - - if (pos >= history_length || pos < 0) - return -1; - - (void)history(h, &ev, H_CURR); - curr_num = ev.num; - - /* - * use H_DELDATA to set to nth history (without delete) by passing - * (void **)-1 - */ - if (history(h, &ev, H_DELDATA, pos, (void **)-1)) { - (void)history(h, &ev, H_SET, curr_num); - return -1; - } - return 0; -} - - -/* - * returns previous event in history and shifts pointer accordingly - */ -HIST_ENTRY * -previous_history(void) -{ - - return _move_history(H_PREV); -} - - -/* - * returns next event in history and shifts pointer accordingly - */ -HIST_ENTRY * -next_history(void) -{ - - return _move_history(H_NEXT); -} - - -/* - * searches for first history event containing the str - */ -int -history_search(const char *str, int direction) -{ - HistEvent ev; - const char *strp; - int curr_num; - - if (history(h, &ev, H_CURR) != 0) - return -1; - curr_num = ev.num; - - for (;;) { - if ((strp = strstr(ev.str, str)) != NULL) - return (int)(strp - ev.str); - if (history(h, &ev, direction < 0 ? H_NEXT:H_PREV) != 0) - break; - } - (void)history(h, &ev, H_SET, curr_num); - return -1; -} - - -/* - * searches for first history event beginning with str - */ -int -history_search_prefix(const char *str, int direction) -{ - HistEvent ev; - - return (history(h, &ev, direction < 0 ? - H_PREV_STR : H_NEXT_STR, str)); -} - - -/* - * search for event in history containing str, starting at offset - * abs(pos); continue backward, if pos<0, forward otherwise - */ -/* ARGSUSED */ -int -history_search_pos(const char *str, - int direction __attribute__((__unused__)), int pos) -{ - HistEvent ev; - int curr_num, off; - - off = (pos > 0) ? pos : -pos; - pos = (pos > 0) ? 1 : -1; - - if (history(h, &ev, H_CURR) != 0) - return -1; - curr_num = ev.num; - - if (history_set_pos(off) != 0 || history(h, &ev, H_CURR) != 0) - return -1; - - for (;;) { - if (strstr(ev.str, str)) - return off; - if (history(h, &ev, (pos < 0) ? H_PREV : H_NEXT) != 0) - break; - } - - /* set "current" pointer back to previous state */ - (void)history(h, &ev, - pos < 0 ? H_NEXT_EVENT : H_PREV_EVENT, curr_num); - - return -1; -} - - -/********************************/ -/* completion functions */ - -char * -tilde_expand(char *name) -{ - return fn_tilde_expand(name); -} - -char * -filename_completion_function(const char *name, int state) -{ - return fn_filename_completion_function(name, state); -} - -/* - * a completion generator for usernames; returns _first_ username - * which starts with supplied text - * text contains a partial username preceded by random character - * (usually '~'); state resets search from start (??? should we do that anyway) - * it's callers responsibility to free returned value - */ -char * -username_completion_function(const char *text, int state) -{ -#if defined(HAVE_GETPW_R_POSIX) || defined(HAVE_GETPW_R_DRAFT) - struct passwd pwres; - char pwbuf[1024]; -#endif - struct passwd *pass = NULL; - - if (text[0] == '\0') - return NULL; - - if (*text == '~') - text++; - - if (state == 0) - setpwent(); - - while ( -#if defined(HAVE_GETPW_R_POSIX) || defined(HAVE_GETPW_R_DRAFT) - getpwent_r(&pwres, pwbuf, sizeof(pwbuf), &pass) == 0 && pass != NULL -#else - (pass = getpwent()) != NULL -#endif - && text[0] == pass->pw_name[0] - && strcmp(text, pass->pw_name) == 0) - continue; - - if (pass == NULL) { - endpwent(); - return NULL; - } - return strdup(pass->pw_name); -} - - -/* - * el-compatible wrapper to send TSTP on ^Z - */ -/* ARGSUSED */ -static unsigned char -_el_rl_tstp(EditLine *el __attribute__((__unused__)), int ch __attribute__((__unused__))) -{ - (void)kill(0, SIGTSTP); - return CC_NORM; -} - -/* - * Display list of strings in columnar format on readline's output stream. - * 'matches' is list of strings, 'len' is number of strings in 'matches', - * 'max' is maximum length of string in 'matches'. - */ -void -rl_display_match_list(char **matches, int len, int max) -{ - - fn_display_match_list(e, matches, (size_t)len, (size_t)max); -} - -static const char * -/*ARGSUSED*/ -_rl_completion_append_character_function(const char *dummy - __attribute__((__unused__))) -{ - static char buf[2]; - buf[0] = (char)rl_completion_append_character; - buf[1] = '\0'; - return buf; -} - - -/* - * complete word at current point - */ -/* ARGSUSED */ -int -rl_complete(int ignore __attribute__((__unused__)), int invoking_key) -{ -#ifdef WIDECHAR - static ct_buffer_t wbreak_conv, sprefix_conv; -#endif - - if (h == NULL || e == NULL) - rl_initialize(); - - if (rl_inhibit_completion) { - char arr[2]; - arr[0] = (char)invoking_key; - arr[1] = '\0'; - el_insertstr(e, arr); - return CC_REFRESH; - } - - /* Just look at how many global variables modify this operation! */ - return fn_complete(e, - (CPFunction *)rl_completion_entry_function, - rl_attempted_completion_function, - ct_decode_string(rl_basic_word_break_characters, &wbreak_conv), - ct_decode_string(rl_special_prefixes, &sprefix_conv), - _rl_completion_append_character_function, - (size_t)rl_completion_query_items, - &rl_completion_type, &rl_attempted_completion_over, - &rl_point, &rl_end); - - -} - - -/* ARGSUSED */ -static unsigned char -_el_rl_complete(EditLine *el __attribute__((__unused__)), int ch) -{ - return (unsigned char)rl_complete(0, ch); -} - -/* - * misc other functions - */ - -/* - * bind key c to readline-type function func - */ -int -rl_bind_key(int c, rl_command_func_t *func) -{ - int retval = -1; - - if (h == NULL || e == NULL) - rl_initialize(); - - if (func == rl_insert) { - /* XXX notice there is no range checking of ``c'' */ - e->el_map.key[c] = ED_INSERT; - retval = 0; - } - return retval; -} - - -/* - * read one key from input - handles chars pushed back - * to input stream also - */ -int -rl_read_key(void) -{ - char fooarr[2 * sizeof(int)]; - - if (e == NULL || h == NULL) - rl_initialize(); - - return el_getc(e, fooarr); -} - - -/* - * reset the terminal - */ -/* ARGSUSED */ -void -rl_reset_terminal(const char *p __attribute__((__unused__))) -{ - - if (h == NULL || e == NULL) - rl_initialize(); - el_reset(e); -} - - -/* - * insert character ``c'' back into input stream, ``count'' times - */ -int -rl_insert(int count, int c) -{ - char arr[2]; - - if (h == NULL || e == NULL) - rl_initialize(); - - /* XXX - int -> char conversion can lose on multichars */ - arr[0] = (char)c; - arr[1] = '\0'; - - for (; count > 0; count--) - el_push(e, arr); - - return 0; -} - -int -rl_insert_text(const char *text) -{ - if (!text || *text == 0) - return 0; - - if (h == NULL || e == NULL) - rl_initialize(); - - if (el_insertstr(e, text) < 0) - return 0; - return (int)strlen(text); -} - -/*ARGSUSED*/ -int -rl_newline(int count __attribute__((__unused__)), - int c __attribute__((__unused__))) -{ - /* - * Readline-4.0 appears to ignore the args. - */ - return rl_insert(1, '\n'); -} - -/*ARGSUSED*/ -static unsigned char -rl_bind_wrapper(EditLine *el __attribute__((__unused__)), unsigned char c) -{ - if (map[c] == NULL) - return CC_ERROR; - - _rl_update_pos(); - - (*map[c])(NULL, c); - - /* If rl_done was set by the above call, deal with it here */ - if (rl_done) - return CC_EOF; - - return CC_NORM; -} - -int -rl_add_defun(const char *name, Function *fun, int c) -{ - char dest[8]; - if ((size_t)c >= sizeof(map) / sizeof(map[0]) || c < 0) - return -1; - map[(unsigned char)c] = fun; - el_set(e, EL_ADDFN, name, name, rl_bind_wrapper); - vis(dest, c, VIS_WHITE|VIS_NOSLASH, 0); - el_set(e, EL_BIND, dest, name); - return 0; -} - -void -rl_callback_read_char() -{ - int count = 0, done = 0; - const char *buf = el_gets(e, &count); - char *wbuf; - - if (buf == NULL || count-- <= 0) - return; - if (count == 0 && buf[0] == e->el_tty.t_c[TS_IO][C_EOF]) - done = 1; - if (buf[count] == '\n' || buf[count] == '\r') - done = 2; - - if (done && rl_linefunc != NULL) { - el_set(e, EL_UNBUFFERED, 0); - if (done == 2) { - if ((wbuf = strdup(buf)) != NULL) - wbuf[count] = '\0'; - } else - wbuf = NULL; - (*(void (*)(const char *))rl_linefunc)(wbuf); - /*el_set(e, EL_UNBUFFERED, 1);*/ - } -} - -void -rl_callback_handler_install(const char *prompt, VCPFunction *linefunc) -{ - if (e == NULL) { - rl_initialize(); - } - (void)rl_set_prompt(prompt); - rl_linefunc = linefunc; - el_set(e, EL_UNBUFFERED, 1); -} - -void -rl_callback_handler_remove(void) -{ - el_set(e, EL_UNBUFFERED, 0); - rl_linefunc = NULL; -} - -void -rl_redisplay(void) -{ - char a[2]; - a[0] = (char)e->el_tty.t_c[TS_IO][C_REPRINT]; - a[1] = '\0'; - el_push(e, a); -} - -int -rl_get_previous_history(int count, int key) -{ - char a[2]; - a[0] = (char)key; - a[1] = '\0'; - while (count--) - el_push(e, a); - return 0; -} - -void -/*ARGSUSED*/ -rl_prep_terminal(int meta_flag __attribute__((__unused__))) -{ - el_set(e, EL_PREP_TERM, 1); -} - -void -rl_deprep_terminal(void) -{ - el_set(e, EL_PREP_TERM, 0); -} - -int -rl_read_init_file(const char *s) -{ - return el_source(e, s); -} - -int -rl_parse_and_bind(const char *line) -{ - const char **argv; - int argc; - Tokenizer *tok; - - tok = tok_init(NULL); - tok_str(tok, line, &argc, &argv); - argc = el_parse(e, argc, argv); - tok_end(tok); - return argc ? 1 : 0; -} - -int -rl_variable_bind(const char *var, const char *value) -{ - /* - * The proper return value is undocument, but this is what the - * readline source seems to do. - */ - return el_set(e, EL_BIND, "", var, value) == -1 ? 1 : 0; -} - -void -rl_stuff_char(int c) -{ - char buf[2]; - - buf[0] = (char)c; - buf[1] = '\0'; - el_insertstr(e, buf); -} - -static int -_rl_event_read_char(EditLine *el, char *cp) -{ - int n; - ssize_t num_read = 0; - - *cp = '\0'; - while (rl_event_hook) { - - (*rl_event_hook)(); - -#if defined(FIONREAD) - if (ioctl(el->el_infd, FIONREAD, &n) < 0) - return -1; - if (n) - num_read = read(el->el_infd, cp, (size_t)1); - else - num_read = 0; -#elif defined(F_SETFL) && defined(O_NDELAY) - if ((n = fcntl(el->el_infd, F_GETFL, 0)) < 0) - return -1; - if (fcntl(el->el_infd, F_SETFL, n|O_NDELAY) < 0) - return -1; - num_read = read(el->el_infd, cp, 1); - if (fcntl(el->el_infd, F_SETFL, n)) - return -1; -#else - /* not non-blocking, but what you gonna do? */ - num_read = read(el->el_infd, cp, 1); - return -1; -#endif - - if (num_read < 0 && errno == EAGAIN) - continue; - if (num_read == 0) - continue; - break; - } - if (!rl_event_hook) - el_set(el, EL_GETCFN, EL_BUILTIN_GETCFN); - return (int)num_read; -} - -static void -_rl_update_pos(void) -{ - const LineInfo *li = el_line(e); - - rl_point = (int)(li->cursor - li->buffer); - rl_end = (int)(li->lastchar - li->buffer); -} - -void -rl_get_screen_size(int *rows, int *cols) -{ - if (rows) - el_get(e, EL_GETTC, "li", rows); - if (cols) - el_get(e, EL_GETTC, "co", cols); -} - -void -rl_set_screen_size(int rows, int cols) -{ - char buf[64]; - (void)snprintf(buf, sizeof(buf), "%d", rows); - el_set(e, EL_SETTC, "li", buf); - (void)snprintf(buf, sizeof(buf), "%d", cols); - el_set(e, EL_SETTC, "co", buf); -} - -char ** -rl_completion_matches(const char *str, rl_compentry_func_t *fun) -{ - size_t len, max, i, j, min; - char **list, *match, *a, *b; - - len = 1; - max = 10; - if ((list = el_malloc(max * sizeof(*list))) == NULL) - return NULL; - - while ((match = (*fun)(str, (int)(len - 1))) != NULL) { - list[len++] = match; - if (len == max) { - char **nl; - max += 10; - if ((nl = el_realloc(list, max * sizeof(*nl))) == NULL) - goto out; - list = nl; - } - } - if (len == 1) - goto out; - list[len] = NULL; - if (len == 2) { - if ((list[0] = strdup(list[1])) == NULL) - goto out; - return list; - } - qsort(&list[1], len - 1, sizeof(*list), - (int (*)(const void *, const void *)) strcmp); - min = SIZE_T_MAX; - for (i = 1, a = list[i]; i < len - 1; i++, a = b) { - b = list[i + 1]; - for (j = 0; a[j] && a[j] == b[j]; j++) - continue; - if (min > j) - min = j; - } - if (min == 0 && *str) { - if ((list[0] = strdup(str)) == NULL) - goto out; - } else { - if ((list[0] = el_malloc((min + 1) * sizeof(*list[0]))) == NULL) - goto out; - (void)memcpy(list[0], list[1], min); - list[0][min] = '\0'; - } - return list; - -out: - el_free(list); - return NULL; -} - -char * -rl_filename_completion_function (const char *text, int state) -{ - return fn_filename_completion_function(text, state); -} - -void -rl_forced_update_display(void) -{ - el_set(e, EL_REFRESH); -} - -int -_rl_abort_internal(void) -{ - el_beep(e); - longjmp(topbuf, 1); - /*NOTREACHED*/ -} - -int -_rl_qsort_string_compare(char **s1, char **s2) -{ - return strcoll(*s1, *s2); -} - -HISTORY_STATE * -history_get_history_state(void) -{ - HISTORY_STATE *hs; - - if ((hs = el_malloc(sizeof(*hs))) == NULL) - return NULL; - hs->length = history_length; - return hs; -} - -int -/*ARGSUSED*/ -rl_kill_text(int from __attribute__((__unused__)), - int to __attribute__((__unused__))) -{ - return 0; -} - -Keymap -rl_make_bare_keymap(void) -{ - return NULL; -} - -Keymap -rl_get_keymap(void) -{ - return NULL; -} - -void -/*ARGSUSED*/ -rl_set_keymap(Keymap k __attribute__((__unused__))) -{ -} - -int -/*ARGSUSED*/ -rl_generic_bind(int type __attribute__((__unused__)), - const char * keyseq __attribute__((__unused__)), - const char * data __attribute__((__unused__)), - Keymap k __attribute__((__unused__))) -{ - return 0; -} - -int -/*ARGSUSED*/ -rl_bind_key_in_map(int key __attribute__((__unused__)), - rl_command_func_t *fun __attribute__((__unused__)), - Keymap k __attribute__((__unused__))) -{ - return 0; -} - -/* unsupported, but needed by python */ -void -rl_cleanup_after_signal(void) -{ -} - -int -rl_on_new_line(void) -{ - return 0; -} diff --git a/cmd-line-utils/libedit/readline/readline.h b/cmd-line-utils/libedit/readline/readline.h deleted file mode 100644 index d9efe3e01a8..00000000000 --- a/cmd-line-utils/libedit/readline/readline.h +++ /dev/null @@ -1,221 +0,0 @@ -/* $NetBSD: readline.h,v 1.32 2010/09/16 20:08:52 christos Exp $ */ - -/*- - * Copyright (c) 1997 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Jaromir Dolecek. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef _READLINE_H_ -#define _READLINE_H_ - -#include -#include - -/* list of readline stuff supported by editline library's readline wrapper */ - -/* typedefs */ -typedef int Function(const char *, int); -typedef void VFunction(void); -typedef void VCPFunction(char *); -typedef char *CPFunction(const char *, int); -typedef char **CPPFunction(const char *, int, int); -typedef char *rl_compentry_func_t(const char *, int); -typedef int rl_command_func_t(int, int); - -/* only supports length */ -typedef struct { - int length; -} HISTORY_STATE; - -typedef void *histdata_t; - -typedef struct _hist_entry { - const char *line; - histdata_t data; -} HIST_ENTRY; - -typedef struct _keymap_entry { - char type; -#define ISFUNC 0 -#define ISKMAP 1 -#define ISMACR 2 - Function *function; -} KEYMAP_ENTRY; - -#define KEYMAP_SIZE 256 - -typedef KEYMAP_ENTRY KEYMAP_ENTRY_ARRAY[KEYMAP_SIZE]; -typedef KEYMAP_ENTRY *Keymap; - -#define control_character_threshold 0x20 -#define control_character_bit 0x40 - -#ifndef CTRL -#include -#if !defined(__sun) && !defined(__hpux) && !defined(_AIX) && !defined(__QNXNTO__) && !defined(__USLC__) -#include -#endif -#ifndef CTRL -#define CTRL(c) ((c) & 037) -#endif -#endif -#ifndef UNCTRL -#define UNCTRL(c) (((c) - 'a' + 'A')|control_character_bit) -#endif - -#define RUBOUT 0x7f -#define ABORT_CHAR CTRL('G') -#define RL_READLINE_VERSION 0x0402 -#define RL_PROMPT_START_IGNORE '\1' -#define RL_PROMPT_END_IGNORE '\2' - -/* global variables used by readline enabled applications */ -#ifdef __cplusplus -extern "C" { -#endif -extern const char *rl_library_version; -extern int rl_readline_version; -extern char *rl_readline_name; -extern FILE *rl_instream; -extern FILE *rl_outstream; -extern char *rl_line_buffer; -extern int rl_point, rl_end; -extern int history_base, history_length; -extern int max_input_history; -extern char *rl_basic_word_break_characters; -extern char *rl_completer_word_break_characters; -extern char *rl_completer_quote_characters; -extern Function *rl_completion_entry_function; -extern CPPFunction *rl_attempted_completion_function; -extern int rl_attempted_completion_over; -extern int rl_completion_type; -extern int rl_completion_query_items; -extern char *rl_special_prefixes; -extern int rl_completion_append_character; -extern int rl_inhibit_completion; -extern Function *rl_pre_input_hook; -extern Function *rl_startup_hook; -extern char *rl_terminal_name; -extern int rl_already_prompted; -extern char *rl_prompt; -/* - * The following is not implemented - */ -extern KEYMAP_ENTRY_ARRAY emacs_standard_keymap, - emacs_meta_keymap, - emacs_ctlx_keymap; -extern int rl_filename_completion_desired; -extern int rl_ignore_completion_duplicates; -extern int (*rl_getc_function)(FILE *); -extern VFunction *rl_redisplay_function; -extern VFunction *rl_completion_display_matches_hook; -extern VFunction *rl_prep_term_function; -extern VFunction *rl_deprep_term_function; -extern int readline_echoing_p; -extern int _rl_print_completions_horizontally; - -/* supported functions */ -char *readline(const char *); -int rl_initialize(void); - -void using_history(void); -int add_history(const char *); -void clear_history(void); -void stifle_history(int); -int unstifle_history(void); -int history_is_stifled(void); -int where_history(void); -HIST_ENTRY *current_history(void); -HIST_ENTRY *history_get(int); -HIST_ENTRY *remove_history(int); -HIST_ENTRY *replace_history_entry(int, const char *, histdata_t); -int history_total_bytes(void); -int history_set_pos(int); -HIST_ENTRY *previous_history(void); -HIST_ENTRY *next_history(void); -int history_search(const char *, int); -int history_search_prefix(const char *, int); -int history_search_pos(const char *, int, int); -int read_history(const char *); -int write_history(const char *); -int history_truncate_file (const char *, int); -int history_expand(char *, char **); -char **history_tokenize(const char *); -const char *get_history_event(const char *, int *, int); -char *history_arg_extract(int, int, const char *); - -char *tilde_expand(char *); -char *filename_completion_function(const char *, int); -char *username_completion_function(const char *, int); -int rl_complete(int, int); -int rl_read_key(void); -char **completion_matches(const char *, CPFunction *); -void rl_display_match_list(char **, int, int); - -int rl_insert(int, int); -int rl_insert_text(const char *); -void rl_reset_terminal(const char *); -int rl_bind_key(int, rl_command_func_t *); -int rl_newline(int, int); -void rl_callback_read_char(void); -void rl_callback_handler_install(const char *, VCPFunction *); -void rl_callback_handler_remove(void); -void rl_redisplay(void); -int rl_get_previous_history(int, int); -void rl_prep_terminal(int); -void rl_deprep_terminal(void); -int rl_read_init_file(const char *); -int rl_parse_and_bind(const char *); -int rl_variable_bind(const char *, const char *); -void rl_stuff_char(int); -int rl_add_defun(const char *, Function *, int); -HISTORY_STATE *history_get_history_state(void); -void rl_get_screen_size(int *, int *); -void rl_set_screen_size(int, int); -char *rl_filename_completion_function (const char *, int); -int _rl_abort_internal(void); -int _rl_qsort_string_compare(char **, char **); -char **rl_completion_matches(const char *, rl_compentry_func_t *); -void rl_forced_update_display(void); -int rl_set_prompt(const char *); -int rl_on_new_line(void); - -/* - * The following are not implemented - */ -int rl_kill_text(int, int); -Keymap rl_get_keymap(void); -void rl_set_keymap(Keymap); -Keymap rl_make_bare_keymap(void); -int rl_generic_bind(int, const char *, const char *, Keymap); -int rl_bind_key_in_map(int, rl_command_func_t *, Keymap); -void rl_cleanup_after_signal(void); -void rl_free_line_state(void); -#ifdef __cplusplus -} -#endif - -#endif /* _READLINE_H_ */ diff --git a/cmd-line-utils/libedit/refresh.c b/cmd-line-utils/libedit/refresh.c deleted file mode 100644 index 64057eaabfe..00000000000 --- a/cmd-line-utils/libedit/refresh.c +++ /dev/null @@ -1,1182 +0,0 @@ -/* $NetBSD: refresh.c,v 1.37 2011/07/29 23:44:45 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)refresh.c 8.1 (Berkeley) 6/4/93"; -#else -#endif -#endif /* not lint && not SCCSID */ - -/* - * refresh.c: Lower level screen refreshing functions - */ -#include -#include -#include -#include - -#include "el.h" - -private void re_nextline(EditLine *); -private void re_addc(EditLine *, Int); -private void re_update_line(EditLine *, Char *, Char *, int); -private void re_insert (EditLine *, Char *, int, int, Char *, int); -private void re_delete(EditLine *, Char *, int, int, int); -private void re_fastputc(EditLine *, Int); -private void re_clear_eol(EditLine *, int, int, int); -private void re__strncopy(Char *, Char *, size_t); -private void re__copy_and_pad(Char *, const Char *, size_t); - -#ifdef DEBUG_REFRESH -private void re_printstr(EditLine *, const char *, char *, char *); -#define __F el->el_errfile -#define ELRE_ASSERT(a, b, c) do \ - if (/*CONSTCOND*/ a) { \ - (void) fprintf b; \ - c; \ - } \ - while (/*CONSTCOND*/0) -#define ELRE_DEBUG(a, b) ELRE_ASSERT(a,b,;) - -/* re_printstr(): - * Print a string on the debugging pty - */ -private void -re_printstr(EditLine *el, const char *str, char *f, char *t) -{ - - ELRE_DEBUG(1, (__F, "%s:\"", str)); - while (f < t) - ELRE_DEBUG(1, (__F, "%c", *f++ & 0177)); - ELRE_DEBUG(1, (__F, "\"\r\n")); -} -#else -#define ELRE_ASSERT(a, b, c) -#define ELRE_DEBUG(a, b) -#endif - -/* re_nextline(): - * Move to the next line or scroll - */ -private void -re_nextline(EditLine *el) -{ - el->el_refresh.r_cursor.h = 0; /* reset it. */ - - /* - * If we would overflow (input is longer than terminal size), - * emulate scroll by dropping first line and shuffling the rest. - * We do this via pointer shuffling - it's safe in this case - * and we avoid memcpy(). - */ - if (el->el_refresh.r_cursor.v + 1 >= el->el_terminal.t_size.v) { - int i, lins = el->el_terminal.t_size.v; - Char *firstline = el->el_vdisplay[0]; - - for(i = 1; i < lins; i++) - el->el_vdisplay[i - 1] = el->el_vdisplay[i]; - - firstline[0] = '\0'; /* empty the string */ - el->el_vdisplay[i - 1] = firstline; - } else - el->el_refresh.r_cursor.v++; - - ELRE_ASSERT(el->el_refresh.r_cursor.v >= el->el_terminal.t_size.v, - (__F, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n", - el->el_refresh.r_cursor.v, el->el_terminal.t_size.v), - abort()); -} - -/* re_addc(): - * Draw c, expanding tabs, control chars etc. - */ -private void -re_addc(EditLine *el, Int c) -{ - switch (ct_chr_class((Char)c)) { - case CHTYPE_TAB: /* expand the tab */ - for (;;) { - re_putc(el, ' ', 1); - if ((el->el_refresh.r_cursor.h & 07) == 0) - break; /* go until tab stop */ - } - break; - case CHTYPE_NL: { - int oldv = el->el_refresh.r_cursor.v; - re_putc(el, '\0', 0); /* assure end of line */ - if (oldv == el->el_refresh.r_cursor.v) /* XXX */ - re_nextline(el); - break; - } - case CHTYPE_PRINT: - re_putc(el, c, 1); - break; - default: { - Char visbuf[VISUAL_WIDTH_MAX]; - ssize_t i, n = - ct_visual_char(visbuf, VISUAL_WIDTH_MAX, (Char)c); - for (i = 0; n-- > 0; ++i) - re_putc(el, visbuf[i], 1); - break; - } - } -} - - -/* re_putc(): - * Draw the character given - */ -protected void -re_putc(EditLine *el, Int c, int shift) -{ - int i, w = Width(c); - ELRE_DEBUG(1, (__F, "printing %5x '%c'\r\n", c, c)); - - while (shift && (el->el_refresh.r_cursor.h + w > el->el_terminal.t_size.h)) - re_putc(el, ' ', 1); - - el->el_vdisplay[el->el_refresh.r_cursor.v] - [el->el_refresh.r_cursor.h] = c; - /* assumes !shift is only used for single-column chars */ - i = w; - while (--i > 0) - el->el_vdisplay[el->el_refresh.r_cursor.v] - [el->el_refresh.r_cursor.h + i] = MB_FILL_CHAR; - - if (!shift) - return; - - el->el_refresh.r_cursor.h += w; /* advance to next place */ - if (el->el_refresh.r_cursor.h >= el->el_terminal.t_size.h) { - /* assure end of line */ - el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_terminal.t_size.h] - = '\0'; - re_nextline(el); - } -} - - -/* re_refresh(): - * draws the new virtual screen image from the current input - * line, then goes line-by-line changing the real image to the new - * virtual image. The routine to re-draw a line can be replaced - * easily in hopes of a smarter one being placed there. - */ -protected void -re_refresh(EditLine *el) -{ - int i, rhdiff; - Char *cp, *st; - coord_t cur; -#ifdef notyet - size_t termsz; -#endif - - ELRE_DEBUG(1, (__F, "el->el_line.buffer = :%s:\r\n", - el->el_line.buffer)); - - /* reset the Drawing cursor */ - el->el_refresh.r_cursor.h = 0; - el->el_refresh.r_cursor.v = 0; - - /* temporarily draw rprompt to calculate its size */ - prompt_print(el, EL_RPROMPT); - - /* reset the Drawing cursor */ - el->el_refresh.r_cursor.h = 0; - el->el_refresh.r_cursor.v = 0; - - if (el->el_line.cursor >= el->el_line.lastchar) { - if (el->el_map.current == el->el_map.alt - && el->el_line.lastchar != el->el_line.buffer) - el->el_line.cursor = el->el_line.lastchar - 1; - else - el->el_line.cursor = el->el_line.lastchar; - } - - cur.h = -1; /* set flag in case I'm not set */ - cur.v = 0; - - prompt_print(el, EL_PROMPT); - - /* draw the current input buffer */ -#if notyet - termsz = el->el_terminal.t_size.h * el->el_terminal.t_size.v; - if (el->el_line.lastchar - el->el_line.buffer > termsz) { - /* - * If line is longer than terminal, process only part - * of line which would influence display. - */ - size_t rem = (el->el_line.lastchar-el->el_line.buffer)%termsz; - - st = el->el_line.lastchar - rem - - (termsz - (((rem / el->el_terminal.t_size.v) - 1) - * el->el_terminal.t_size.v)); - } else -#endif - st = el->el_line.buffer; - - for (cp = st; cp < el->el_line.lastchar; cp++) { - if (cp == el->el_line.cursor) { - int w = Width(*cp); - /* save for later */ - cur.h = el->el_refresh.r_cursor.h; - cur.v = el->el_refresh.r_cursor.v; - /* handle being at a linebroken doublewidth char */ - if (w > 1 && el->el_refresh.r_cursor.h + w > - el->el_terminal.t_size.h) { - cur.h = 0; - cur.v++; - } - } - re_addc(el, *cp); - } - - if (cur.h == -1) { /* if I haven't been set yet, I'm at the end */ - cur.h = el->el_refresh.r_cursor.h; - cur.v = el->el_refresh.r_cursor.v; - } - rhdiff = el->el_terminal.t_size.h - el->el_refresh.r_cursor.h - - el->el_rprompt.p_pos.h; - if (el->el_rprompt.p_pos.h && !el->el_rprompt.p_pos.v && - !el->el_refresh.r_cursor.v && rhdiff > 1) { - /* - * have a right-hand side prompt that will fit - * on the end of the first line with at least - * one character gap to the input buffer. - */ - while (--rhdiff > 0) /* pad out with spaces */ - re_putc(el, ' ', 1); - prompt_print(el, EL_RPROMPT); - } else { - el->el_rprompt.p_pos.h = 0; /* flag "not using rprompt" */ - el->el_rprompt.p_pos.v = 0; - } - - re_putc(el, '\0', 0); /* make line ended with NUL, no cursor shift */ - - el->el_refresh.r_newcv = el->el_refresh.r_cursor.v; - - ELRE_DEBUG(1, (__F, - "term.h=%d vcur.h=%d vcur.v=%d vdisplay[0]=\r\n:%80.80s:\r\n", - el->el_terminal.t_size.h, el->el_refresh.r_cursor.h, - el->el_refresh.r_cursor.v, ct_encode_string(el->el_vdisplay[0]))); - - ELRE_DEBUG(1, (__F, "updating %d lines.\r\n", el->el_refresh.r_newcv)); - for (i = 0; i <= el->el_refresh.r_newcv; i++) { - /* NOTE THAT re_update_line MAY CHANGE el_display[i] */ - re_update_line(el, el->el_display[i], el->el_vdisplay[i], i); - - /* - * Copy the new line to be the current one, and pad out with - * spaces to the full width of the terminal so that if we try - * moving the cursor by writing the character that is at the - * end of the screen line, it won't be a NUL or some old - * leftover stuff. - */ - re__copy_and_pad(el->el_display[i], el->el_vdisplay[i], - (size_t) el->el_terminal.t_size.h); - } - ELRE_DEBUG(1, (__F, - "\r\nel->el_refresh.r_cursor.v=%d,el->el_refresh.r_oldcv=%d i=%d\r\n", - el->el_refresh.r_cursor.v, el->el_refresh.r_oldcv, i)); - - if (el->el_refresh.r_oldcv > el->el_refresh.r_newcv) - for (; i <= el->el_refresh.r_oldcv; i++) { - terminal_move_to_line(el, i); - terminal_move_to_char(el, 0); - /* This Strlen should be safe even with MB_FILL_CHARs */ - terminal_clear_EOL(el, (int) Strlen(el->el_display[i])); -#ifdef DEBUG_REFRESH - terminal_overwrite(el, "C\b", (size_t)2); -#endif /* DEBUG_REFRESH */ - el->el_display[i][0] = '\0'; - } - - el->el_refresh.r_oldcv = el->el_refresh.r_newcv; /* set for next time */ - ELRE_DEBUG(1, (__F, - "\r\ncursor.h = %d, cursor.v = %d, cur.h = %d, cur.v = %d\r\n", - el->el_refresh.r_cursor.h, el->el_refresh.r_cursor.v, - cur.h, cur.v)); - terminal_move_to_line(el, cur.v); /* go to where the cursor is */ - terminal_move_to_char(el, cur.h); -} - - -/* re_goto_bottom(): - * used to go to last used screen line - */ -protected void -re_goto_bottom(EditLine *el) -{ - - terminal_move_to_line(el, el->el_refresh.r_oldcv); - terminal__putc(el, '\n'); - re_clear_display(el); - terminal__flush(el); -} - - -/* re_insert(): - * insert num characters of s into d (in front of the character) - * at dat, maximum length of d is dlen - */ -private void -/*ARGSUSED*/ -re_insert(EditLine *el __attribute__((__unused__)), - Char *d, int dat, int dlen, Char *s, int num) -{ - Char *a, *b; - - if (num <= 0) - return; - if (num > dlen - dat) - num = dlen - dat; - - ELRE_DEBUG(1, - (__F, "re_insert() starting: %d at %d max %d, d == \"%s\"\n", - num, dat, dlen, ct_encode_string(d))); - ELRE_DEBUG(1, (__F, "s == \"%s\"\n", ct_encode_string(s))); - - /* open up the space for num chars */ - if (num > 0) { - b = d + dlen - 1; - a = b - num; - while (a >= &d[dat]) - *b-- = *a--; - d[dlen] = '\0'; /* just in case */ - } - - ELRE_DEBUG(1, (__F, - "re_insert() after insert: %d at %d max %d, d == \"%s\"\n", - num, dat, dlen, ct_encode_string(d))); - ELRE_DEBUG(1, (__F, "s == \"%s\"\n", ct_encode_string(s))); - - /* copy the characters */ - for (a = d + dat; (a < d + dlen) && (num > 0); num--) - *a++ = *s++; - -#ifdef notyet - /* ct_encode_string() uses a static buffer, so we can't conveniently - * encode both d & s here */ - ELRE_DEBUG(1, - (__F, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n", - num, dat, dlen, d, s)); - ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s)); -#endif -} - - -/* re_delete(): - * delete num characters d at dat, maximum length of d is dlen - */ -private void -/*ARGSUSED*/ -re_delete(EditLine *el __attribute__((__unused__)), - Char *d, int dat, int dlen, int num) -{ - Char *a, *b; - - if (num <= 0) - return; - if (dat + num >= dlen) { - d[dat] = '\0'; - return; - } - ELRE_DEBUG(1, - (__F, "re_delete() starting: %d at %d max %d, d == \"%s\"\n", - num, dat, dlen, ct_encode_string(d))); - - /* open up the space for num chars */ - if (num > 0) { - b = d + dat; - a = b + num; - while (a < &d[dlen]) - *b++ = *a++; - d[dlen] = '\0'; /* just in case */ - } - ELRE_DEBUG(1, - (__F, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n", - num, dat, dlen, ct_encode_string(d))); -} - - -/* re__strncopy(): - * Like strncpy without padding. - */ -private void -re__strncopy(Char *a, Char *b, size_t n) -{ - - while (n-- && *b) - *a++ = *b++; -} - -/* re_clear_eol(): - * Find the number of characters we need to clear till the end of line - * in order to make sure that we have cleared the previous contents of - * the line. fx and sx is the number of characters inserted or deleted - * in the first or second diff, diff is the difference between the - * number of characters between the new and old line. - */ -private void -re_clear_eol(EditLine *el, int fx, int sx, int diff) -{ - - ELRE_DEBUG(1, (__F, "re_clear_eol sx %d, fx %d, diff %d\n", - sx, fx, diff)); - - if (fx < 0) - fx = -fx; - if (sx < 0) - sx = -sx; - if (fx > diff) - diff = fx; - if (sx > diff) - diff = sx; - - ELRE_DEBUG(1, (__F, "re_clear_eol %d\n", diff)); - terminal_clear_EOL(el, diff); -} - -/***************************************************************** - re_update_line() is based on finding the middle difference of each line - on the screen; vis: - - /old first difference - /beginning of line | /old last same /old EOL - v v v v -old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as -new: eddie> Oh, my little buggy says to me, as lurgid as - ^ ^ ^ ^ - \beginning of line | \new last same \new end of line - \new first difference - - all are character pointers for the sake of speed. Special cases for - no differences, as well as for end of line additions must be handled. -**************************************************************** */ - -/* Minimum at which doing an insert it "worth it". This should be about - * half the "cost" of going into insert mode, inserting a character, and - * going back out. This should really be calculated from the termcap - * data... For the moment, a good number for ANSI terminals. - */ -#define MIN_END_KEEP 4 - -private void -re_update_line(EditLine *el, Char *old, Char *new, int i) -{ - Char *o, *n, *p, c; - Char *ofd, *ols, *oe, *nfd, *nls, *ne; - Char *osb, *ose, *nsb, *nse; - int fx, sx; - size_t len; - - /* - * find first diff - */ - for (o = old, n = new; *o && (*o == *n); o++, n++) - continue; - ofd = o; - nfd = n; - - /* - * Find the end of both old and new - */ - while (*o) - o++; - /* - * Remove any trailing blanks off of the end, being careful not to - * back up past the beginning. - */ - while (ofd < o) { - if (o[-1] != ' ') - break; - o--; - } - oe = o; - *oe = '\0'; - - while (*n) - n++; - - /* remove blanks from end of new */ - while (nfd < n) { - if (n[-1] != ' ') - break; - n--; - } - ne = n; - *ne = '\0'; - - /* - * if no diff, continue to next line of redraw - */ - if (*ofd == '\0' && *nfd == '\0') { - ELRE_DEBUG(1, (__F, "no difference.\r\n")); - return; - } - /* - * find last same pointer - */ - while ((o > ofd) && (n > nfd) && (*--o == *--n)) - continue; - ols = ++o; - nls = ++n; - - /* - * find same begining and same end - */ - osb = ols; - nsb = nls; - ose = ols; - nse = nls; - - /* - * case 1: insert: scan from nfd to nls looking for *ofd - */ - if (*ofd) { - for (c = *ofd, n = nfd; n < nls; n++) { - if (c == *n) { - for (o = ofd, p = n; - p < nls && o < ols && *o == *p; - o++, p++) - continue; - /* - * if the new match is longer and it's worth - * keeping, then we take it - */ - if (((nse - nsb) < (p - n)) && - (2 * (p - n) > n - nfd)) { - nsb = n; - nse = p; - osb = ofd; - ose = o; - } - } - } - } - /* - * case 2: delete: scan from ofd to ols looking for *nfd - */ - if (*nfd) { - for (c = *nfd, o = ofd; o < ols; o++) { - if (c == *o) { - for (n = nfd, p = o; - p < ols && n < nls && *p == *n; - p++, n++) - continue; - /* - * if the new match is longer and it's worth - * keeping, then we take it - */ - if (((ose - osb) < (p - o)) && - (2 * (p - o) > o - ofd)) { - nsb = nfd; - nse = n; - osb = o; - ose = p; - } - } - } - } - /* - * Pragmatics I: If old trailing whitespace or not enough characters to - * save to be worth it, then don't save the last same info. - */ - if ((oe - ols) < MIN_END_KEEP) { - ols = oe; - nls = ne; - } - /* - * Pragmatics II: if the terminal isn't smart enough, make the data - * dumber so the smart update doesn't try anything fancy - */ - - /* - * fx is the number of characters we need to insert/delete: in the - * beginning to bring the two same begins together - */ - fx = (int)((nsb - nfd) - (osb - ofd)); - /* - * sx is the number of characters we need to insert/delete: in the - * end to bring the two same last parts together - */ - sx = (int)((nls - nse) - (ols - ose)); - - if (!EL_CAN_INSERT) { - if (fx > 0) { - osb = ols; - ose = ols; - nsb = nls; - nse = nls; - } - if (sx > 0) { - ols = oe; - nls = ne; - } - if ((ols - ofd) < (nls - nfd)) { - ols = oe; - nls = ne; - } - } - if (!EL_CAN_DELETE) { - if (fx < 0) { - osb = ols; - ose = ols; - nsb = nls; - nse = nls; - } - if (sx < 0) { - ols = oe; - nls = ne; - } - if ((ols - ofd) > (nls - nfd)) { - ols = oe; - nls = ne; - } - } - /* - * Pragmatics III: make sure the middle shifted pointers are correct if - * they don't point to anything (we may have moved ols or nls). - */ - /* if the change isn't worth it, don't bother */ - /* was: if (osb == ose) */ - if ((ose - osb) < MIN_END_KEEP) { - osb = ols; - ose = ols; - nsb = nls; - nse = nls; - } - /* - * Now that we are done with pragmatics we recompute fx, sx - */ - fx = (int)((nsb - nfd) - (osb - ofd)); - sx = (int)((nls - nse) - (ols - ose)); - - ELRE_DEBUG(1, (__F, "fx %d, sx %d\n", fx, sx)); - ELRE_DEBUG(1, (__F, "ofd %d, osb %d, ose %d, ols %d, oe %d\n", - ofd - old, osb - old, ose - old, ols - old, oe - old)); - ELRE_DEBUG(1, (__F, "nfd %d, nsb %d, nse %d, nls %d, ne %d\n", - nfd - new, nsb - new, nse - new, nls - new, ne - new)); - ELRE_DEBUG(1, (__F, - "xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n")); - ELRE_DEBUG(1, (__F, - "xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n")); -#ifdef DEBUG_REFRESH - re_printstr(el, "old- oe", old, oe); - re_printstr(el, "new- ne", new, ne); - re_printstr(el, "old-ofd", old, ofd); - re_printstr(el, "new-nfd", new, nfd); - re_printstr(el, "ofd-osb", ofd, osb); - re_printstr(el, "nfd-nsb", nfd, nsb); - re_printstr(el, "osb-ose", osb, ose); - re_printstr(el, "nsb-nse", nsb, nse); - re_printstr(el, "ose-ols", ose, ols); - re_printstr(el, "nse-nls", nse, nls); - re_printstr(el, "ols- oe", ols, oe); - re_printstr(el, "nls- ne", nls, ne); -#endif /* DEBUG_REFRESH */ - - /* - * el_cursor.v to this line i MUST be in this routine so that if we - * don't have to change the line, we don't move to it. el_cursor.h to - * first diff char - */ - terminal_move_to_line(el, i); - - /* - * at this point we have something like this: - * - * /old /ofd /osb /ose /ols /oe - * v.....................v v..................v v........v - * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as - * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as - * ^.....................^ ^..................^ ^........^ - * \new \nfd \nsb \nse \nls \ne - * - * fx is the difference in length between the chars between nfd and - * nsb, and the chars between ofd and osb, and is thus the number of - * characters to delete if < 0 (new is shorter than old, as above), - * or insert (new is longer than short). - * - * sx is the same for the second differences. - */ - - /* - * if we have a net insert on the first difference, AND inserting the - * net amount ((nsb-nfd) - (osb-ofd)) won't push the last useful - * character (which is ne if nls != ne, otherwise is nse) off the edge - * of the screen (el->el_terminal.t_size.h) else we do the deletes first - * so that we keep everything we need to. - */ - - /* - * if the last same is the same like the end, there is no last same - * part, otherwise we want to keep the last same part set p to the - * last useful old character - */ - p = (ols != oe) ? oe : ose; - - /* - * if (There is a diffence in the beginning) && (we need to insert - * characters) && (the number of characters to insert is less than - * the term width) - * We need to do an insert! - * else if (we need to delete characters) - * We need to delete characters! - * else - * No insert or delete - */ - if ((nsb != nfd) && fx > 0 && - ((p - old) + fx <= el->el_terminal.t_size.h)) { - ELRE_DEBUG(1, - (__F, "first diff insert at %d...\r\n", nfd - new)); - /* - * Move to the first char to insert, where the first diff is. - */ - terminal_move_to_char(el, (int)(nfd - new)); - /* - * Check if we have stuff to keep at end - */ - if (nsb != ne) { - ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n")); - /* - * insert fx chars of new starting at nfd - */ - if (fx > 0) { - ELRE_DEBUG(!EL_CAN_INSERT, (__F, - "ERROR: cannot insert in early first diff\n")); - terminal_insertwrite(el, nfd, fx); - re_insert(el, old, (int)(ofd - old), - el->el_terminal.t_size.h, nfd, fx); - } - /* - * write (nsb-nfd) - fx chars of new starting at - * (nfd + fx) - */ - len = (size_t) ((nsb - nfd) - fx); - terminal_overwrite(el, (nfd + fx), len); - re__strncopy(ofd + fx, nfd + fx, len); - } else { - ELRE_DEBUG(1, (__F, "without anything to save\r\n")); - len = (size_t)(nsb - nfd); - terminal_overwrite(el, nfd, len); - re__strncopy(ofd, nfd, len); - /* - * Done - */ - return; - } - } else if (fx < 0) { - ELRE_DEBUG(1, - (__F, "first diff delete at %d...\r\n", ofd - old)); - /* - * move to the first char to delete where the first diff is - */ - terminal_move_to_char(el, (int)(ofd - old)); - /* - * Check if we have stuff to save - */ - if (osb != oe) { - ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n")); - /* - * fx is less than zero *always* here but we check - * for code symmetry - */ - if (fx < 0) { - ELRE_DEBUG(!EL_CAN_DELETE, (__F, - "ERROR: cannot delete in first diff\n")); - terminal_deletechars(el, -fx); - re_delete(el, old, (int)(ofd - old), - el->el_terminal.t_size.h, -fx); - } - /* - * write (nsb-nfd) chars of new starting at nfd - */ - len = (size_t) (nsb - nfd); - terminal_overwrite(el, nfd, len); - re__strncopy(ofd, nfd, len); - - } else { - ELRE_DEBUG(1, (__F, - "but with nothing left to save\r\n")); - /* - * write (nsb-nfd) chars of new starting at nfd - */ - terminal_overwrite(el, nfd, (size_t)(nsb - nfd)); - re_clear_eol(el, fx, sx, - (int)((oe - old) - (ne - new))); - /* - * Done - */ - return; - } - } else - fx = 0; - - if (sx < 0 && (ose - old) + fx < el->el_terminal.t_size.h) { - ELRE_DEBUG(1, (__F, - "second diff delete at %d...\r\n", (ose - old) + fx)); - /* - * Check if we have stuff to delete - */ - /* - * fx is the number of characters inserted (+) or deleted (-) - */ - - terminal_move_to_char(el, (int)((ose - old) + fx)); - /* - * Check if we have stuff to save - */ - if (ols != oe) { - ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n")); - /* - * Again a duplicate test. - */ - if (sx < 0) { - ELRE_DEBUG(!EL_CAN_DELETE, (__F, - "ERROR: cannot delete in second diff\n")); - terminal_deletechars(el, -sx); - } - /* - * write (nls-nse) chars of new starting at nse - */ - terminal_overwrite(el, nse, (size_t)(nls - nse)); - } else { - ELRE_DEBUG(1, (__F, - "but with nothing left to save\r\n")); - terminal_overwrite(el, nse, (size_t)(nls - nse)); - re_clear_eol(el, fx, sx, - (int)((oe - old) - (ne - new))); - } - } - /* - * if we have a first insert AND WE HAVEN'T ALREADY DONE IT... - */ - if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) { - ELRE_DEBUG(1, (__F, "late first diff insert at %d...\r\n", - nfd - new)); - - terminal_move_to_char(el, (int)(nfd - new)); - /* - * Check if we have stuff to keep at the end - */ - if (nsb != ne) { - ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n")); - /* - * We have to recalculate fx here because we set it - * to zero above as a flag saying that we hadn't done - * an early first insert. - */ - fx = (int)((nsb - nfd) - (osb - ofd)); - if (fx > 0) { - /* - * insert fx chars of new starting at nfd - */ - ELRE_DEBUG(!EL_CAN_INSERT, (__F, - "ERROR: cannot insert in late first diff\n")); - terminal_insertwrite(el, nfd, fx); - re_insert(el, old, (int)(ofd - old), - el->el_terminal.t_size.h, nfd, fx); - } - /* - * write (nsb-nfd) - fx chars of new starting at - * (nfd + fx) - */ - len = (size_t) ((nsb - nfd) - fx); - terminal_overwrite(el, (nfd + fx), len); - re__strncopy(ofd + fx, nfd + fx, len); - } else { - ELRE_DEBUG(1, (__F, "without anything to save\r\n")); - len = (size_t) (nsb - nfd); - terminal_overwrite(el, nfd, len); - re__strncopy(ofd, nfd, len); - } - } - /* - * line is now NEW up to nse - */ - if (sx >= 0) { - ELRE_DEBUG(1, (__F, - "second diff insert at %d...\r\n", (int)(nse - new))); - terminal_move_to_char(el, (int)(nse - new)); - if (ols != oe) { - ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n")); - if (sx > 0) { - /* insert sx chars of new starting at nse */ - ELRE_DEBUG(!EL_CAN_INSERT, (__F, - "ERROR: cannot insert in second diff\n")); - terminal_insertwrite(el, nse, sx); - } - /* - * write (nls-nse) - sx chars of new starting at - * (nse + sx) - */ - terminal_overwrite(el, (nse + sx), - (size_t)((nls - nse) - sx)); - } else { - ELRE_DEBUG(1, (__F, "without anything to save\r\n")); - terminal_overwrite(el, nse, (size_t)(nls - nse)); - - /* - * No need to do a clear-to-end here because we were - * doing a second insert, so we will have over - * written all of the old string. - */ - } - } - ELRE_DEBUG(1, (__F, "done.\r\n")); -} - - -/* re__copy_and_pad(): - * Copy string and pad with spaces - */ -private void -re__copy_and_pad(Char *dst, const Char *src, size_t width) -{ - size_t i; - - for (i = 0; i < width; i++) { - if (*src == '\0') - break; - *dst++ = *src++; - } - - for (; i < width; i++) - *dst++ = ' '; - - *dst = '\0'; -} - - -/* re_refresh_cursor(): - * Move to the new cursor position - */ -protected void -re_refresh_cursor(EditLine *el) -{ - Char *cp; - int h, v, th, w; - - if (el->el_line.cursor >= el->el_line.lastchar) { - if (el->el_map.current == el->el_map.alt - && el->el_line.lastchar != el->el_line.buffer) - el->el_line.cursor = el->el_line.lastchar - 1; - else - el->el_line.cursor = el->el_line.lastchar; - } - - /* first we must find where the cursor is... */ - h = el->el_prompt.p_pos.h; - v = el->el_prompt.p_pos.v; - th = el->el_terminal.t_size.h; /* optimize for speed */ - - /* do input buffer to el->el_line.cursor */ - for (cp = el->el_line.buffer; cp < el->el_line.cursor; cp++) { - switch (ct_chr_class(*cp)) { - case CHTYPE_NL: /* handle newline in data part too */ - h = 0; - v++; - break; - case CHTYPE_TAB: /* if a tab, to next tab stop */ - while (++h & 07) - continue; - break; - default: - w = Width(*cp); - if (w > 1 && h + w > th) { /* won't fit on line */ - h = 0; - v++; - } - h += ct_visual_width(*cp); - break; - } - - if (h >= th) { /* check, extra long tabs picked up here also */ - h -= th; - v++; - } - } - /* if we have a next character, and it's a doublewidth one, we need to - * check whether we need to linebreak for it to fit */ - if (cp < el->el_line.lastchar && (w = Width(*cp)) > 1) - if (h + w > th) { - h = 0; - v++; - } - - /* now go there */ - terminal_move_to_line(el, v); - terminal_move_to_char(el, h); - terminal__flush(el); -} - - -/* re_fastputc(): - * Add a character fast. - */ -private void -re_fastputc(EditLine *el, Int c) -{ - int w = Width((Char)c); - while (w > 1 && el->el_cursor.h + w > el->el_terminal.t_size.h) - re_fastputc(el, ' '); - - terminal__putc(el, c); - el->el_display[el->el_cursor.v][el->el_cursor.h++] = c; - while (--w > 0) - el->el_display[el->el_cursor.v][el->el_cursor.h++] - = MB_FILL_CHAR; - - if (el->el_cursor.h >= el->el_terminal.t_size.h) { - /* if we must overflow */ - el->el_cursor.h = 0; - - /* - * If we would overflow (input is longer than terminal size), - * emulate scroll by dropping first line and shuffling the rest. - * We do this via pointer shuffling - it's safe in this case - * and we avoid memcpy(). - */ - if (el->el_cursor.v + 1 >= el->el_terminal.t_size.v) { - int i, lins = el->el_terminal.t_size.v; - Char *firstline = el->el_display[0]; - - for(i = 1; i < lins; i++) - el->el_display[i - 1] = el->el_display[i]; - - re__copy_and_pad(firstline, STR(""), (size_t)0); - el->el_display[i - 1] = firstline; - } else { - el->el_cursor.v++; - el->el_refresh.r_oldcv++; - } - if (EL_HAS_AUTO_MARGINS) { - if (EL_HAS_MAGIC_MARGINS) { - terminal__putc(el, ' '); - terminal__putc(el, '\b'); - } - } else { - terminal__putc(el, '\r'); - terminal__putc(el, '\n'); - } - } -} - - -/* re_fastaddc(): - * we added just one char, handle it fast. - * Assumes that screen cursor == real cursor - */ -protected void -re_fastaddc(EditLine *el) -{ - Char c; - int rhdiff; - - c = el->el_line.cursor[-1]; - - if (c == '\t' || el->el_line.cursor != el->el_line.lastchar) { - re_refresh(el); /* too hard to handle */ - return; - } - rhdiff = el->el_terminal.t_size.h - el->el_cursor.h - - el->el_rprompt.p_pos.h; - if (el->el_rprompt.p_pos.h && rhdiff < 3) { - re_refresh(el); /* clear out rprompt if less than 1 char gap */ - return; - } /* else (only do at end of line, no TAB) */ - switch (ct_chr_class(c)) { - case CHTYPE_TAB: /* already handled, should never happen here */ - break; - case CHTYPE_NL: - case CHTYPE_PRINT: - re_fastputc(el, c); - break; - case CHTYPE_ASCIICTL: - case CHTYPE_NONPRINT: { - Char visbuf[VISUAL_WIDTH_MAX]; - ssize_t i, n = - ct_visual_char(visbuf, VISUAL_WIDTH_MAX, (Char)c); - for (i = 0; n-- > 0; ++i) - re_fastputc(el, visbuf[i]); - break; - } - } - terminal__flush(el); -} - - -/* re_clear_display(): - * clear the screen buffers so that new new prompt starts fresh. - */ -protected void -re_clear_display(EditLine *el) -{ - int i; - - el->el_cursor.v = 0; - el->el_cursor.h = 0; - for (i = 0; i < el->el_terminal.t_size.v; i++) - el->el_display[i][0] = '\0'; - el->el_refresh.r_oldcv = 0; -} - - -/* re_clear_lines(): - * Make sure all lines are *really* blank - */ -protected void -re_clear_lines(EditLine *el) -{ - - if (EL_CAN_CEOL) { - int i; - for (i = el->el_refresh.r_oldcv; i >= 0; i--) { - /* for each line on the screen */ - terminal_move_to_line(el, i); - terminal_move_to_char(el, 0); - terminal_clear_EOL(el, el->el_terminal.t_size.h); - } - } else { - terminal_move_to_line(el, el->el_refresh.r_oldcv); - /* go to last line */ - terminal__putc(el, '\r'); /* go to BOL */ - terminal__putc(el, '\n'); /* go to new line */ - } -} diff --git a/cmd-line-utils/libedit/refresh.h b/cmd-line-utils/libedit/refresh.h deleted file mode 100644 index f80be463545..00000000000 --- a/cmd-line-utils/libedit/refresh.h +++ /dev/null @@ -1,59 +0,0 @@ -/* $NetBSD: refresh.h,v 1.6 2009/12/30 22:37:40 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)refresh.h 8.1 (Berkeley) 6/4/93 - */ - -/* - * el.refresh.h: Screen refresh functions - */ -#ifndef _h_el_refresh -#define _h_el_refresh - -#include "histedit.h" - -typedef struct { - coord_t r_cursor; /* Refresh cursor position */ - int r_oldcv; /* Vertical locations */ - int r_newcv; -} el_refresh_t; - -protected void re_putc(EditLine *, Int, int); -protected void re_clear_lines(EditLine *); -protected void re_clear_display(EditLine *); -protected void re_refresh(EditLine *); -protected void re_refresh_cursor(EditLine *); -protected void re_fastaddc(EditLine *); -protected void re_goto_bottom(EditLine *); - -#endif /* _h_el_refresh */ diff --git a/cmd-line-utils/libedit/search.c b/cmd-line-utils/libedit/search.c deleted file mode 100644 index 2324cc94d76..00000000000 --- a/cmd-line-utils/libedit/search.c +++ /dev/null @@ -1,640 +0,0 @@ -/* $NetBSD: search.c,v 1.30 2011/10/04 15:27:04 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)search.c 8.1 (Berkeley) 6/4/93"; -#else -#endif -#endif /* not lint && not SCCSID */ - -/* - * search.c: History and character search functions - */ -#include -#if defined(REGEX) -#include -#elif defined(REGEXP) -#include -#endif -#include "el.h" - -/* - * Adjust cursor in vi mode to include the character under it - */ -#define EL_CURSOR(el) \ - ((el)->el_line.cursor + (((el)->el_map.type == MAP_VI) && \ - ((el)->el_map.current == (el)->el_map.alt))) - -/* search_init(): - * Initialize the search stuff - */ -protected int -search_init(EditLine *el) -{ - - el->el_search.patbuf = el_malloc(EL_BUFSIZ * - sizeof(*el->el_search.patbuf)); - if (el->el_search.patbuf == NULL) - return -1; - el->el_search.patlen = 0; - el->el_search.patdir = -1; - el->el_search.chacha = '\0'; - el->el_search.chadir = CHAR_FWD; - el->el_search.chatflg = 0; - return 0; -} - - -/* search_end(): - * Initialize the search stuff - */ -protected void -search_end(EditLine *el) -{ - - el_free(el->el_search.patbuf); - el->el_search.patbuf = NULL; -} - - -#ifdef REGEXP -/* regerror(): - * Handle regular expression errors - */ -public void -/*ARGSUSED*/ -regerror(const char *msg) -{ -} -#endif - - -/* el_match(): - * Return if string matches pattern - */ -protected int -el_match(const Char *str, const Char *pat) -{ -#ifdef WIDECHAR - static ct_buffer_t conv; -#endif -#if defined (REGEX) - regex_t re; - int rv; -#elif defined (REGEXP) - regexp *rp; - int rv; -#else - extern char *re_comp(const char *); - extern int re_exec(const char *); -#endif - - if (Strstr(str, pat) != 0) - return 1; - -#if defined(REGEX) - if (regcomp(&re, ct_encode_string(pat, &conv), 0) == 0) { - rv = regexec(&re, ct_encode_string(str, &conv), (size_t)0, NULL, - 0) == 0; - regfree(&re); - } else { - rv = 0; - } - return rv; -#elif defined(REGEXP) - if ((re = regcomp(ct_encode_string(pat, &conv))) != NULL) { - rv = regexec(re, ct_encode_string(str, &conv)); - el_free(re); - } else { - rv = 0; - } - return rv; -#else - if (re_comp(ct_encode_string(pat, &conv)) != NULL) - return 0; - else - return re_exec(ct_encode_string(str, &conv) == 1); -#endif -} - - -/* c_hmatch(): - * return True if the pattern matches the prefix - */ -protected int -c_hmatch(EditLine *el, const Char *str) -{ -#ifdef SDEBUG - (void) fprintf(el->el_errfile, "match `%s' with `%s'\n", - el->el_search.patbuf, str); -#endif /* SDEBUG */ - - return el_match(str, el->el_search.patbuf); -} - - -/* c_setpat(): - * Set the history seatch pattern - */ -protected void -c_setpat(EditLine *el) -{ - if (el->el_state.lastcmd != ED_SEARCH_PREV_HISTORY && - el->el_state.lastcmd != ED_SEARCH_NEXT_HISTORY) { - el->el_search.patlen = - (size_t)(EL_CURSOR(el) - el->el_line.buffer); - if (el->el_search.patlen >= EL_BUFSIZ) - el->el_search.patlen = EL_BUFSIZ - 1; - if (el->el_search.patlen != 0) { - (void) Strncpy(el->el_search.patbuf, el->el_line.buffer, - el->el_search.patlen); - el->el_search.patbuf[el->el_search.patlen] = '\0'; - } else - el->el_search.patlen = Strlen(el->el_search.patbuf); - } -#ifdef SDEBUG - (void) fprintf(el->el_errfile, "\neventno = %d\n", - el->el_history.eventno); - (void) fprintf(el->el_errfile, "patlen = %d\n", el->el_search.patlen); - (void) fprintf(el->el_errfile, "patbuf = \"%s\"\n", - el->el_search.patbuf); - (void) fprintf(el->el_errfile, "cursor %d lastchar %d\n", - EL_CURSOR(el) - el->el_line.buffer, - el->el_line.lastchar - el->el_line.buffer); -#endif -} - - -/* ce_inc_search(): - * Emacs incremental search - */ -protected el_action_t -ce_inc_search(EditLine *el, int dir) -{ - static const Char STRfwd[] = {'f', 'w', 'd', '\0'}, - STRbck[] = {'b', 'c', 'k', '\0'}; - static Char pchar = ':';/* ':' = normal, '?' = failed */ - static Char endcmd[2] = {'\0', '\0'}; - Char ch, *ocursor = el->el_line.cursor, oldpchar = pchar; - const Char *cp; - - el_action_t ret = CC_NORM; - - int ohisteventno = el->el_history.eventno; - size_t oldpatlen = el->el_search.patlen; - int newdir = dir; - int done, redo; - - if (el->el_line.lastchar + sizeof(STRfwd) / - sizeof(*el->el_line.lastchar) + 2 + - el->el_search.patlen >= el->el_line.limit) - return CC_ERROR; - - for (;;) { - - if (el->el_search.patlen == 0) { /* first round */ - pchar = ':'; -#ifdef ANCHOR -#define LEN 2 - el->el_search.patbuf[el->el_search.patlen++] = '.'; - el->el_search.patbuf[el->el_search.patlen++] = '*'; -#else -#define LEN 0 -#endif - } - done = redo = 0; - *el->el_line.lastchar++ = '\n'; - for (cp = (newdir == ED_SEARCH_PREV_HISTORY) ? STRbck : STRfwd; - *cp; *el->el_line.lastchar++ = *cp++) - continue; - *el->el_line.lastchar++ = pchar; - for (cp = &el->el_search.patbuf[LEN]; - cp < &el->el_search.patbuf[el->el_search.patlen]; - *el->el_line.lastchar++ = *cp++) - continue; - *el->el_line.lastchar = '\0'; - re_refresh(el); - - if (FUN(el,getc)(el, &ch) != 1) - return ed_end_of_file(el, 0); - - switch (el->el_map.current[(unsigned char) ch]) { - case ED_INSERT: - case ED_DIGIT: - if (el->el_search.patlen >= EL_BUFSIZ - LEN) - terminal_beep(el); - else { - el->el_search.patbuf[el->el_search.patlen++] = - ch; - *el->el_line.lastchar++ = ch; - *el->el_line.lastchar = '\0'; - re_refresh(el); - } - break; - - case EM_INC_SEARCH_NEXT: - newdir = ED_SEARCH_NEXT_HISTORY; - redo++; - break; - - case EM_INC_SEARCH_PREV: - newdir = ED_SEARCH_PREV_HISTORY; - redo++; - break; - - case EM_DELETE_PREV_CHAR: - case ED_DELETE_PREV_CHAR: - if (el->el_search.patlen > LEN) - done++; - else - terminal_beep(el); - break; - - default: - switch (ch) { - case 0007: /* ^G: Abort */ - ret = CC_ERROR; - done++; - break; - - case 0027: /* ^W: Append word */ - /* No can do if globbing characters in pattern */ - for (cp = &el->el_search.patbuf[LEN];; cp++) - if (cp >= &el->el_search.patbuf[ - el->el_search.patlen]) { - el->el_line.cursor += - el->el_search.patlen - LEN - 1; - cp = c__next_word(el->el_line.cursor, - el->el_line.lastchar, 1, - ce__isword); - while (el->el_line.cursor < cp && - *el->el_line.cursor != '\n') { - if (el->el_search.patlen >= - EL_BUFSIZ - LEN) { - terminal_beep(el); - break; - } - el->el_search.patbuf[el->el_search.patlen++] = - *el->el_line.cursor; - *el->el_line.lastchar++ = - *el->el_line.cursor++; - } - el->el_line.cursor = ocursor; - *el->el_line.lastchar = '\0'; - re_refresh(el); - break; - } else if (isglob(*cp)) { - terminal_beep(el); - break; - } - break; - - default: /* Terminate and execute cmd */ - endcmd[0] = ch; - FUN(el,push)(el, endcmd); - /* FALLTHROUGH */ - - case 0033: /* ESC: Terminate */ - ret = CC_REFRESH; - done++; - break; - } - break; - } - - while (el->el_line.lastchar > el->el_line.buffer && - *el->el_line.lastchar != '\n') - *el->el_line.lastchar-- = '\0'; - *el->el_line.lastchar = '\0'; - - if (!done) { - - /* Can't search if unmatched '[' */ - for (cp = &el->el_search.patbuf[el->el_search.patlen-1], - ch = ']'; - cp >= &el->el_search.patbuf[LEN]; - cp--) - if (*cp == '[' || *cp == ']') { - ch = *cp; - break; - } - if (el->el_search.patlen > LEN && ch != '[') { - if (redo && newdir == dir) { - if (pchar == '?') { /* wrap around */ - el->el_history.eventno = - newdir == ED_SEARCH_PREV_HISTORY ? 0 : 0x7fffffff; - if (hist_get(el) == CC_ERROR) - /* el->el_history.event - * no was fixed by - * first call */ - (void) hist_get(el); - el->el_line.cursor = newdir == - ED_SEARCH_PREV_HISTORY ? - el->el_line.lastchar : - el->el_line.buffer; - } else - el->el_line.cursor += - newdir == - ED_SEARCH_PREV_HISTORY ? - -1 : 1; - } -#ifdef ANCHOR - el->el_search.patbuf[el->el_search.patlen++] = - '.'; - el->el_search.patbuf[el->el_search.patlen++] = - '*'; -#endif - el->el_search.patbuf[el->el_search.patlen] = - '\0'; - if (el->el_line.cursor < el->el_line.buffer || - el->el_line.cursor > el->el_line.lastchar || - (ret = ce_search_line(el, newdir)) - == CC_ERROR) { - /* avoid c_setpat */ - el->el_state.lastcmd = - (el_action_t) newdir; - ret = (el_action_t) - (newdir == ED_SEARCH_PREV_HISTORY ? - ed_search_prev_history(el, 0) : - ed_search_next_history(el, 0)); - if (ret != CC_ERROR) { - el->el_line.cursor = newdir == - ED_SEARCH_PREV_HISTORY ? - el->el_line.lastchar : - el->el_line.buffer; - (void) ce_search_line(el, - newdir); - } - } - el->el_search.patlen -= LEN; - el->el_search.patbuf[el->el_search.patlen] = - '\0'; - if (ret == CC_ERROR) { - terminal_beep(el); - if (el->el_history.eventno != - ohisteventno) { - el->el_history.eventno = - ohisteventno; - if (hist_get(el) == CC_ERROR) - return CC_ERROR; - } - el->el_line.cursor = ocursor; - pchar = '?'; - } else { - pchar = ':'; - } - } - ret = ce_inc_search(el, newdir); - - if (ret == CC_ERROR && pchar == '?' && oldpchar == ':') - /* - * break abort of failed search at last - * non-failed - */ - ret = CC_NORM; - - } - if (ret == CC_NORM || (ret == CC_ERROR && oldpatlen == 0)) { - /* restore on normal return or error exit */ - pchar = oldpchar; - el->el_search.patlen = oldpatlen; - if (el->el_history.eventno != ohisteventno) { - el->el_history.eventno = ohisteventno; - if (hist_get(el) == CC_ERROR) - return CC_ERROR; - } - el->el_line.cursor = ocursor; - if (ret == CC_ERROR) - re_refresh(el); - } - if (done || ret != CC_NORM) - return ret; - } -} - - -/* cv_search(): - * Vi search. - */ -protected el_action_t -cv_search(EditLine *el, int dir) -{ - Char ch; - Char tmpbuf[EL_BUFSIZ]; - ssize_t tmplen; - -#ifdef ANCHOR - tmpbuf[0] = '.'; - tmpbuf[1] = '*'; -#endif - tmplen = LEN; - - el->el_search.patdir = dir; - - tmplen = c_gets(el, &tmpbuf[LEN], - dir == ED_SEARCH_PREV_HISTORY ? STR("\n/") : STR("\n?") ); - if (tmplen == -1) - return CC_REFRESH; - - tmplen += LEN; - ch = tmpbuf[tmplen]; - tmpbuf[tmplen] = '\0'; - - if (tmplen == LEN) { - /* - * Use the old pattern, but wild-card it. - */ - if (el->el_search.patlen == 0) { - re_refresh(el); - return CC_ERROR; - } -#ifdef ANCHOR - if (el->el_search.patbuf[0] != '.' && - el->el_search.patbuf[0] != '*') { - (void) Strncpy(tmpbuf, el->el_search.patbuf, - sizeof(tmpbuf) / sizeof(*tmpbuf) - 1); - el->el_search.patbuf[0] = '.'; - el->el_search.patbuf[1] = '*'; - (void) Strncpy(&el->el_search.patbuf[2], tmpbuf, - EL_BUFSIZ - 3); - el->el_search.patlen++; - el->el_search.patbuf[el->el_search.patlen++] = '.'; - el->el_search.patbuf[el->el_search.patlen++] = '*'; - el->el_search.patbuf[el->el_search.patlen] = '\0'; - } -#endif - } else { -#ifdef ANCHOR - tmpbuf[tmplen++] = '.'; - tmpbuf[tmplen++] = '*'; -#endif - tmpbuf[tmplen] = '\0'; - (void) Strncpy(el->el_search.patbuf, tmpbuf, EL_BUFSIZ - 1); - el->el_search.patlen = (size_t)tmplen; - } - el->el_state.lastcmd = (el_action_t) dir; /* avoid c_setpat */ - el->el_line.cursor = el->el_line.lastchar = el->el_line.buffer; - if ((dir == ED_SEARCH_PREV_HISTORY ? ed_search_prev_history(el, 0) : - ed_search_next_history(el, 0)) == CC_ERROR) { - re_refresh(el); - return CC_ERROR; - } - if (ch == 0033) { - re_refresh(el); - return ed_newline(el, 0); - } - return CC_REFRESH; -} - - -/* ce_search_line(): - * Look for a pattern inside a line - */ -protected el_action_t -ce_search_line(EditLine *el, int dir) -{ - Char *cp = el->el_line.cursor; - Char *pattern = el->el_search.patbuf; - Char oc, *ocp; -#ifdef ANCHOR - ocp = &pattern[1]; - oc = *ocp; - *ocp = '^'; -#else - ocp = pattern; - oc = *ocp; -#endif - - if (dir == ED_SEARCH_PREV_HISTORY) { - for (; cp >= el->el_line.buffer; cp--) { - if (el_match(cp, ocp)) { - *ocp = oc; - el->el_line.cursor = cp; - return CC_NORM; - } - } - *ocp = oc; - return CC_ERROR; - } else { - for (; *cp != '\0' && cp < el->el_line.limit; cp++) { - if (el_match(cp, ocp)) { - *ocp = oc; - el->el_line.cursor = cp; - return CC_NORM; - } - } - *ocp = oc; - return CC_ERROR; - } -} - - -/* cv_repeat_srch(): - * Vi repeat search - */ -protected el_action_t -cv_repeat_srch(EditLine *el, Int c) -{ - -#ifdef SDEBUG - (void) fprintf(el->el_errfile, "dir %d patlen %d patbuf %s\n", - c, el->el_search.patlen, ct_encode_string(el->el_search.patbuf)); -#endif - - el->el_state.lastcmd = (el_action_t) c; /* Hack to stop c_setpat */ - el->el_line.lastchar = el->el_line.buffer; - - switch (c) { - case ED_SEARCH_NEXT_HISTORY: - return ed_search_next_history(el, 0); - case ED_SEARCH_PREV_HISTORY: - return ed_search_prev_history(el, 0); - default: - return CC_ERROR; - } -} - - -/* cv_csearch(): - * Vi character search - */ -protected el_action_t -cv_csearch(EditLine *el, int direction, Int ch, int count, int tflag) -{ - Char *cp; - - if (ch == 0) - return CC_ERROR; - - if (ch == (Int)-1) { - Char c; - if (FUN(el,getc)(el, &c) != 1) - return ed_end_of_file(el, 0); - ch = c; - } - - /* Save for ';' and ',' commands */ - el->el_search.chacha = ch; - el->el_search.chadir = direction; - el->el_search.chatflg = (char)tflag; - - cp = el->el_line.cursor; - while (count--) { - if ((Int)*cp == ch) - cp += direction; - for (;;cp += direction) { - if (cp >= el->el_line.lastchar) - return CC_ERROR; - if (cp < el->el_line.buffer) - return CC_ERROR; - if ((Int)*cp == ch) - break; - } - } - - if (tflag) - cp -= direction; - - el->el_line.cursor = cp; - - if (el->el_chared.c_vcmd.action != NOP) { - if (direction > 0) - el->el_line.cursor++; - cv_delfini(el); - return CC_REFRESH; - } - return CC_CURSOR; -} diff --git a/cmd-line-utils/libedit/search.h b/cmd-line-utils/libedit/search.h deleted file mode 100644 index d9f27e56185..00000000000 --- a/cmd-line-utils/libedit/search.h +++ /dev/null @@ -1,66 +0,0 @@ -/* $NetBSD: search.h,v 1.9 2009/12/30 22:37:40 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)search.h 8.1 (Berkeley) 6/4/93 - */ - -/* - * el.search.h: Line and history searching utilities - */ -#ifndef _h_el_search -#define _h_el_search - -#include "histedit.h" - -typedef struct el_search_t { - Char *patbuf; /* The pattern buffer */ - size_t patlen; /* Length of the pattern buffer */ - int patdir; /* Direction of the last search */ - int chadir; /* Character search direction */ - Char chacha; /* Character we are looking for */ - char chatflg; /* 0 if f, 1 if t */ -} el_search_t; - - -protected int el_match(const Char *, const Char *); -protected int search_init(EditLine *); -protected void search_end(EditLine *); -protected int c_hmatch(EditLine *, const Char *); -protected void c_setpat(EditLine *); -protected el_action_t ce_inc_search(EditLine *, int); -protected el_action_t cv_search(EditLine *, int); -protected el_action_t ce_search_line(EditLine *, int); -protected el_action_t cv_repeat_srch(EditLine *, Int); -protected el_action_t cv_csearch(EditLine *, int, Int, int, int); - -#endif /* _h_el_search */ diff --git a/cmd-line-utils/libedit/sig.c b/cmd-line-utils/libedit/sig.c deleted file mode 100644 index 986ad5792e2..00000000000 --- a/cmd-line-utils/libedit/sig.c +++ /dev/null @@ -1,199 +0,0 @@ -/* $NetBSD: sig.c,v 1.17 2011/07/28 20:50:55 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)sig.c 8.1 (Berkeley) 6/4/93"; -#else -#endif -#endif /* not lint && not SCCSID */ - -/* - * sig.c: Signal handling stuff. - * our policy is to trap all signals, set a good state - * and pass the ball to our caller. - */ -#include "el.h" -#include - -private EditLine *sel = NULL; - -private const int sighdl[] = { -#define _DO(a) (a), - ALLSIGS -#undef _DO - - 1 -}; - -private void sig_handler(int); - -/* sig_handler(): - * This is the handler called for all signals - * XXX: we cannot pass any data so we just store the old editline - * state in a private variable - */ -private void -sig_handler(int signo) -{ - int i; - sigset_t nset, oset; - - (void) sigemptyset(&nset); - (void) sigaddset(&nset, signo); - (void) sigprocmask(SIG_BLOCK, &nset, &oset); - - sel->el_signal->sig_no = signo; - - switch (signo) { - case SIGCONT: - tty_rawmode(sel); - if (ed_redisplay(sel, 0) == CC_REFRESH) - re_refresh(sel); - terminal__flush(sel); - break; - - case SIGWINCH: - el_resize(sel); - break; - - default: - tty_cookedmode(sel); - break; - } - - for (i = 0; sighdl[i] != -1; i++) - if (signo == sighdl[i]) - break; - - (void) sigaction(signo, &sel->el_signal->sig_action[i], NULL); - sel->el_signal->sig_action[i].sa_handler = SIG_ERR; - sel->el_signal->sig_action[i].sa_flags = 0; - sigemptyset(&sel->el_signal->sig_action[i].sa_mask); - (void) sigprocmask(SIG_SETMASK, &oset, NULL); - (void) kill(0, signo); -} - - -/* sig_init(): - * Initialize all signal stuff - */ -protected int -sig_init(EditLine *el) -{ - size_t i; - sigset_t *nset, oset; - - el->el_signal = el_malloc(sizeof(*el->el_signal)); - if (el->el_signal == NULL) - return -1; - - nset = &el->el_signal->sig_set; - (void) sigemptyset(nset); -#define _DO(a) (void) sigaddset(nset, a); - ALLSIGS -#undef _DO - (void) sigprocmask(SIG_BLOCK, nset, &oset); - - for (i = 0; sighdl[i] != -1; i++) { - el->el_signal->sig_action[i].sa_handler = SIG_ERR; - el->el_signal->sig_action[i].sa_flags = 0; - sigemptyset(&el->el_signal->sig_action[i].sa_mask); - } - - (void) sigprocmask(SIG_SETMASK, &oset, NULL); - - return 0; -} - - -/* sig_end(): - * Clear all signal stuff - */ -protected void -sig_end(EditLine *el) -{ - - el_free(el->el_signal); - el->el_signal = NULL; -} - - -/* sig_set(): - * set all the signal handlers - */ -protected void -sig_set(EditLine *el) -{ - size_t i; - sigset_t oset; - struct sigaction osa, nsa; - - nsa.sa_handler = sig_handler; - nsa.sa_flags = 0; - sigemptyset(&nsa.sa_mask); - - (void) sigprocmask(SIG_BLOCK, &el->el_signal->sig_set, &oset); - - for (i = 0; sighdl[i] != -1; i++) { - /* This could happen if we get interrupted */ - if (sigaction(sighdl[i], &nsa, &osa) != -1 && - osa.sa_handler != sig_handler) - el->el_signal->sig_action[i] = osa; - } - sel = el; - (void) sigprocmask(SIG_SETMASK, &oset, NULL); -} - - -/* sig_clr(): - * clear all the signal handlers - */ -protected void -sig_clr(EditLine *el) -{ - size_t i; - sigset_t oset; - - (void) sigprocmask(SIG_BLOCK, &el->el_signal->sig_set, &oset); - - for (i = 0; sighdl[i] != -1; i++) - if (el->el_signal->sig_action[i].sa_handler != SIG_ERR) - (void)sigaction(sighdl[i], - &el->el_signal->sig_action[i], NULL); - - sel = NULL; /* we are going to die if the handler is - * called */ - (void)sigprocmask(SIG_SETMASK, &oset, NULL); -} diff --git a/cmd-line-utils/libedit/sig.h b/cmd-line-utils/libedit/sig.h deleted file mode 100644 index c957cfdf5a7..00000000000 --- a/cmd-line-utils/libedit/sig.h +++ /dev/null @@ -1,72 +0,0 @@ -/* $NetBSD: sig.h,v 1.8 2009/02/19 15:20:22 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)sig.h 8.1 (Berkeley) 6/4/93 - */ - -/* - * el.sig.h: Signal handling functions - */ -#ifndef _h_el_sig -#define _h_el_sig - -#include - -#include "histedit.h" - -/* - * Define here all the signals we are going to handle - * The _DO macro is used to iterate in the source code - */ -#define ALLSIGS \ - _DO(SIGINT) \ - _DO(SIGTSTP) \ - _DO(SIGQUIT) \ - _DO(SIGHUP) \ - _DO(SIGTERM) \ - _DO(SIGCONT) \ - _DO(SIGWINCH) -#define ALLSIGSNO 7 - -typedef struct { - struct sigaction sig_action[ALLSIGSNO]; - sigset_t sig_set; - volatile sig_atomic_t sig_no; -} *el_signal_t; - -protected void sig_end(EditLine*); -protected int sig_init(EditLine*); -protected void sig_set(EditLine*); -protected void sig_clr(EditLine*); - -#endif /* _h_el_sig */ diff --git a/cmd-line-utils/libedit/sys.h b/cmd-line-utils/libedit/sys.h deleted file mode 100644 index af55bcd7202..00000000000 --- a/cmd-line-utils/libedit/sys.h +++ /dev/null @@ -1,187 +0,0 @@ -/* $NetBSD: sys.h,v 1.17 2011/09/28 14:08:04 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)sys.h 8.1 (Berkeley) 6/4/93 - */ - -/* - * sys.h: Put all the stupid compiler and system dependencies here... - */ -#ifndef _h_sys -#define _h_sys - -#ifdef __linux__ -/* Apparently we need _GNU_SOURCE defined to get access to wcsdup on Linux */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#endif - -#ifndef __USE_XOPEN -#define __USE_XOPEN -#endif - -#ifdef HAVE_SYS_CDEFS_H -#include -#endif - -#if !defined(__attribute__) && (defined(__cplusplus) || !defined(__GNUC__) || __GNUC__ == 2 && __GNUC_MINOR__ < 8) -# define __attribute__(A) -#endif - -#ifndef __BEGIN_DECLS -# ifdef __cplusplus -# define __BEGIN_DECLS extern "C" { -# define __END_DECLS } -# else -# define __BEGIN_DECLS -# define __END_DECLS -# endif -#endif - -#ifndef public -# define public /* Externally visible functions/variables */ -#endif - -#ifndef private -# define private static /* Always hidden internals */ -#endif - -#ifndef protected -# define protected /* Redefined from elsewhere to "static" */ - /* When we want to hide everything */ -#endif - -#ifndef __arraycount -# define __arraycount(a) (sizeof(a) / sizeof(*(a))) -#endif - -#include - -#ifndef HAVE_STRLCAT -#define strlcat libedit_strlcat -size_t strlcat(char *dst, const char *src, size_t size); -#endif - -#ifndef HAVE_STRLCPY -#define strlcpy libedit_strlcpy -size_t strlcpy(char *dst, const char *src, size_t size); -#endif - -#ifndef HAVE_FGETLN -#define fgetln libedit_fgetln -char *fgetln(FILE *fp, size_t *len); -#endif - -#include -#include - -#ifndef HAVE_WCSDUP -wchar_t *wcsdup(const wchar_t *); -#endif - -#ifndef _DIAGASSERT -#define _DIAGASSERT(x) -#endif - -#ifndef __RCSID -#define __RCSID(x) -#endif - -#ifndef HAVE_U_INT32_T -typedef unsigned int u_int32_t; -#endif - -#ifndef SIZE_T_MAX -#define SIZE_T_MAX ((size_t)-1) -#endif - -#define REGEX /* Use POSIX.2 regular expression functions */ -#undef REGEXP /* Use UNIX V8 regular expression functions */ - -#if defined(__sun) -extern int tgetent(char *, const char *); -extern int tgetflag(char *); -extern int tgetnum(char *); -extern int tputs(const char *, int, int (*)(int)); -extern char* tgoto(const char*, int, int); -extern char* tgetstr(char*, char**); -#endif - -/* XXXMYSQL: Bug#10218 Command line recall rolls into segfault */ -#if !HAVE_DECL_TGOTO -/* - 'tgoto' is not declared in the system header files, this causes - problems on 64-bit systems. The function returns a 64 bit pointer - but caller see it as "int" and it's thus truncated to 32-bit -*/ -extern char* tgoto(const char*, int, int); -#endif - -#ifdef notdef -# undef REGEX -# undef REGEXP -# include -# ifdef __GNUC__ -/* - * Broken hdrs. - */ -extern int tgetent(const char *bp, char *name); -extern int tgetflag(const char *id); -extern int tgetnum(const char *id); -extern char *tgetstr(const char *id, char **area); -extern char *tgoto(const char *cap, int col, int row); -extern int tputs(const char *str, int affcnt, int (*putc)(int)); -extern char *getenv(const char *); -extern int fprintf(FILE *, const char *, ...); -extern int sigsetmask(int); -extern int sigblock(int); -extern int fputc(int, FILE *); -extern int fgetc(FILE *); -extern int fflush(FILE *); -extern int tolower(int); -extern int toupper(int); -extern int errno, sys_nerr; -extern char *sys_errlist[]; -extern void perror(const char *); -# include -# define strerror(e) sys_errlist[e] -# endif -# ifdef SABER -extern void * memcpy(void *, const void *, size_t); -extern void * memset(void *, int, size_t); -# endif -extern char *fgetline(FILE *, int *); -#endif - -#endif /* _h_sys */ diff --git a/cmd-line-utils/libedit/terminal.c b/cmd-line-utils/libedit/terminal.c deleted file mode 100644 index fb5600a4140..00000000000 --- a/cmd-line-utils/libedit/terminal.c +++ /dev/null @@ -1,1677 +0,0 @@ -/* $NetBSD: terminal.c,v 1.10 2011/10/04 15:27:04 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)term.c 8.2 (Berkeley) 4/30/95"; -#else -#endif -#endif /* not lint && not SCCSID */ - -/* - * terminal.c: Editor/termcap-curses interface - * We have to declare a static variable here, since the - * termcap putchar routine does not take an argument! - */ -#include -#include -#include -#include -#include -#include -#if 0 /* TODO: do we need this */ -#ifdef HAVE_TERMCAP_H -#include -#endif -#endif -#ifdef HAVE_CURSES_H -#include -#elif HAVE_NCURSES_H -#include -#endif - -/* Solaris's term.h does horrid things. */ -#if defined(HAVE_TERM_H) && !defined(__sun) -#include -#endif - -#include -#include - -#ifdef _REENTRANT -#include -#endif - -#include "el.h" - -/* - * IMPORTANT NOTE: these routines are allowed to look at the current screen - * and the current position assuming that it is correct. If this is not - * true, then the update will be WRONG! This is (should be) a valid - * assumption... - */ - -#define TC_BUFSIZE ((size_t)2048) - -#define GoodStr(a) (el->el_terminal.t_str[a] != NULL && \ - el->el_terminal.t_str[a][0] != '\0') -#define Str(a) el->el_terminal.t_str[a] -#define Val(a) el->el_terminal.t_val[a] - -private const struct termcapstr { - const char *name; - const char *long_name; -} tstr[] = { -#define T_al 0 - { "al", "add new blank line" }, -#define T_bl 1 - { "bl", "audible bell" }, -#define T_cd 2 - { "cd", "clear to bottom" }, -#define T_ce 3 - { "ce", "clear to end of line" }, -#define T_ch 4 - { "ch", "cursor to horiz pos" }, -#define T_cl 5 - { "cl", "clear screen" }, -#define T_dc 6 - { "dc", "delete a character" }, -#define T_dl 7 - { "dl", "delete a line" }, -#define T_dm 8 - { "dm", "start delete mode" }, -#define T_ed 9 - { "ed", "end delete mode" }, -#define T_ei 10 - { "ei", "end insert mode" }, -#define T_fs 11 - { "fs", "cursor from status line" }, -#define T_ho 12 - { "ho", "home cursor" }, -#define T_ic 13 - { "ic", "insert character" }, -#define T_im 14 - { "im", "start insert mode" }, -#define T_ip 15 - { "ip", "insert padding" }, -#define T_kd 16 - { "kd", "sends cursor down" }, -#define T_kl 17 - { "kl", "sends cursor left" }, -#define T_kr 18 - { "kr", "sends cursor right" }, -#define T_ku 19 - { "ku", "sends cursor up" }, -#define T_md 20 - { "md", "begin bold" }, -#define T_me 21 - { "me", "end attributes" }, -#define T_nd 22 - { "nd", "non destructive space" }, -#define T_se 23 - { "se", "end standout" }, -#define T_so 24 - { "so", "begin standout" }, -#define T_ts 25 - { "ts", "cursor to status line" }, -#define T_up 26 - { "up", "cursor up one" }, -#define T_us 27 - { "us", "begin underline" }, -#define T_ue 28 - { "ue", "end underline" }, -#define T_vb 29 - { "vb", "visible bell" }, -#define T_DC 30 - { "DC", "delete multiple chars" }, -#define T_DO 31 - { "DO", "cursor down multiple" }, -#define T_IC 32 - { "IC", "insert multiple chars" }, -#define T_LE 33 - { "LE", "cursor left multiple" }, -#define T_RI 34 - { "RI", "cursor right multiple" }, -#define T_UP 35 - { "UP", "cursor up multiple" }, -#define T_kh 36 - { "kh", "send cursor home" }, -#define T_at7 37 - { "@7", "send cursor end" }, -#define T_str 38 - { NULL, NULL } -}; - -private const struct termcapval { - const char *name; - const char *long_name; -} tval[] = { -#define T_am 0 - { "am", "has automatic margins" }, -#define T_pt 1 - { "pt", "has physical tabs" }, -#define T_li 2 - { "li", "Number of lines" }, -#define T_co 3 - { "co", "Number of columns" }, -#define T_km 4 - { "km", "Has meta key" }, -#define T_xt 5 - { "xt", "Tab chars destructive" }, -#define T_xn 6 - { "xn", "newline ignored at right margin" }, -#define T_MT 7 - { "MT", "Has meta key" }, /* XXX? */ -#define T_val 8 - { NULL, NULL, } -}; -/* do two or more of the attributes use me */ - -private void terminal_setflags(EditLine *); -private int terminal_rebuffer_display(EditLine *); -private void terminal_free_display(EditLine *); -private int terminal_alloc_display(EditLine *); -private void terminal_alloc(EditLine *, const struct termcapstr *, - const char *); -private void terminal_init_arrow(EditLine *); -private void terminal_reset_arrow(EditLine *); -private int terminal_putc(int); -private void terminal_tputs(EditLine *, const char *, int); - -#ifdef _REENTRANT -private pthread_mutex_t terminal_mutex = PTHREAD_MUTEX_INITIALIZER; -#endif -private FILE *terminal_outfile = NULL; - - -/* terminal_setflags(): - * Set the terminal capability flags - */ -private void -terminal_setflags(EditLine *el) -{ - EL_FLAGS = 0; - if (el->el_tty.t_tabs) - EL_FLAGS |= (Val(T_pt) && !Val(T_xt)) ? TERM_CAN_TAB : 0; - - EL_FLAGS |= (Val(T_km) || Val(T_MT)) ? TERM_HAS_META : 0; - EL_FLAGS |= GoodStr(T_ce) ? TERM_CAN_CEOL : 0; - EL_FLAGS |= (GoodStr(T_dc) || GoodStr(T_DC)) ? TERM_CAN_DELETE : 0; - EL_FLAGS |= (GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC)) ? - TERM_CAN_INSERT : 0; - EL_FLAGS |= (GoodStr(T_up) || GoodStr(T_UP)) ? TERM_CAN_UP : 0; - EL_FLAGS |= Val(T_am) ? TERM_HAS_AUTO_MARGINS : 0; - EL_FLAGS |= Val(T_xn) ? TERM_HAS_MAGIC_MARGINS : 0; - - if (GoodStr(T_me) && GoodStr(T_ue)) - EL_FLAGS |= (strcmp(Str(T_me), Str(T_ue)) == 0) ? - TERM_CAN_ME : 0; - else - EL_FLAGS &= ~TERM_CAN_ME; - if (GoodStr(T_me) && GoodStr(T_se)) - EL_FLAGS |= (strcmp(Str(T_me), Str(T_se)) == 0) ? - TERM_CAN_ME : 0; - - -#ifdef DEBUG_SCREEN - if (!EL_CAN_UP) { - (void) fprintf(el->el_errfile, - "WARNING: Your terminal cannot move up.\n"); - (void) fprintf(el->el_errfile, - "Editing may be odd for long lines.\n"); - } - if (!EL_CAN_CEOL) - (void) fprintf(el->el_errfile, "no clear EOL capability.\n"); - if (!EL_CAN_DELETE) - (void) fprintf(el->el_errfile, "no delete char capability.\n"); - if (!EL_CAN_INSERT) - (void) fprintf(el->el_errfile, "no insert char capability.\n"); -#endif /* DEBUG_SCREEN */ -} - -/* terminal_init(): - * Initialize the terminal stuff - */ -protected int -terminal_init(EditLine *el) -{ - - el->el_terminal.t_buf = el_malloc(TC_BUFSIZE * - sizeof(*el->el_terminal.t_buf)); - if (el->el_terminal.t_buf == NULL) - return -1; - el->el_terminal.t_cap = el_malloc(TC_BUFSIZE * - sizeof(*el->el_terminal.t_cap)); - if (el->el_terminal.t_cap == NULL) - return -1; - el->el_terminal.t_fkey = el_malloc(A_K_NKEYS * - sizeof(*el->el_terminal.t_fkey)); - if (el->el_terminal.t_fkey == NULL) - return -1; - el->el_terminal.t_loc = 0; - el->el_terminal.t_str = el_malloc(T_str * - sizeof(*el->el_terminal.t_str)); - if (el->el_terminal.t_str == NULL) - return -1; - (void) memset(el->el_terminal.t_str, 0, T_str * - sizeof(*el->el_terminal.t_str)); - el->el_terminal.t_val = el_malloc(T_val * - sizeof(*el->el_terminal.t_val)); - if (el->el_terminal.t_val == NULL) - return -1; - (void) memset(el->el_terminal.t_val, 0, T_val * - sizeof(*el->el_terminal.t_val)); - (void) terminal_set(el, NULL); - terminal_init_arrow(el); - return 0; -} - -/* terminal_end(): - * Clean up the terminal stuff - */ -protected void -terminal_end(EditLine *el) -{ - - el_free(el->el_terminal.t_buf); - el->el_terminal.t_buf = NULL; - el_free(el->el_terminal.t_cap); - el->el_terminal.t_cap = NULL; - el->el_terminal.t_loc = 0; - el_free(el->el_terminal.t_str); - el->el_terminal.t_str = NULL; - el_free(el->el_terminal.t_val); - el->el_terminal.t_val = NULL; - el_free(el->el_terminal.t_fkey); - el->el_terminal.t_fkey = NULL; - terminal_free_display(el); -} - - -/* terminal_alloc(): - * Maintain a string pool for termcap strings - */ -private void -terminal_alloc(EditLine *el, const struct termcapstr *t, const char *cap) -{ - char termbuf[TC_BUFSIZE]; - size_t tlen, clen; - char **tlist = el->el_terminal.t_str; - char **tmp, **str = &tlist[t - tstr]; - - if (cap == NULL || *cap == '\0') { - *str = NULL; - return; - } else - clen = strlen(cap); - - tlen = *str == NULL ? 0 : strlen(*str); - - /* - * New string is shorter; no need to allocate space - */ - if (clen <= tlen) { - if (*str) - (void) strcpy(*str, cap); /* XXX strcpy is safe */ - return; - } - /* - * New string is longer; see if we have enough space to append - */ - if (el->el_terminal.t_loc + 3 < TC_BUFSIZE) { - /* XXX strcpy is safe */ - (void) strcpy(*str = &el->el_terminal.t_buf[ - el->el_terminal.t_loc], cap); - el->el_terminal.t_loc += clen + 1; /* one for \0 */ - return; - } - /* - * Compact our buffer; no need to check compaction, cause we know it - * fits... - */ - tlen = 0; - for (tmp = tlist; tmp < &tlist[T_str]; tmp++) - if (*tmp != NULL && *tmp != '\0' && *tmp != *str) { - char *ptr; - - for (ptr = *tmp; *ptr != '\0'; termbuf[tlen++] = *ptr++) - continue; - termbuf[tlen++] = '\0'; - } - memcpy(el->el_terminal.t_buf, termbuf, TC_BUFSIZE); - el->el_terminal.t_loc = tlen; - if (el->el_terminal.t_loc + 3 >= TC_BUFSIZE) { - (void) fprintf(el->el_errfile, - "Out of termcap string space.\n"); - return; - } - /* XXX strcpy is safe */ - (void) strcpy(*str = &el->el_terminal.t_buf[el->el_terminal.t_loc], - cap); - el->el_terminal.t_loc += (size_t)clen + 1; /* one for \0 */ - return; -} - - -/* terminal_rebuffer_display(): - * Rebuffer the display after the screen changed size - */ -private int -terminal_rebuffer_display(EditLine *el) -{ - coord_t *c = &el->el_terminal.t_size; - - terminal_free_display(el); - - c->h = Val(T_co); - c->v = Val(T_li); - - if (terminal_alloc_display(el) == -1) - return -1; - return 0; -} - - -/* terminal_alloc_display(): - * Allocate a new display. - */ -private int -terminal_alloc_display(EditLine *el) -{ - int i; - Char **b; - coord_t *c = &el->el_terminal.t_size; - - b = el_malloc(sizeof(*b) * (size_t)(c->v + 1)); - if (b == NULL) - return -1; - for (i = 0; i < c->v; i++) { - b[i] = el_malloc(sizeof(**b) * (size_t)(c->h + 1)); - if (b[i] == NULL) { - while (--i >= 0) - el_free(b[i]); - el_free(b); - return -1; - } - } - b[c->v] = NULL; - el->el_display = b; - - b = el_malloc(sizeof(*b) * (size_t)(c->v + 1)); - if (b == NULL) - return -1; - for (i = 0; i < c->v; i++) { - b[i] = el_malloc(sizeof(**b) * (size_t)(c->h + 1)); - if (b[i] == NULL) { - while (--i >= 0) - el_free(b[i]); - el_free(b); - return -1; - } - } - b[c->v] = NULL; - el->el_vdisplay = b; - return 0; -} - - -/* terminal_free_display(): - * Free the display buffers - */ -private void -terminal_free_display(EditLine *el) -{ - Char **b; - Char **bufp; - - b = el->el_display; - el->el_display = NULL; - if (b != NULL) { - for (bufp = b; *bufp != NULL; bufp++) - el_free(*bufp); - el_free(b); - } - b = el->el_vdisplay; - el->el_vdisplay = NULL; - if (b != NULL) { - for (bufp = b; *bufp != NULL; bufp++) - el_free(*bufp); - el_free(b); - } -} - - -/* terminal_move_to_line(): - * move to line (first line == 0) - * as efficiently as possible - */ -protected void -terminal_move_to_line(EditLine *el, int where) -{ - int del; - - if (where == el->el_cursor.v) - return; - - if (where > el->el_terminal.t_size.v) { -#ifdef DEBUG_SCREEN - (void) fprintf(el->el_errfile, - "terminal_move_to_line: where is ridiculous: %d\r\n", - where); -#endif /* DEBUG_SCREEN */ - return; - } - if ((del = where - el->el_cursor.v) > 0) { - while (del > 0) { - if (EL_HAS_AUTO_MARGINS && - el->el_display[el->el_cursor.v][0] != '\0') { - size_t h = (size_t) - (el->el_terminal.t_size.h - 1); -#ifdef WIDECHAR - for (; h > 0 && - el->el_display[el->el_cursor.v][h] == - MB_FILL_CHAR; - h--) - continue; -#endif - /* move without newline */ - terminal_move_to_char(el, (int)h); - terminal_overwrite(el, &el->el_display - [el->el_cursor.v][el->el_cursor.h], - (size_t)(el->el_terminal.t_size.h - - el->el_cursor.h)); - /* updates Cursor */ - del--; - } else { - if ((del > 1) && GoodStr(T_DO)) { - terminal_tputs(el, tgoto(Str(T_DO), del, - del), del); - del = 0; - } else { - for (; del > 0; del--) - terminal__putc(el, '\n'); - /* because the \n will become \r\n */ - el->el_cursor.h = 0; - } - } - } - } else { /* del < 0 */ - if (GoodStr(T_UP) && (-del > 1 || !GoodStr(T_up))) - terminal_tputs(el, tgoto(Str(T_UP), -del, -del), -del); - else { - if (GoodStr(T_up)) - for (; del < 0; del++) - terminal_tputs(el, Str(T_up), 1); - } - } - el->el_cursor.v = where;/* now where is here */ -} - - -/* terminal_move_to_char(): - * Move to the character position specified - */ -protected void -terminal_move_to_char(EditLine *el, int where) -{ - int del, i; - -mc_again: - if (where == el->el_cursor.h) - return; - - if (where > el->el_terminal.t_size.h) { -#ifdef DEBUG_SCREEN - (void) fprintf(el->el_errfile, - "terminal_move_to_char: where is riduculous: %d\r\n", - where); -#endif /* DEBUG_SCREEN */ - return; - } - if (!where) { /* if where is first column */ - terminal__putc(el, '\r'); /* do a CR */ - el->el_cursor.h = 0; - return; - } - del = where - el->el_cursor.h; - - if ((del < -4 || del > 4) && GoodStr(T_ch)) - /* go there directly */ - terminal_tputs(el, tgoto(Str(T_ch), where, where), where); - else { - if (del > 0) { /* moving forward */ - if ((del > 4) && GoodStr(T_RI)) - terminal_tputs(el, tgoto(Str(T_RI), del, del), - del); - else { - /* if I can do tabs, use them */ - if (EL_CAN_TAB) { - if ((el->el_cursor.h & 0370) != - (where & ~0x7) -#ifdef WIDECHAR - && (el->el_display[ - el->el_cursor.v][where & 0370] != - MB_FILL_CHAR) -#endif - ) { - /* if not within tab stop */ - for (i = - (el->el_cursor.h & 0370); - i < (where & ~0x7); - i += 8) - terminal__putc(el, - '\t'); - /* then tab over */ - el->el_cursor.h = where & ~0x7; - } - } - /* - * it's usually cheaper to just write the - * chars, so we do. - */ - /* - * NOTE THAT terminal_overwrite() WILL CHANGE - * el->el_cursor.h!!! - */ - terminal_overwrite(el, &el->el_display[ - el->el_cursor.v][el->el_cursor.h], - (size_t)(where - el->el_cursor.h)); - - } - } else { /* del < 0 := moving backward */ - if ((-del > 4) && GoodStr(T_LE)) - terminal_tputs(el, tgoto(Str(T_LE), -del, -del), - -del); - else { /* can't go directly there */ - /* - * if the "cost" is greater than the "cost" - * from col 0 - */ - if (EL_CAN_TAB ? - ((unsigned int)-del > - (((unsigned int) where >> 3) + - (where & 07))) - : (-del > where)) { - terminal__putc(el, '\r');/* do a CR */ - el->el_cursor.h = 0; - goto mc_again; /* and try again */ - } - for (i = 0; i < -del; i++) - terminal__putc(el, '\b'); - } - } - } - el->el_cursor.h = where; /* now where is here */ -} - - -/* terminal_overwrite(): - * Overstrike num characters - * Assumes MB_FILL_CHARs are present to keep the column count correct - */ -protected void -terminal_overwrite(EditLine *el, const Char *cp, size_t n) -{ -#ifdef WIDECHAR - int width; -#endif - - if (n == 0) - return; - - if (n > (size_t)el->el_terminal.t_size.h) { -#ifdef DEBUG_SCREEN - (void) fprintf(el->el_errfile, - "terminal_overwrite: n is riduculous: %d\r\n", n); -#endif /* DEBUG_SCREEN */ - return; - } - - do { -#ifdef WIDECHAR - width = wcwidth(*cp); /* Returns -1 for faux character. */ - if (width != -1) - el->el_cursor.h += width; -#else - el->el_cursor.h++; -#endif - /* terminal__putc() ignores any MB_FILL_CHARs */ - terminal__putc(el, *cp++); - } while (--n); - - if (el->el_cursor.h >= el->el_terminal.t_size.h) { /* wrap? */ - if (EL_HAS_AUTO_MARGINS) { /* yes */ - el->el_cursor.h = 0; - el->el_cursor.v++; - if (EL_HAS_MAGIC_MARGINS) { - /* force the wrap to avoid the "magic" - * situation */ - Char c; - if ((c = el->el_display[el->el_cursor.v] - [el->el_cursor.h]) != '\0') { - terminal_overwrite(el, &c, (size_t)1); -#ifdef WIDECHAR - while (el->el_display[el->el_cursor.v] - [el->el_cursor.h] == MB_FILL_CHAR) - el->el_cursor.h++; -#endif - } else { - terminal__putc(el, ' '); - el->el_cursor.h = 1; - } - } - } else /* no wrap, but cursor stays on screen */ - el->el_cursor.h = el->el_terminal.t_size.h - 1; - } -} - - -/* terminal_deletechars(): - * Delete num characters - */ -protected void -terminal_deletechars(EditLine *el, int num) -{ - if (num <= 0) - return; - - if (!EL_CAN_DELETE) { -#ifdef DEBUG_EDIT - (void) fprintf(el->el_errfile, " ERROR: cannot delete \n"); -#endif /* DEBUG_EDIT */ - return; - } - if (num > el->el_terminal.t_size.h) { -#ifdef DEBUG_SCREEN - (void) fprintf(el->el_errfile, - "terminal_deletechars: num is riduculous: %d\r\n", num); -#endif /* DEBUG_SCREEN */ - return; - } - if (GoodStr(T_DC)) /* if I have multiple delete */ - if ((num > 1) || !GoodStr(T_dc)) { /* if dc would be more - * expen. */ - terminal_tputs(el, tgoto(Str(T_DC), num, num), num); - return; - } - if (GoodStr(T_dm)) /* if I have delete mode */ - terminal_tputs(el, Str(T_dm), 1); - - if (GoodStr(T_dc)) /* else do one at a time */ - while (num--) - terminal_tputs(el, Str(T_dc), 1); - - if (GoodStr(T_ed)) /* if I have delete mode */ - terminal_tputs(el, Str(T_ed), 1); -} - - -/* terminal_insertwrite(): - * Puts terminal in insert character mode or inserts num - * characters in the line - * Assumes MB_FILL_CHARs are present to keep column count correct - */ -protected void -terminal_insertwrite(EditLine *el, Char *cp, int num) -{ - if (num <= 0) - return; - if (!EL_CAN_INSERT) { -#ifdef DEBUG_EDIT - (void) fprintf(el->el_errfile, " ERROR: cannot insert \n"); -#endif /* DEBUG_EDIT */ - return; - } - if (num > el->el_terminal.t_size.h) { -#ifdef DEBUG_SCREEN - (void) fprintf(el->el_errfile, - "StartInsert: num is riduculous: %d\r\n", num); -#endif /* DEBUG_SCREEN */ - return; - } - if (GoodStr(T_IC)) /* if I have multiple insert */ - if ((num > 1) || !GoodStr(T_ic)) { - /* if ic would be more expensive */ - terminal_tputs(el, tgoto(Str(T_IC), num, num), num); - terminal_overwrite(el, cp, (size_t)num); - /* this updates el_cursor.h */ - return; - } - if (GoodStr(T_im) && GoodStr(T_ei)) { /* if I have insert mode */ - terminal_tputs(el, Str(T_im), 1); - - el->el_cursor.h += num; - do - terminal__putc(el, *cp++); - while (--num); - - if (GoodStr(T_ip)) /* have to make num chars insert */ - terminal_tputs(el, Str(T_ip), 1); - - terminal_tputs(el, Str(T_ei), 1); - return; - } - do { - if (GoodStr(T_ic)) /* have to make num chars insert */ - terminal_tputs(el, Str(T_ic), 1); - - terminal__putc(el, *cp++); - - el->el_cursor.h++; - - if (GoodStr(T_ip)) /* have to make num chars insert */ - terminal_tputs(el, Str(T_ip), 1); - /* pad the inserted char */ - - } while (--num); -} - - -/* terminal_clear_EOL(): - * clear to end of line. There are num characters to clear - */ -protected void -terminal_clear_EOL(EditLine *el, int num) -{ - int i; - - if (EL_CAN_CEOL && GoodStr(T_ce)) - terminal_tputs(el, Str(T_ce), 1); - else { - for (i = 0; i < num; i++) - terminal__putc(el, ' '); - el->el_cursor.h += num; /* have written num spaces */ - } -} - - -/* terminal_clear_screen(): - * Clear the screen - */ -protected void -terminal_clear_screen(EditLine *el) -{ /* clear the whole screen and home */ - - if (GoodStr(T_cl)) - /* send the clear screen code */ - terminal_tputs(el, Str(T_cl), Val(T_li)); - else if (GoodStr(T_ho) && GoodStr(T_cd)) { - terminal_tputs(el, Str(T_ho), Val(T_li)); /* home */ - /* clear to bottom of screen */ - terminal_tputs(el, Str(T_cd), Val(T_li)); - } else { - terminal__putc(el, '\r'); - terminal__putc(el, '\n'); - } -} - - -/* terminal_beep(): - * Beep the way the terminal wants us - */ -protected void -terminal_beep(EditLine *el) -{ - if (GoodStr(T_bl)) - /* what termcap says we should use */ - terminal_tputs(el, Str(T_bl), 1); - else - terminal__putc(el, '\007'); /* an ASCII bell; ^G */ -} - - -protected void -terminal_get(EditLine *el, const char **term) -{ - *term = el->el_terminal.t_name; -} - - -/* terminal_set(): - * Read in the terminal capabilities from the requested terminal - */ -protected int -terminal_set(EditLine *el, const char *term) -{ - int i; - char buf[TC_BUFSIZE]; - char *area; - const struct termcapstr *t; - sigset_t oset, nset; - int lins, cols; - - (void) sigemptyset(&nset); - (void) sigaddset(&nset, SIGWINCH); - (void) sigprocmask(SIG_BLOCK, &nset, &oset); - - area = buf; - - - if (term == NULL) - term = getenv("TERM"); - - if (!term || !term[0]) - term = "dumb"; - - if (strcmp(term, "emacs") == 0) - el->el_flags |= EDIT_DISABLED; - - memset(el->el_terminal.t_cap, 0, TC_BUFSIZE); - - i = tgetent(el->el_terminal.t_cap, term); - - if (i <= 0) { - if (i == -1) - (void) fprintf(el->el_errfile, - "Cannot read termcap database;\n"); - else if (i == 0) - (void) fprintf(el->el_errfile, - "No entry for terminal type \"%s\";\n", term); - (void) fprintf(el->el_errfile, - "using dumb terminal settings.\n"); - Val(T_co) = 80; /* do a dumb terminal */ - Val(T_pt) = Val(T_km) = Val(T_li) = 0; - Val(T_xt) = Val(T_MT); - for (t = tstr; t->name != NULL; t++) - terminal_alloc(el, t, NULL); - } else { - /* auto/magic margins */ - Val(T_am) = tgetflag((char*) "am"); - Val(T_xn) = tgetflag((char*) "xn"); - /* Can we tab */ - Val(T_pt) = tgetflag((char*) "pt"); - Val(T_xt) = tgetflag((char*) "xt"); - /* do we have a meta? */ - Val(T_km) = tgetflag((char*) "km"); - Val(T_MT) = tgetflag((char*) "MT"); - /* Get the size */ - Val(T_co) = tgetnum((char*) "co"); - Val(T_li) = tgetnum((char*) "li"); - for (t = tstr; t->name != NULL; t++) { - /* XXX: some systems' tgetstr needs non const */ - terminal_alloc(el, t, tgetstr(strchr(t->name, *t->name), - &area)); - } - } - - if (Val(T_co) < 2) - Val(T_co) = 80; /* just in case */ - if (Val(T_li) < 1) - Val(T_li) = 24; - - el->el_terminal.t_size.v = Val(T_co); - el->el_terminal.t_size.h = Val(T_li); - - terminal_setflags(el); - - /* get the correct window size */ - (void) terminal_get_size(el, &lins, &cols); - if (terminal_change_size(el, lins, cols) == -1) - return -1; - (void) sigprocmask(SIG_SETMASK, &oset, NULL); - terminal_bind_arrow(el); - el->el_terminal.t_name = term; - return i <= 0 ? -1 : 0; -} - - -/* terminal_get_size(): - * Return the new window size in lines and cols, and - * true if the size was changed. - */ -protected int -terminal_get_size(EditLine *el, int *lins, int *cols) -{ - - *cols = Val(T_co); - *lins = Val(T_li); - -#ifdef TIOCGWINSZ - { - struct winsize ws; - if (ioctl(el->el_infd, TIOCGWINSZ, &ws) != -1) { - if (ws.ws_col) - *cols = ws.ws_col; - if (ws.ws_row) - *lins = ws.ws_row; - } - } -#endif -#ifdef TIOCGSIZE - { - struct ttysize ts; - if (ioctl(el->el_infd, TIOCGSIZE, &ts) != -1) { - if (ts.ts_cols) - *cols = ts.ts_cols; - if (ts.ts_lines) - *lins = ts.ts_lines; - } - } -#endif - return Val(T_co) != *cols || Val(T_li) != *lins; -} - - -/* terminal_change_size(): - * Change the size of the terminal - */ -protected int -terminal_change_size(EditLine *el, int lins, int cols) -{ - /* - * Just in case - */ - Val(T_co) = (cols < 2) ? 80 : cols; - Val(T_li) = (lins < 1) ? 24 : lins; - - /* re-make display buffers */ - if (terminal_rebuffer_display(el) == -1) - return -1; - re_clear_display(el); - return 0; -} - - -/* terminal_init_arrow(): - * Initialize the arrow key bindings from termcap - */ -private void -terminal_init_arrow(EditLine *el) -{ - funckey_t *arrow = el->el_terminal.t_fkey; - - arrow[A_K_DN].name = STR("down"); - arrow[A_K_DN].key = T_kd; - arrow[A_K_DN].fun.cmd = ED_NEXT_HISTORY; - arrow[A_K_DN].type = XK_CMD; - - arrow[A_K_UP].name = STR("up"); - arrow[A_K_UP].key = T_ku; - arrow[A_K_UP].fun.cmd = ED_PREV_HISTORY; - arrow[A_K_UP].type = XK_CMD; - - arrow[A_K_LT].name = STR("left"); - arrow[A_K_LT].key = T_kl; - arrow[A_K_LT].fun.cmd = ED_PREV_CHAR; - arrow[A_K_LT].type = XK_CMD; - - arrow[A_K_RT].name = STR("right"); - arrow[A_K_RT].key = T_kr; - arrow[A_K_RT].fun.cmd = ED_NEXT_CHAR; - arrow[A_K_RT].type = XK_CMD; - - arrow[A_K_HO].name = STR("home"); - arrow[A_K_HO].key = T_kh; - arrow[A_K_HO].fun.cmd = ED_MOVE_TO_BEG; - arrow[A_K_HO].type = XK_CMD; - - arrow[A_K_EN].name = STR("end"); - arrow[A_K_EN].key = T_at7; - arrow[A_K_EN].fun.cmd = ED_MOVE_TO_END; - arrow[A_K_EN].type = XK_CMD; -} - - -/* terminal_reset_arrow(): - * Reset arrow key bindings - */ -private void -terminal_reset_arrow(EditLine *el) -{ - funckey_t *arrow = el->el_terminal.t_fkey; - static const Char strA[] = {033, '[', 'A', '\0'}; - static const Char strB[] = {033, '[', 'B', '\0'}; - static const Char strC[] = {033, '[', 'C', '\0'}; - static const Char strD[] = {033, '[', 'D', '\0'}; - static const Char strH[] = {033, '[', 'H', '\0'}; - static const Char strF[] = {033, '[', 'F', '\0'}; - static const Char stOA[] = {033, 'O', 'A', '\0'}; - static const Char stOB[] = {033, 'O', 'B', '\0'}; - static const Char stOC[] = {033, 'O', 'C', '\0'}; - static const Char stOD[] = {033, 'O', 'D', '\0'}; - static const Char stOH[] = {033, 'O', 'H', '\0'}; - static const Char stOF[] = {033, 'O', 'F', '\0'}; - - keymacro_add(el, strA, &arrow[A_K_UP].fun, arrow[A_K_UP].type); - keymacro_add(el, strB, &arrow[A_K_DN].fun, arrow[A_K_DN].type); - keymacro_add(el, strC, &arrow[A_K_RT].fun, arrow[A_K_RT].type); - keymacro_add(el, strD, &arrow[A_K_LT].fun, arrow[A_K_LT].type); - keymacro_add(el, strH, &arrow[A_K_HO].fun, arrow[A_K_HO].type); - keymacro_add(el, strF, &arrow[A_K_EN].fun, arrow[A_K_EN].type); - keymacro_add(el, stOA, &arrow[A_K_UP].fun, arrow[A_K_UP].type); - keymacro_add(el, stOB, &arrow[A_K_DN].fun, arrow[A_K_DN].type); - keymacro_add(el, stOC, &arrow[A_K_RT].fun, arrow[A_K_RT].type); - keymacro_add(el, stOD, &arrow[A_K_LT].fun, arrow[A_K_LT].type); - keymacro_add(el, stOH, &arrow[A_K_HO].fun, arrow[A_K_HO].type); - keymacro_add(el, stOF, &arrow[A_K_EN].fun, arrow[A_K_EN].type); - - if (el->el_map.type != MAP_VI) - return; - keymacro_add(el, &strA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type); - keymacro_add(el, &strB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type); - keymacro_add(el, &strC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type); - keymacro_add(el, &strD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type); - keymacro_add(el, &strH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type); - keymacro_add(el, &strF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type); - keymacro_add(el, &stOA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type); - keymacro_add(el, &stOB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type); - keymacro_add(el, &stOC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type); - keymacro_add(el, &stOD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type); - keymacro_add(el, &stOH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type); - keymacro_add(el, &stOF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type); -} - - -/* terminal_set_arrow(): - * Set an arrow key binding - */ -protected int -terminal_set_arrow(EditLine *el, const Char *name, keymacro_value_t *fun, - int type) -{ - funckey_t *arrow = el->el_terminal.t_fkey; - int i; - - for (i = 0; i < A_K_NKEYS; i++) - if (Strcmp(name, arrow[i].name) == 0) { - arrow[i].fun = *fun; - arrow[i].type = type; - return 0; - } - return -1; -} - - -/* terminal_clear_arrow(): - * Clear an arrow key binding - */ -protected int -terminal_clear_arrow(EditLine *el, const Char *name) -{ - funckey_t *arrow = el->el_terminal.t_fkey; - int i; - - for (i = 0; i < A_K_NKEYS; i++) - if (Strcmp(name, arrow[i].name) == 0) { - arrow[i].type = XK_NOD; - return 0; - } - return -1; -} - - -/* terminal_print_arrow(): - * Print the arrow key bindings - */ -protected void -terminal_print_arrow(EditLine *el, const Char *name) -{ - int i; - funckey_t *arrow = el->el_terminal.t_fkey; - - for (i = 0; i < A_K_NKEYS; i++) - if (*name == '\0' || Strcmp(name, arrow[i].name) == 0) - if (arrow[i].type != XK_NOD) - keymacro_kprint(el, arrow[i].name, - &arrow[i].fun, arrow[i].type); -} - - -/* terminal_bind_arrow(): - * Bind the arrow keys - */ -protected void -terminal_bind_arrow(EditLine *el) -{ - el_action_t *map; - const el_action_t *dmap; - int i, j; - char *p; - funckey_t *arrow = el->el_terminal.t_fkey; - - /* Check if the components needed are initialized */ - if (el->el_terminal.t_buf == NULL || el->el_map.key == NULL) - return; - - map = el->el_map.type == MAP_VI ? el->el_map.alt : el->el_map.key; - dmap = el->el_map.type == MAP_VI ? el->el_map.vic : el->el_map.emacs; - - terminal_reset_arrow(el); - - for (i = 0; i < A_K_NKEYS; i++) { - Char wt_str[VISUAL_WIDTH_MAX]; - Char *px; - size_t n; - - p = el->el_terminal.t_str[arrow[i].key]; - if (!p || !*p) - continue; - for (n = 0; n < VISUAL_WIDTH_MAX && p[n]; ++n) - wt_str[n] = p[n]; - while (n < VISUAL_WIDTH_MAX) - wt_str[n++] = '\0'; - px = wt_str; - j = (unsigned char) *p; - /* - * Assign the arrow keys only if: - * - * 1. They are multi-character arrow keys and the user - * has not re-assigned the leading character, or - * has re-assigned the leading character to be - * ED_SEQUENCE_LEAD_IN - * 2. They are single arrow keys pointing to an - * unassigned key. - */ - if (arrow[i].type == XK_NOD) - keymacro_clear(el, map, px); - else { - if (p[1] && (dmap[j] == map[j] || - map[j] == ED_SEQUENCE_LEAD_IN)) { - keymacro_add(el, px, &arrow[i].fun, - arrow[i].type); - map[j] = ED_SEQUENCE_LEAD_IN; - } else if (map[j] == ED_UNASSIGNED) { - keymacro_clear(el, map, px); - if (arrow[i].type == XK_CMD) - map[j] = arrow[i].fun.cmd; - else - keymacro_add(el, px, &arrow[i].fun, - arrow[i].type); - } - } - } -} - -/* terminal_putc(): - * Add a character - */ -private int -terminal_putc(int c) -{ - if (terminal_outfile == NULL) - return -1; - return fputc(c, terminal_outfile); -} - -private void -terminal_tputs(EditLine *el, const char *cap, int affcnt) -{ -#ifdef _REENTRANT - pthread_mutex_lock(&terminal_mutex); -#endif - terminal_outfile = el->el_outfile; - (void)tputs(cap, affcnt, terminal_putc); -#ifdef _REENTRANT - pthread_mutex_unlock(&terminal_mutex); -#endif -} - -/* terminal__putc(): - * Add a character - */ -protected int -terminal__putc(EditLine *el, Int c) -{ - char buf[MB_LEN_MAX +1]; - ssize_t i; - mbstate_t state; - - memset(&state, 0, sizeof(mbstate_t)); - if (c == (Int)MB_FILL_CHAR) - return 0; - i = ct_encode_char(buf, (size_t)MB_CUR_MAX, c, &state); - if (i <= 0) - return (int)i; - buf[i] = '\0'; - return fputs(buf, el->el_outfile); -} - -/* terminal__flush(): - * Flush output - */ -protected void -terminal__flush(EditLine *el) -{ - - (void) fflush(el->el_outfile); -} - -/* terminal_writec(): - * Write the given character out, in a human readable form - */ -protected void -terminal_writec(EditLine *el, Int c) -{ - Char visbuf[VISUAL_WIDTH_MAX +1]; - ssize_t vcnt = ct_visual_char(visbuf, VISUAL_WIDTH_MAX, c); - visbuf[vcnt] = '\0'; - terminal_overwrite(el, visbuf, (size_t)vcnt); - terminal__flush(el); -} - - -/* terminal_telltc(): - * Print the current termcap characteristics - */ -protected int -/*ARGSUSED*/ -terminal_telltc(EditLine *el, int argc __attribute__((__unused__)), - const Char **argv __attribute__((__unused__))) -{ - const struct termcapstr *t; - char **ts; - - (void) fprintf(el->el_outfile, "\n\tYour terminal has the\n"); - (void) fprintf(el->el_outfile, "\tfollowing characteristics:\n\n"); - (void) fprintf(el->el_outfile, "\tIt has %d columns and %d lines\n", - Val(T_co), Val(T_li)); - (void) fprintf(el->el_outfile, - "\tIt has %s meta key\n", EL_HAS_META ? "a" : "no"); - (void) fprintf(el->el_outfile, - "\tIt can%suse tabs\n", EL_CAN_TAB ? " " : "not "); - (void) fprintf(el->el_outfile, "\tIt %s automatic margins\n", - EL_HAS_AUTO_MARGINS ? "has" : "does not have"); - if (EL_HAS_AUTO_MARGINS) - (void) fprintf(el->el_outfile, "\tIt %s magic margins\n", - EL_HAS_MAGIC_MARGINS ? "has" : "does not have"); - - for (t = tstr, ts = el->el_terminal.t_str; t->name != NULL; t++, ts++) { - const char *ub; - if (*ts && **ts) { - ub = ct_encode_string(ct_visual_string( - ct_decode_string(*ts, &el->el_scratch)), - &el->el_scratch); - } else { - ub = "(empty)"; - } - (void) fprintf(el->el_outfile, "\t%25s (%s) == %s\n", - t->long_name, t->name, ub); - } - (void) fputc('\n', el->el_outfile); - return 0; -} - - -/* terminal_settc(): - * Change the current terminal characteristics - */ -protected int -/*ARGSUSED*/ -terminal_settc(EditLine *el, int argc __attribute__((__unused__)), - const Char **argv) -{ - const struct termcapstr *ts; - const struct termcapval *tv; - char what[8], how[8]; - - if (argv == NULL || argv[1] == NULL || argv[2] == NULL) - return -1; - - strncpy(what, ct_encode_string(argv[1], &el->el_scratch), sizeof(what)); - what[sizeof(what) - 1] = '\0'; - strncpy(how, ct_encode_string(argv[2], &el->el_scratch), sizeof(how)); - how[sizeof(how) - 1] = '\0'; - - /* - * Do the strings first - */ - for (ts = tstr; ts->name != NULL; ts++) - if (strcmp(ts->name, what) == 0) - break; - - if (ts->name != NULL) { - terminal_alloc(el, ts, how); - terminal_setflags(el); - return 0; - } - /* - * Do the numeric ones second - */ - for (tv = tval; tv->name != NULL; tv++) - if (strcmp(tv->name, what) == 0) - break; - - if (tv->name != NULL) - return -1; - - if (tv == &tval[T_pt] || tv == &tval[T_km] || - tv == &tval[T_am] || tv == &tval[T_xn]) { - if (strcmp(how, "yes") == 0) - el->el_terminal.t_val[tv - tval] = 1; - else if (strcmp(how, "no") == 0) - el->el_terminal.t_val[tv - tval] = 0; - else { - (void) fprintf(el->el_errfile, - "" FSTR ": Bad value `%s'.\n", argv[0], how); - return -1; - } - terminal_setflags(el); - if (terminal_change_size(el, Val(T_li), Val(T_co)) == -1) - return -1; - return 0; - } else { - long i; - char *ep; - - i = strtol(how, &ep, 10); - if (*ep != '\0') { - (void) fprintf(el->el_errfile, - "" FSTR ": Bad value `%s'.\n", argv[0], how); - return -1; - } - el->el_terminal.t_val[tv - tval] = (int) i; - el->el_terminal.t_size.v = Val(T_co); - el->el_terminal.t_size.h = Val(T_li); - if (tv == &tval[T_co] || tv == &tval[T_li]) - if (terminal_change_size(el, Val(T_li), Val(T_co)) - == -1) - return -1; - return 0; - } -} - - -/* terminal_gettc(): - * Get the current terminal characteristics - */ -protected int -/*ARGSUSED*/ -terminal_gettc(EditLine *el, int argc __attribute__((__unused__)), char **argv) -{ - const struct termcapstr *ts; - const struct termcapval *tv; - char *what; - void *how; - - if (argv == NULL || argv[1] == NULL || argv[2] == NULL) - return -1; - - what = argv[1]; - how = argv[2]; - - /* - * Do the strings first - */ - for (ts = tstr; ts->name != NULL; ts++) - if (strcmp(ts->name, what) == 0) - break; - - if (ts->name != NULL) { - *(char **)how = el->el_terminal.t_str[ts - tstr]; - return 0; - } - /* - * Do the numeric ones second - */ - for (tv = tval; tv->name != NULL; tv++) - if (strcmp(tv->name, what) == 0) - break; - - if (tv->name == NULL) - return -1; - - if (tv == &tval[T_pt] || tv == &tval[T_km] || - tv == &tval[T_am] || tv == &tval[T_xn]) { - static char yes[] = "yes"; - static char no[] = "no"; - if (el->el_terminal.t_val[tv - tval]) - *(char **)how = yes; - else - *(char **)how = no; - return 0; - } else { - *(int *)how = el->el_terminal.t_val[tv - tval]; - return 0; - } -} - -/* terminal_echotc(): - * Print the termcap string out with variable substitution - */ -protected int -/*ARGSUSED*/ -terminal_echotc(EditLine *el, int argc __attribute__((__unused__)), - const Char **argv) -{ - char *cap, *scap; - Char *ep; - int arg_need, arg_cols, arg_rows; - int verbose = 0, silent = 0; - char *area; - static const char fmts[] = "%s\n", fmtd[] = "%d\n"; - const struct termcapstr *t; - char buf[TC_BUFSIZE]; - long i; - - area = buf; - - if (argv == NULL || argv[1] == NULL) - return -1; - argv++; - - if (argv[0][0] == '-') { - switch (argv[0][1]) { - case 'v': - verbose = 1; - break; - case 's': - silent = 1; - break; - default: - /* stderror(ERR_NAME | ERR_TCUSAGE); */ - break; - } - argv++; - } - if (!*argv || *argv[0] == '\0') - return 0; - if (Strcmp(*argv, STR("tabs")) == 0) { - (void) fprintf(el->el_outfile, fmts, EL_CAN_TAB ? "yes" : "no"); - return 0; - } else if (Strcmp(*argv, STR("meta")) == 0) { - (void) fprintf(el->el_outfile, fmts, Val(T_km) ? "yes" : "no"); - return 0; - } else if (Strcmp(*argv, STR("xn")) == 0) { - (void) fprintf(el->el_outfile, fmts, EL_HAS_MAGIC_MARGINS ? - "yes" : "no"); - return 0; - } else if (Strcmp(*argv, STR("am")) == 0) { - (void) fprintf(el->el_outfile, fmts, EL_HAS_AUTO_MARGINS ? - "yes" : "no"); - return 0; - } else if (Strcmp(*argv, STR("baud")) == 0) { - (void) fprintf(el->el_outfile, fmtd, (int)el->el_tty.t_speed); - return 0; - } else if (Strcmp(*argv, STR("rows")) == 0 || - Strcmp(*argv, STR("lines")) == 0) { - (void) fprintf(el->el_outfile, fmtd, Val(T_li)); - return 0; - } else if (Strcmp(*argv, STR("cols")) == 0) { - (void) fprintf(el->el_outfile, fmtd, Val(T_co)); - return 0; - } - /* - * Try to use our local definition first - */ - scap = NULL; - for (t = tstr; t->name != NULL; t++) - if (strcmp(t->name, - ct_encode_string(*argv, &el->el_scratch)) == 0) { - scap = el->el_terminal.t_str[t - tstr]; - break; - } - if (t->name == NULL) { - /* XXX: some systems' tgetstr needs non const */ - scap = tgetstr(ct_encode_string(*argv, &el->el_scratch), &area); - } - if (!scap || scap[0] == '\0') { - if (!silent) - (void) fprintf(el->el_errfile, - "echotc: Termcap parameter `" FSTR "' not found.\n", - *argv); - return -1; - } - /* - * Count home many values we need for this capability. - */ - for (cap = scap, arg_need = 0; *cap; cap++) - if (*cap == '%') - switch (*++cap) { - case 'd': - case '2': - case '3': - case '.': - case '+': - arg_need++; - break; - case '%': - case '>': - case 'i': - case 'r': - case 'n': - case 'B': - case 'D': - break; - default: - /* - * hpux has lot's of them... - */ - if (verbose) - (void) fprintf(el->el_errfile, - "echotc: Warning: unknown termcap %% `%c'.\n", - *cap); - /* This is bad, but I won't complain */ - break; - } - - switch (arg_need) { - case 0: - argv++; - if (*argv && *argv[0]) { - if (!silent) - (void) fprintf(el->el_errfile, - "echotc: Warning: Extra argument `" FSTR "'.\n", - *argv); - return -1; - } - terminal_tputs(el, scap, 1); - break; - case 1: - argv++; - if (!*argv || *argv[0] == '\0') { - if (!silent) - (void) fprintf(el->el_errfile, - "echotc: Warning: Missing argument.\n"); - return -1; - } - arg_cols = 0; - i = Strtol(*argv, &ep, 10); - if (*ep != '\0' || i < 0) { - if (!silent) - (void) fprintf(el->el_errfile, - "echotc: Bad value `" FSTR "' for rows.\n", - *argv); - return -1; - } - arg_rows = (int) i; - argv++; - if (*argv && *argv[0]) { - if (!silent) - (void) fprintf(el->el_errfile, - "echotc: Warning: Extra argument `" FSTR - "'.\n", *argv); - return -1; - } - terminal_tputs(el, tgoto(scap, arg_cols, arg_rows), 1); - break; - default: - /* This is wrong, but I will ignore it... */ - if (verbose) - (void) fprintf(el->el_errfile, - "echotc: Warning: Too many required arguments (%d).\n", - arg_need); - /* FALLTHROUGH */ - case 2: - argv++; - if (!*argv || *argv[0] == '\0') { - if (!silent) - (void) fprintf(el->el_errfile, - "echotc: Warning: Missing argument.\n"); - return -1; - } - i = Strtol(*argv, &ep, 10); - if (*ep != '\0' || i < 0) { - if (!silent) - (void) fprintf(el->el_errfile, - "echotc: Bad value `" FSTR "' for cols.\n", - *argv); - return -1; - } - arg_cols = (int) i; - argv++; - if (!*argv || *argv[0] == '\0') { - if (!silent) - (void) fprintf(el->el_errfile, - "echotc: Warning: Missing argument.\n"); - return -1; - } - i = Strtol(*argv, &ep, 10); - if (*ep != '\0' || i < 0) { - if (!silent) - (void) fprintf(el->el_errfile, - "echotc: Bad value `" FSTR "' for rows.\n", - *argv); - return -1; - } - arg_rows = (int) i; - if (*ep != '\0') { - if (!silent) - (void) fprintf(el->el_errfile, - "echotc: Bad value `" FSTR "'.\n", *argv); - return -1; - } - argv++; - if (*argv && *argv[0]) { - if (!silent) - (void) fprintf(el->el_errfile, - "echotc: Warning: Extra argument `" FSTR - "'.\n", *argv); - return -1; - } - terminal_tputs(el, tgoto(scap, arg_cols, arg_rows), arg_rows); - break; - } - return 0; -} diff --git a/cmd-line-utils/libedit/tokenizer.c b/cmd-line-utils/libedit/tokenizer.c deleted file mode 100644 index 7267164e9b6..00000000000 --- a/cmd-line-utils/libedit/tokenizer.c +++ /dev/null @@ -1,449 +0,0 @@ -/* $NetBSD: tokenizer.c,v 1.19 2011/07/28 20:50:55 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)tokenizer.c 8.1 (Berkeley) 6/4/93"; -#else -#endif -#endif /* not lint && not SCCSID */ - -/* We build this file twice, once as NARROW, once as WIDE. */ -/* - * tokenize.c: Bourne shell like tokenizer - */ -#include -#include -#include "histedit.h" -#include "chartype.h" - -typedef enum { - Q_none, Q_single, Q_double, Q_one, Q_doubleone -} quote_t; - -#define TOK_KEEP 1 -#define TOK_EAT 2 - -#define WINCR 20 -#define AINCR 10 - -#define IFS STR("\t \n") - -#define tok_malloc(a) malloc(a) -#define tok_free(a) free(a) -#define tok_realloc(a, b) realloc(a, b) -#define tok_strdup(a) Strdup(a) - - -struct TYPE(tokenizer) { - Char *ifs; /* In field separator */ - int argc, amax; /* Current and maximum number of args */ - Char **argv; /* Argument list */ - Char *wptr, *wmax; /* Space and limit on the word buffer */ - Char *wstart; /* Beginning of next word */ - Char *wspace; /* Space of word buffer */ - quote_t quote; /* Quoting state */ - int flags; /* flags; */ -}; - - -private void FUN(tok,finish)(TYPE(Tokenizer) *); - - -/* FUN(tok,finish)(): - * Finish a word in the tokenizer. - */ -private void -FUN(tok,finish)(TYPE(Tokenizer) *tok) -{ - - *tok->wptr = '\0'; - if ((tok->flags & TOK_KEEP) || tok->wptr != tok->wstart) { - tok->argv[tok->argc++] = tok->wstart; - tok->argv[tok->argc] = NULL; - tok->wstart = ++tok->wptr; - } - tok->flags &= ~TOK_KEEP; -} - - -/* FUN(tok,init)(): - * Initialize the tokenizer - */ -public TYPE(Tokenizer) * -FUN(tok,init)(const Char *ifs) -{ - TYPE(Tokenizer) *tok = tok_malloc(sizeof(*tok)); - - if (tok == NULL) - return NULL; - tok->ifs = tok_strdup(ifs ? ifs : IFS); - if (tok->ifs == NULL) { - tok_free(tok); - return NULL; - } - tok->argc = 0; - tok->amax = AINCR; - tok->argv = tok_malloc(sizeof(*tok->argv) * tok->amax); - if (tok->argv == NULL) { - tok_free(tok->ifs); - tok_free(tok); - return NULL; - } - tok->argv[0] = NULL; - tok->wspace = tok_malloc(WINCR * sizeof(*tok->wspace)); - if (tok->wspace == NULL) { - tok_free(tok->argv); - tok_free(tok->ifs); - tok_free(tok); - return NULL; - } - tok->wmax = tok->wspace + WINCR; - tok->wstart = tok->wspace; - tok->wptr = tok->wspace; - tok->flags = 0; - tok->quote = Q_none; - - return (tok); -} - - -/* FUN(tok,reset)(): - * Reset the tokenizer - */ -public void -FUN(tok,reset)(TYPE(Tokenizer) *tok) -{ - - tok->argc = 0; - tok->wstart = tok->wspace; - tok->wptr = tok->wspace; - tok->flags = 0; - tok->quote = Q_none; -} - - -/* FUN(tok,end)(): - * Clean up - */ -public void -FUN(tok,end)(TYPE(Tokenizer) *tok) -{ - - tok_free(tok->ifs); - tok_free(tok->wspace); - tok_free(tok->argv); - tok_free(tok); -} - - - -/* FUN(tok,line)(): - * Bourne shell (sh(1)) like tokenizing - * Arguments: - * tok current tokenizer state (setup with FUN(tok,init)()) - * line line to parse - * Returns: - * -1 Internal error - * 3 Quoted return - * 2 Unmatched double quote - * 1 Unmatched single quote - * 0 Ok - * Modifies (if return value is 0): - * argc number of arguments - * argv argument array - * cursorc if !NULL, argv element containing cursor - * cursorv if !NULL, offset in argv[cursorc] of cursor - */ -public int -FUN(tok,line)(TYPE(Tokenizer) *tok, const TYPE(LineInfo) *line, - int *argc, const Char ***argv, int *cursorc, int *cursoro) -{ - const Char *ptr; - int cc, co; - - cc = co = -1; - ptr = line->buffer; - for (ptr = line->buffer; ;ptr++) { - if (ptr >= line->lastchar) - ptr = STR(""); - if (ptr == line->cursor) { - cc = tok->argc; - co = (int)(tok->wptr - tok->wstart); - } - switch (*ptr) { - case '\'': - tok->flags |= TOK_KEEP; - tok->flags &= ~TOK_EAT; - switch (tok->quote) { - case Q_none: - tok->quote = Q_single; /* Enter single quote - * mode */ - break; - - case Q_single: /* Exit single quote mode */ - tok->quote = Q_none; - break; - - case Q_one: /* Quote this ' */ - tok->quote = Q_none; - *tok->wptr++ = *ptr; - break; - - case Q_double: /* Stay in double quote mode */ - *tok->wptr++ = *ptr; - break; - - case Q_doubleone: /* Quote this ' */ - tok->quote = Q_double; - *tok->wptr++ = *ptr; - break; - - default: - return (-1); - } - break; - - case '"': - tok->flags &= ~TOK_EAT; - tok->flags |= TOK_KEEP; - switch (tok->quote) { - case Q_none: /* Enter double quote mode */ - tok->quote = Q_double; - break; - - case Q_double: /* Exit double quote mode */ - tok->quote = Q_none; - break; - - case Q_one: /* Quote this " */ - tok->quote = Q_none; - *tok->wptr++ = *ptr; - break; - - case Q_single: /* Stay in single quote mode */ - *tok->wptr++ = *ptr; - break; - - case Q_doubleone: /* Quote this " */ - tok->quote = Q_double; - *tok->wptr++ = *ptr; - break; - - default: - return (-1); - } - break; - - case '\\': - tok->flags |= TOK_KEEP; - tok->flags &= ~TOK_EAT; - switch (tok->quote) { - case Q_none: /* Quote next character */ - tok->quote = Q_one; - break; - - case Q_double: /* Quote next character */ - tok->quote = Q_doubleone; - break; - - case Q_one: /* Quote this, restore state */ - *tok->wptr++ = *ptr; - tok->quote = Q_none; - break; - - case Q_single: /* Stay in single quote mode */ - *tok->wptr++ = *ptr; - break; - - case Q_doubleone: /* Quote this \ */ - tok->quote = Q_double; - *tok->wptr++ = *ptr; - break; - - default: - return (-1); - } - break; - - case '\n': - tok->flags &= ~TOK_EAT; - switch (tok->quote) { - case Q_none: - goto tok_line_outok; - - case Q_single: - case Q_double: - *tok->wptr++ = *ptr; /* Add the return */ - break; - - case Q_doubleone: /* Back to double, eat the '\n' */ - tok->flags |= TOK_EAT; - tok->quote = Q_double; - break; - - case Q_one: /* No quote, more eat the '\n' */ - tok->flags |= TOK_EAT; - tok->quote = Q_none; - break; - - default: - return (0); - } - break; - - case '\0': - switch (tok->quote) { - case Q_none: - /* Finish word and return */ - if (tok->flags & TOK_EAT) { - tok->flags &= ~TOK_EAT; - return (3); - } - goto tok_line_outok; - - case Q_single: - return (1); - - case Q_double: - return (2); - - case Q_doubleone: - tok->quote = Q_double; - *tok->wptr++ = *ptr; - break; - - case Q_one: - tok->quote = Q_none; - *tok->wptr++ = *ptr; - break; - - default: - return (-1); - } - break; - - default: - tok->flags &= ~TOK_EAT; - switch (tok->quote) { - case Q_none: - if (Strchr(tok->ifs, *ptr) != NULL) - FUN(tok,finish)(tok); - else - *tok->wptr++ = *ptr; - break; - - case Q_single: - case Q_double: - *tok->wptr++ = *ptr; - break; - - - case Q_doubleone: - *tok->wptr++ = '\\'; - tok->quote = Q_double; - *tok->wptr++ = *ptr; - break; - - case Q_one: - tok->quote = Q_none; - *tok->wptr++ = *ptr; - break; - - default: - return (-1); - - } - break; - } - - if (tok->wptr >= tok->wmax - 4) { - size_t size = tok->wmax - tok->wspace + WINCR; - Char *s = tok_realloc(tok->wspace, - size * sizeof(*s)); - if (s == NULL) - return (-1); - - if (s != tok->wspace) { - int i; - for (i = 0; i < tok->argc; i++) { - tok->argv[i] = - (tok->argv[i] - tok->wspace) + s; - } - tok->wptr = (tok->wptr - tok->wspace) + s; - tok->wstart = (tok->wstart - tok->wspace) + s; - tok->wspace = s; - } - tok->wmax = s + size; - } - if (tok->argc >= tok->amax - 4) { - Char **p; - tok->amax += AINCR; - p = tok_realloc(tok->argv, tok->amax * sizeof(*p)); - if (p == NULL) - return (-1); - tok->argv = p; - } - } - tok_line_outok: - if (cc == -1 && co == -1) { - cc = tok->argc; - co = (int)(tok->wptr - tok->wstart); - } - if (cursorc != NULL) - *cursorc = cc; - if (cursoro != NULL) - *cursoro = co; - FUN(tok,finish)(tok); - *argv = (const Char **)tok->argv; - *argc = tok->argc; - return (0); -} - -/* FUN(tok,str)(): - * Simpler version of tok_line, taking a NUL terminated line - * and splitting into words, ignoring cursor state. - */ -public int -FUN(tok,str)(TYPE(Tokenizer) *tok, const Char *line, int *argc, - const Char ***argv) -{ - TYPE(LineInfo) li; - - memset(&li, 0, sizeof(li)); - li.buffer = line; - li.cursor = li.lastchar = Strchr(line, '\0'); - return (FUN(tok,line)(tok, &li, argc, argv, NULL, NULL)); -} diff --git a/cmd-line-utils/libedit/tokenizern.c b/cmd-line-utils/libedit/tokenizern.c deleted file mode 100644 index 92376e066f1..00000000000 --- a/cmd-line-utils/libedit/tokenizern.c +++ /dev/null @@ -1,5 +0,0 @@ -#define NARROW_WRAPPER -#include "config.h" -#undef WIDECHAR -#define NARROWCHAR -#include "./tokenizer.c" diff --git a/cmd-line-utils/libedit/tty.c b/cmd-line-utils/libedit/tty.c deleted file mode 100644 index eea00bfc245..00000000000 --- a/cmd-line-utils/libedit/tty.c +++ /dev/null @@ -1,1353 +0,0 @@ -/* $NetBSD: tty.c,v 1.41 2011/10/04 15:27:04 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)tty.c 8.1 (Berkeley) 6/4/93"; -#else -#endif -#endif /* not lint && not SCCSID */ - -/* - * tty.c: tty interface stuff - */ -#include -#include -#include /* for isatty */ -#include /* for ffs */ -#include "el.h" -#include "tty.h" - -typedef struct ttymodes_t { - const char *m_name; - unsigned int m_value; - int m_type; -} ttymodes_t; - -typedef struct ttymap_t { - Int nch, och; /* Internal and termio rep of chars */ - el_action_t bind[3]; /* emacs, vi, and vi-cmd */ -} ttymap_t; - - -private const ttyperm_t ttyperm = { - { - {"iflag:", ICRNL, (INLCR | IGNCR)}, - {"oflag:", (OPOST | ONLCR), ONLRET}, - {"cflag:", 0, 0}, - {"lflag:", (ISIG | ICANON | ECHO | ECHOE | ECHOCTL | IEXTEN), - (NOFLSH | ECHONL | EXTPROC | FLUSHO)}, - {"chars:", 0, 0}, - }, - { - {"iflag:", (INLCR | ICRNL), IGNCR}, - {"oflag:", (OPOST | ONLCR), ONLRET}, - {"cflag:", 0, 0}, - {"lflag:", ISIG, - (NOFLSH | ICANON | ECHO | ECHOK | ECHONL | EXTPROC | IEXTEN | FLUSHO)}, - {"chars:", (C_SH(C_MIN) | C_SH(C_TIME) | C_SH(C_SWTCH) | C_SH(C_DSWTCH) | - C_SH(C_SUSP) | C_SH(C_DSUSP) | C_SH(C_EOL) | C_SH(C_DISCARD) | - C_SH(C_PGOFF) | C_SH(C_PAGE) | C_SH(C_STATUS)), 0} - }, - { - {"iflag:", 0, IXON | IXOFF | INLCR | ICRNL}, - {"oflag:", 0, 0}, - {"cflag:", 0, 0}, - {"lflag:", 0, ISIG | IEXTEN}, - {"chars:", 0, 0}, - } -}; - -private const ttychar_t ttychar = { - { - CINTR, CQUIT, CERASE, CKILL, - CEOF, CEOL, CEOL2, CSWTCH, - CDSWTCH, CERASE2, CSTART, CSTOP, - CWERASE, CSUSP, CDSUSP, CREPRINT, - CDISCARD, CLNEXT, CSTATUS, CPAGE, - CPGOFF, CKILL2, CBRK, CMIN, - CTIME - }, - { - CINTR, CQUIT, CERASE, CKILL, - _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, - _POSIX_VDISABLE, CERASE2, CSTART, CSTOP, - _POSIX_VDISABLE, CSUSP, _POSIX_VDISABLE, _POSIX_VDISABLE, - CDISCARD, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, - _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, 1, - 0 - }, - { - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0 - } -}; - -private const ttymap_t tty_map[] = { -#ifdef VERASE - {C_ERASE, VERASE, - {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}}, -#endif /* VERASE */ -#ifdef VERASE2 - {C_ERASE2, VERASE2, - {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}}, -#endif /* VERASE2 */ -#ifdef VKILL - {C_KILL, VKILL, - {EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}}, -#endif /* VKILL */ -#ifdef VKILL2 - {C_KILL2, VKILL2, - {EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}}, -#endif /* VKILL2 */ -#ifdef VEOF - {C_EOF, VEOF, - {EM_DELETE_OR_LIST, VI_LIST_OR_EOF, ED_UNASSIGNED}}, -#endif /* VEOF */ -#ifdef VWERASE - {C_WERASE, VWERASE, - {ED_DELETE_PREV_WORD, ED_DELETE_PREV_WORD, ED_PREV_WORD}}, -#endif /* VWERASE */ -#ifdef VREPRINT - {C_REPRINT, VREPRINT, - {ED_REDISPLAY, ED_INSERT, ED_REDISPLAY}}, -#endif /* VREPRINT */ -#ifdef VLNEXT - {C_LNEXT, VLNEXT, - {ED_QUOTED_INSERT, ED_QUOTED_INSERT, ED_UNASSIGNED}}, -#endif /* VLNEXT */ - {(Int)-1, (Int)-1, - {ED_UNASSIGNED, ED_UNASSIGNED, ED_UNASSIGNED}} -}; - -private const ttymodes_t ttymodes[] = { -#ifdef IGNBRK - {"ignbrk", IGNBRK, MD_INP}, -#endif /* IGNBRK */ -#ifdef BRKINT - {"brkint", BRKINT, MD_INP}, -#endif /* BRKINT */ -#ifdef IGNPAR - {"ignpar", IGNPAR, MD_INP}, -#endif /* IGNPAR */ -#ifdef PARMRK - {"parmrk", PARMRK, MD_INP}, -#endif /* PARMRK */ -#ifdef INPCK - {"inpck", INPCK, MD_INP}, -#endif /* INPCK */ -#ifdef ISTRIP - {"istrip", ISTRIP, MD_INP}, -#endif /* ISTRIP */ -#ifdef INLCR - {"inlcr", INLCR, MD_INP}, -#endif /* INLCR */ -#ifdef IGNCR - {"igncr", IGNCR, MD_INP}, -#endif /* IGNCR */ -#ifdef ICRNL - {"icrnl", ICRNL, MD_INP}, -#endif /* ICRNL */ -#ifdef IUCLC - {"iuclc", IUCLC, MD_INP}, -#endif /* IUCLC */ -#ifdef IXON - {"ixon", IXON, MD_INP}, -#endif /* IXON */ -#ifdef IXANY - {"ixany", IXANY, MD_INP}, -#endif /* IXANY */ -#ifdef IXOFF - {"ixoff", IXOFF, MD_INP}, -#endif /* IXOFF */ -#ifdef IMAXBEL - {"imaxbel", IMAXBEL, MD_INP}, -#endif /* IMAXBEL */ - -#ifdef OPOST - {"opost", OPOST, MD_OUT}, -#endif /* OPOST */ -#ifdef OLCUC - {"olcuc", OLCUC, MD_OUT}, -#endif /* OLCUC */ -#ifdef ONLCR - {"onlcr", ONLCR, MD_OUT}, -#endif /* ONLCR */ -#ifdef OCRNL - {"ocrnl", OCRNL, MD_OUT}, -#endif /* OCRNL */ -#ifdef ONOCR - {"onocr", ONOCR, MD_OUT}, -#endif /* ONOCR */ -#ifdef ONOEOT - {"onoeot", ONOEOT, MD_OUT}, -#endif /* ONOEOT */ -#ifdef ONLRET - {"onlret", ONLRET, MD_OUT}, -#endif /* ONLRET */ -#ifdef OFILL - {"ofill", OFILL, MD_OUT}, -#endif /* OFILL */ -#ifdef OFDEL - {"ofdel", OFDEL, MD_OUT}, -#endif /* OFDEL */ -#ifdef NLDLY - {"nldly", NLDLY, MD_OUT}, -#endif /* NLDLY */ -#ifdef CRDLY - {"crdly", CRDLY, MD_OUT}, -#endif /* CRDLY */ -#ifdef TABDLY - {"tabdly", TABDLY, MD_OUT}, -#endif /* TABDLY */ -#ifdef XTABS - {"xtabs", XTABS, MD_OUT}, -#endif /* XTABS */ -#ifdef BSDLY - {"bsdly", BSDLY, MD_OUT}, -#endif /* BSDLY */ -#ifdef VTDLY - {"vtdly", VTDLY, MD_OUT}, -#endif /* VTDLY */ -#ifdef FFDLY - {"ffdly", FFDLY, MD_OUT}, -#endif /* FFDLY */ -#ifdef PAGEOUT - {"pageout", PAGEOUT, MD_OUT}, -#endif /* PAGEOUT */ -#ifdef WRAP - {"wrap", WRAP, MD_OUT}, -#endif /* WRAP */ - -#ifdef CIGNORE - {"cignore", CIGNORE, MD_CTL}, -#endif /* CBAUD */ -#ifdef CBAUD - {"cbaud", CBAUD, MD_CTL}, -#endif /* CBAUD */ -#ifdef CSTOPB - {"cstopb", CSTOPB, MD_CTL}, -#endif /* CSTOPB */ -#ifdef CREAD - {"cread", CREAD, MD_CTL}, -#endif /* CREAD */ -#ifdef PARENB - {"parenb", PARENB, MD_CTL}, -#endif /* PARENB */ -#ifdef PARODD - {"parodd", PARODD, MD_CTL}, -#endif /* PARODD */ -#ifdef HUPCL - {"hupcl", HUPCL, MD_CTL}, -#endif /* HUPCL */ -#ifdef CLOCAL - {"clocal", CLOCAL, MD_CTL}, -#endif /* CLOCAL */ -#ifdef LOBLK - {"loblk", LOBLK, MD_CTL}, -#endif /* LOBLK */ -#ifdef CIBAUD - {"cibaud", CIBAUD, MD_CTL}, -#endif /* CIBAUD */ -#ifdef CRTSCTS -#ifdef CCTS_OFLOW - {"ccts_oflow", CCTS_OFLOW, MD_CTL}, -#else - {"crtscts", CRTSCTS, MD_CTL}, -#endif /* CCTS_OFLOW */ -#endif /* CRTSCTS */ -#ifdef CRTS_IFLOW - {"crts_iflow", CRTS_IFLOW, MD_CTL}, -#endif /* CRTS_IFLOW */ -#ifdef CDTRCTS - {"cdtrcts", CDTRCTS, MD_CTL}, -#endif /* CDTRCTS */ -#ifdef MDMBUF - {"mdmbuf", MDMBUF, MD_CTL}, -#endif /* MDMBUF */ -#ifdef RCV1EN - {"rcv1en", RCV1EN, MD_CTL}, -#endif /* RCV1EN */ -#ifdef XMT1EN - {"xmt1en", XMT1EN, MD_CTL}, -#endif /* XMT1EN */ - -#ifdef ISIG - {"isig", ISIG, MD_LIN}, -#endif /* ISIG */ -#ifdef ICANON - {"icanon", ICANON, MD_LIN}, -#endif /* ICANON */ -#ifdef XCASE - {"xcase", XCASE, MD_LIN}, -#endif /* XCASE */ -#ifdef ECHO - {"echo", ECHO, MD_LIN}, -#endif /* ECHO */ -#ifdef ECHOE - {"echoe", ECHOE, MD_LIN}, -#endif /* ECHOE */ -#ifdef ECHOK - {"echok", ECHOK, MD_LIN}, -#endif /* ECHOK */ -#ifdef ECHONL - {"echonl", ECHONL, MD_LIN}, -#endif /* ECHONL */ -#ifdef NOFLSH - {"noflsh", NOFLSH, MD_LIN}, -#endif /* NOFLSH */ -#ifdef TOSTOP - {"tostop", TOSTOP, MD_LIN}, -#endif /* TOSTOP */ -#ifdef ECHOCTL - {"echoctl", ECHOCTL, MD_LIN}, -#endif /* ECHOCTL */ -#ifdef ECHOPRT - {"echoprt", ECHOPRT, MD_LIN}, -#endif /* ECHOPRT */ -#ifdef ECHOKE - {"echoke", ECHOKE, MD_LIN}, -#endif /* ECHOKE */ -#ifdef DEFECHO - {"defecho", DEFECHO, MD_LIN}, -#endif /* DEFECHO */ -#ifdef FLUSHO - {"flusho", FLUSHO, MD_LIN}, -#endif /* FLUSHO */ -#ifdef PENDIN - {"pendin", PENDIN, MD_LIN}, -#endif /* PENDIN */ -#ifdef IEXTEN - {"iexten", IEXTEN, MD_LIN}, -#endif /* IEXTEN */ -#ifdef NOKERNINFO - {"nokerninfo", NOKERNINFO, MD_LIN}, -#endif /* NOKERNINFO */ -#ifdef ALTWERASE - {"altwerase", ALTWERASE, MD_LIN}, -#endif /* ALTWERASE */ -#ifdef EXTPROC - {"extproc", EXTPROC, MD_LIN}, -#endif /* EXTPROC */ - -#if defined(VINTR) - {"intr", C_SH(C_INTR), MD_CHAR}, -#endif /* VINTR */ -#if defined(VQUIT) - {"quit", C_SH(C_QUIT), MD_CHAR}, -#endif /* VQUIT */ -#if defined(VERASE) - {"erase", C_SH(C_ERASE), MD_CHAR}, -#endif /* VERASE */ -#if defined(VKILL) - {"kill", C_SH(C_KILL), MD_CHAR}, -#endif /* VKILL */ -#if defined(VEOF) - {"eof", C_SH(C_EOF), MD_CHAR}, -#endif /* VEOF */ -#if defined(VEOL) - {"eol", C_SH(C_EOL), MD_CHAR}, -#endif /* VEOL */ -#if defined(VEOL2) - {"eol2", C_SH(C_EOL2), MD_CHAR}, -#endif /* VEOL2 */ -#if defined(VSWTCH) - {"swtch", C_SH(C_SWTCH), MD_CHAR}, -#endif /* VSWTCH */ -#if defined(VDSWTCH) - {"dswtch", C_SH(C_DSWTCH), MD_CHAR}, -#endif /* VDSWTCH */ -#if defined(VERASE2) - {"erase2", C_SH(C_ERASE2), MD_CHAR}, -#endif /* VERASE2 */ -#if defined(VSTART) - {"start", C_SH(C_START), MD_CHAR}, -#endif /* VSTART */ -#if defined(VSTOP) - {"stop", C_SH(C_STOP), MD_CHAR}, -#endif /* VSTOP */ -#if defined(VWERASE) - {"werase", C_SH(C_WERASE), MD_CHAR}, -#endif /* VWERASE */ -#if defined(VSUSP) - {"susp", C_SH(C_SUSP), MD_CHAR}, -#endif /* VSUSP */ -#if defined(VDSUSP) - {"dsusp", C_SH(C_DSUSP), MD_CHAR}, -#endif /* VDSUSP */ -#if defined(VREPRINT) - {"reprint", C_SH(C_REPRINT), MD_CHAR}, -#endif /* VREPRINT */ -#if defined(VDISCARD) - {"discard", C_SH(C_DISCARD), MD_CHAR}, -#endif /* VDISCARD */ -#if defined(VLNEXT) - {"lnext", C_SH(C_LNEXT), MD_CHAR}, -#endif /* VLNEXT */ -#if defined(VSTATUS) - {"status", C_SH(C_STATUS), MD_CHAR}, -#endif /* VSTATUS */ -#if defined(VPAGE) - {"page", C_SH(C_PAGE), MD_CHAR}, -#endif /* VPAGE */ -#if defined(VPGOFF) - {"pgoff", C_SH(C_PGOFF), MD_CHAR}, -#endif /* VPGOFF */ -#if defined(VKILL2) - {"kill2", C_SH(C_KILL2), MD_CHAR}, -#endif /* VKILL2 */ -#if defined(VBRK) - {"brk", C_SH(C_BRK), MD_CHAR}, -#endif /* VBRK */ -#if defined(VMIN) - {"min", C_SH(C_MIN), MD_CHAR}, -#endif /* VMIN */ -#if defined(VTIME) - {"time", C_SH(C_TIME), MD_CHAR}, -#endif /* VTIME */ - {NULL, 0, -1}, -}; - - - -#define tty__gettabs(td) ((((td)->c_oflag & TAB3) == TAB3) ? 0 : 1) -#define tty__geteightbit(td) (((td)->c_cflag & CSIZE) == CS8) -#define tty__cooked_mode(td) ((td)->c_lflag & ICANON) - -private int tty_getty(EditLine *, struct termios *); -private int tty_setty(EditLine *, int, const struct termios *); -private int tty__getcharindex(int); -private void tty__getchar(struct termios *, unsigned char *); -private void tty__setchar(struct termios *, unsigned char *); -private speed_t tty__getspeed(struct termios *); -private int tty_setup(EditLine *); - -#define t_qu t_ts - -/* tty_getty(): - * Wrapper for tcgetattr to handle EINTR - */ -private int -tty_getty(EditLine *el, struct termios *t) -{ - int rv; - while ((rv = tcgetattr(el->el_infd, t)) == -1 && errno == EINTR) - continue; - return rv; -} - -/* tty_setty(): - * Wrapper for tcsetattr to handle EINTR - */ -private int -tty_setty(EditLine *el, int action, const struct termios *t) -{ - int rv; - while ((rv = tcsetattr(el->el_infd, action, t)) == -1 && errno == EINTR) - continue; - return rv; -} - -/* tty_setup(): - * Get the tty parameters and initialize the editing state - */ -private int -tty_setup(EditLine *el) -{ - int rst = 1; - - if (el->el_flags & EDIT_DISABLED) - return 0; - - if (!isatty(el->el_outfd)) { -#ifdef DEBUG_TTY - (void) fprintf(el->el_errfile, - "tty_setup: isatty: %s\n", strerror(errno)); -#endif /* DEBUG_TTY */ - return -1; - } - if (tty_getty(el, &el->el_tty.t_ed) == -1) { -#ifdef DEBUG_TTY - (void) fprintf(el->el_errfile, - "tty_setup: tty_getty: %s\n", strerror(errno)); -#endif /* DEBUG_TTY */ - return -1; - } - el->el_tty.t_ts = el->el_tty.t_ex = el->el_tty.t_ed; - - el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ex); - el->el_tty.t_tabs = tty__gettabs(&el->el_tty.t_ex); - el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ex); - - el->el_tty.t_ex.c_iflag &= ~el->el_tty.t_t[EX_IO][MD_INP].t_clrmask; - el->el_tty.t_ex.c_iflag |= el->el_tty.t_t[EX_IO][MD_INP].t_setmask; - - el->el_tty.t_ex.c_oflag &= ~el->el_tty.t_t[EX_IO][MD_OUT].t_clrmask; - el->el_tty.t_ex.c_oflag |= el->el_tty.t_t[EX_IO][MD_OUT].t_setmask; - - el->el_tty.t_ex.c_cflag &= ~el->el_tty.t_t[EX_IO][MD_CTL].t_clrmask; - el->el_tty.t_ex.c_cflag |= el->el_tty.t_t[EX_IO][MD_CTL].t_setmask; - - el->el_tty.t_ex.c_lflag &= ~el->el_tty.t_t[EX_IO][MD_LIN].t_clrmask; - el->el_tty.t_ex.c_lflag |= el->el_tty.t_t[EX_IO][MD_LIN].t_setmask; - - /* - * Reset the tty chars to reasonable defaults - * If they are disabled, then enable them. - */ - if (rst) { - if (tty__cooked_mode(&el->el_tty.t_ts)) { - tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]); - /* - * Don't affect CMIN and CTIME for the editor mode - */ - for (rst = 0; rst < C_NCC - 2; rst++) - if (el->el_tty.t_c[TS_IO][rst] != - el->el_tty.t_vdisable - && el->el_tty.t_c[ED_IO][rst] != - el->el_tty.t_vdisable) - el->el_tty.t_c[ED_IO][rst] = - el->el_tty.t_c[TS_IO][rst]; - for (rst = 0; rst < C_NCC; rst++) - if (el->el_tty.t_c[TS_IO][rst] != - el->el_tty.t_vdisable) - el->el_tty.t_c[EX_IO][rst] = - el->el_tty.t_c[TS_IO][rst]; - } - tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]); - if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) { -#ifdef DEBUG_TTY - (void) fprintf(el->el_errfile, - "tty_setup: tty_setty: %s\n", - strerror(errno)); -#endif /* DEBUG_TTY */ - return -1; - } - } - - el->el_tty.t_ed.c_iflag &= ~el->el_tty.t_t[ED_IO][MD_INP].t_clrmask; - el->el_tty.t_ed.c_iflag |= el->el_tty.t_t[ED_IO][MD_INP].t_setmask; - - el->el_tty.t_ed.c_oflag &= ~el->el_tty.t_t[ED_IO][MD_OUT].t_clrmask; - el->el_tty.t_ed.c_oflag |= el->el_tty.t_t[ED_IO][MD_OUT].t_setmask; - - el->el_tty.t_ed.c_cflag &= ~el->el_tty.t_t[ED_IO][MD_CTL].t_clrmask; - el->el_tty.t_ed.c_cflag |= el->el_tty.t_t[ED_IO][MD_CTL].t_setmask; - - el->el_tty.t_ed.c_lflag &= ~el->el_tty.t_t[ED_IO][MD_LIN].t_clrmask; - el->el_tty.t_ed.c_lflag |= el->el_tty.t_t[ED_IO][MD_LIN].t_setmask; - - tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]); - tty_bind_char(el, 1); - return 0; -} - -protected int -tty_init(EditLine *el) -{ - - el->el_tty.t_mode = EX_IO; - el->el_tty.t_vdisable = _POSIX_VDISABLE; - (void) memcpy(el->el_tty.t_t, ttyperm, sizeof(ttyperm_t)); - (void) memcpy(el->el_tty.t_c, ttychar, sizeof(ttychar_t)); - return tty_setup(el); -} - - -/* tty_end(): - * Restore the tty to its original settings - */ -protected void -/*ARGSUSED*/ -tty_end(EditLine *el __attribute__((__unused__))) -{ - - /* XXX: Maybe reset to an initial state? */ -} - - -/* tty__getspeed(): - * Get the tty speed - */ -private speed_t -tty__getspeed(struct termios *td) -{ - speed_t spd; - - if ((spd = cfgetispeed(td)) == 0) - spd = cfgetospeed(td); - return spd; -} - -/* tty__getspeed(): - * Return the index of the asked char in the c_cc array - */ -private int -tty__getcharindex(int i) -{ - switch (i) { -#ifdef VINTR - case C_INTR: - return VINTR; -#endif /* VINTR */ -#ifdef VQUIT - case C_QUIT: - return VQUIT; -#endif /* VQUIT */ -#ifdef VERASE - case C_ERASE: - return VERASE; -#endif /* VERASE */ -#ifdef VKILL - case C_KILL: - return VKILL; -#endif /* VKILL */ -#ifdef VEOF - case C_EOF: - return VEOF; -#endif /* VEOF */ -#ifdef VEOL - case C_EOL: - return VEOL; -#endif /* VEOL */ -#ifdef VEOL2 - case C_EOL2: - return VEOL2; -#endif /* VEOL2 */ -#ifdef VSWTCH - case C_SWTCH: - return VSWTCH; -#endif /* VSWTCH */ -#ifdef VDSWTCH - case C_DSWTCH: - return VDSWTCH; -#endif /* VDSWTCH */ -#ifdef VERASE2 - case C_ERASE2: - return VERASE2; -#endif /* VERASE2 */ -#ifdef VSTART - case C_START: - return VSTART; -#endif /* VSTART */ -#ifdef VSTOP - case C_STOP: - return VSTOP; -#endif /* VSTOP */ -#ifdef VWERASE - case C_WERASE: - return VWERASE; -#endif /* VWERASE */ -#ifdef VSUSP - case C_SUSP: - return VSUSP; -#endif /* VSUSP */ -#ifdef VDSUSP - case C_DSUSP: - return VDSUSP; -#endif /* VDSUSP */ -#ifdef VREPRINT - case C_REPRINT: - return VREPRINT; -#endif /* VREPRINT */ -#ifdef VDISCARD - case C_DISCARD: - return VDISCARD; -#endif /* VDISCARD */ -#ifdef VLNEXT - case C_LNEXT: - return VLNEXT; -#endif /* VLNEXT */ -#ifdef VSTATUS - case C_STATUS: - return VSTATUS; -#endif /* VSTATUS */ -#ifdef VPAGE - case C_PAGE: - return VPAGE; -#endif /* VPAGE */ -#ifdef VPGOFF - case C_PGOFF: - return VPGOFF; -#endif /* VPGOFF */ -#ifdef VKILL2 - case C_KILL2: - return VKILL2; -#endif /* KILL2 */ -#ifdef VMIN - case C_MIN: - return VMIN; -#endif /* VMIN */ -#ifdef VTIME - case C_TIME: - return VTIME; -#endif /* VTIME */ - default: - return -1; - } -} - -/* tty__getchar(): - * Get the tty characters - */ -private void -tty__getchar(struct termios *td, unsigned char *s) -{ - -#ifdef VINTR - s[C_INTR] = td->c_cc[VINTR]; -#endif /* VINTR */ -#ifdef VQUIT - s[C_QUIT] = td->c_cc[VQUIT]; -#endif /* VQUIT */ -#ifdef VERASE - s[C_ERASE] = td->c_cc[VERASE]; -#endif /* VERASE */ -#ifdef VKILL - s[C_KILL] = td->c_cc[VKILL]; -#endif /* VKILL */ -#ifdef VEOF - s[C_EOF] = td->c_cc[VEOF]; -#endif /* VEOF */ -#ifdef VEOL - s[C_EOL] = td->c_cc[VEOL]; -#endif /* VEOL */ -#ifdef VEOL2 - s[C_EOL2] = td->c_cc[VEOL2]; -#endif /* VEOL2 */ -#ifdef VSWTCH - s[C_SWTCH] = td->c_cc[VSWTCH]; -#endif /* VSWTCH */ -#ifdef VDSWTCH - s[C_DSWTCH] = td->c_cc[VDSWTCH]; -#endif /* VDSWTCH */ -#ifdef VERASE2 - s[C_ERASE2] = td->c_cc[VERASE2]; -#endif /* VERASE2 */ -#ifdef VSTART - s[C_START] = td->c_cc[VSTART]; -#endif /* VSTART */ -#ifdef VSTOP - s[C_STOP] = td->c_cc[VSTOP]; -#endif /* VSTOP */ -#ifdef VWERASE - s[C_WERASE] = td->c_cc[VWERASE]; -#endif /* VWERASE */ -#ifdef VSUSP - s[C_SUSP] = td->c_cc[VSUSP]; -#endif /* VSUSP */ -#ifdef VDSUSP - s[C_DSUSP] = td->c_cc[VDSUSP]; -#endif /* VDSUSP */ -#ifdef VREPRINT - s[C_REPRINT] = td->c_cc[VREPRINT]; -#endif /* VREPRINT */ -#ifdef VDISCARD - s[C_DISCARD] = td->c_cc[VDISCARD]; -#endif /* VDISCARD */ -#ifdef VLNEXT - s[C_LNEXT] = td->c_cc[VLNEXT]; -#endif /* VLNEXT */ -#ifdef VSTATUS - s[C_STATUS] = td->c_cc[VSTATUS]; -#endif /* VSTATUS */ -#ifdef VPAGE - s[C_PAGE] = td->c_cc[VPAGE]; -#endif /* VPAGE */ -#ifdef VPGOFF - s[C_PGOFF] = td->c_cc[VPGOFF]; -#endif /* VPGOFF */ -#ifdef VKILL2 - s[C_KILL2] = td->c_cc[VKILL2]; -#endif /* KILL2 */ -#ifdef VMIN - s[C_MIN] = td->c_cc[VMIN]; -#endif /* VMIN */ -#ifdef VTIME - s[C_TIME] = td->c_cc[VTIME]; -#endif /* VTIME */ -} /* tty__getchar */ - - -/* tty__setchar(): - * Set the tty characters - */ -private void -tty__setchar(struct termios *td, unsigned char *s) -{ - -#ifdef VINTR - td->c_cc[VINTR] = s[C_INTR]; -#endif /* VINTR */ -#ifdef VQUIT - td->c_cc[VQUIT] = s[C_QUIT]; -#endif /* VQUIT */ -#ifdef VERASE - td->c_cc[VERASE] = s[C_ERASE]; -#endif /* VERASE */ -#ifdef VKILL - td->c_cc[VKILL] = s[C_KILL]; -#endif /* VKILL */ -#ifdef VEOF - td->c_cc[VEOF] = s[C_EOF]; -#endif /* VEOF */ -#ifdef VEOL - td->c_cc[VEOL] = s[C_EOL]; -#endif /* VEOL */ -#ifdef VEOL2 - td->c_cc[VEOL2] = s[C_EOL2]; -#endif /* VEOL2 */ -#ifdef VSWTCH - td->c_cc[VSWTCH] = s[C_SWTCH]; -#endif /* VSWTCH */ -#ifdef VDSWTCH - td->c_cc[VDSWTCH] = s[C_DSWTCH]; -#endif /* VDSWTCH */ -#ifdef VERASE2 - td->c_cc[VERASE2] = s[C_ERASE2]; -#endif /* VERASE2 */ -#ifdef VSTART - td->c_cc[VSTART] = s[C_START]; -#endif /* VSTART */ -#ifdef VSTOP - td->c_cc[VSTOP] = s[C_STOP]; -#endif /* VSTOP */ -#ifdef VWERASE - td->c_cc[VWERASE] = s[C_WERASE]; -#endif /* VWERASE */ -#ifdef VSUSP - td->c_cc[VSUSP] = s[C_SUSP]; -#endif /* VSUSP */ -#ifdef VDSUSP - td->c_cc[VDSUSP] = s[C_DSUSP]; -#endif /* VDSUSP */ -#ifdef VREPRINT - td->c_cc[VREPRINT] = s[C_REPRINT]; -#endif /* VREPRINT */ -#ifdef VDISCARD - td->c_cc[VDISCARD] = s[C_DISCARD]; -#endif /* VDISCARD */ -#ifdef VLNEXT - td->c_cc[VLNEXT] = s[C_LNEXT]; -#endif /* VLNEXT */ -#ifdef VSTATUS - td->c_cc[VSTATUS] = s[C_STATUS]; -#endif /* VSTATUS */ -#ifdef VPAGE - td->c_cc[VPAGE] = s[C_PAGE]; -#endif /* VPAGE */ -#ifdef VPGOFF - td->c_cc[VPGOFF] = s[C_PGOFF]; -#endif /* VPGOFF */ -#ifdef VKILL2 - td->c_cc[VKILL2] = s[C_KILL2]; -#endif /* VKILL2 */ -#ifdef VMIN - td->c_cc[VMIN] = s[C_MIN]; -#endif /* VMIN */ -#ifdef VTIME - td->c_cc[VTIME] = s[C_TIME]; -#endif /* VTIME */ -} /* tty__setchar */ - - -/* tty_bind_char(): - * Rebind the editline functions - */ -protected void -tty_bind_char(EditLine *el, int force) -{ - - unsigned char *t_n = el->el_tty.t_c[ED_IO]; - unsigned char *t_o = el->el_tty.t_ed.c_cc; - Char new[2], old[2]; - const ttymap_t *tp; - el_action_t *map, *alt; - const el_action_t *dmap, *dalt; - new[1] = old[1] = '\0'; - - map = el->el_map.key; - alt = el->el_map.alt; - if (el->el_map.type == MAP_VI) { - dmap = el->el_map.vii; - dalt = el->el_map.vic; - } else { - dmap = el->el_map.emacs; - dalt = NULL; - } - - for (tp = tty_map; tp->nch != (Int)-1; tp++) { - new[0] = t_n[tp->nch]; - old[0] = t_o[tp->och]; - if (new[0] == old[0] && !force) - continue; - /* Put the old default binding back, and set the new binding */ - keymacro_clear(el, map, old); - map[UC(old[0])] = dmap[UC(old[0])]; - keymacro_clear(el, map, new); - /* MAP_VI == 1, MAP_EMACS == 0... */ - map[UC(new[0])] = tp->bind[el->el_map.type]; - if (dalt) { - keymacro_clear(el, alt, old); - alt[UC(old[0])] = dalt[UC(old[0])]; - keymacro_clear(el, alt, new); - alt[UC(new[0])] = tp->bind[el->el_map.type + 1]; - } - } -} - - -/* tty_rawmode(): - * Set terminal into 1 character at a time mode. - */ -protected int -tty_rawmode(EditLine *el) -{ - - if (el->el_tty.t_mode == ED_IO || el->el_tty.t_mode == QU_IO) - return 0; - - if (el->el_flags & EDIT_DISABLED) - return 0; - - if (tty_getty(el, &el->el_tty.t_ts) == -1) { -#ifdef DEBUG_TTY - (void) fprintf(el->el_errfile, "tty_rawmode: tty_getty: %s\n", - strerror(errno)); -#endif /* DEBUG_TTY */ - return -1; - } - /* - * We always keep up with the eight bit setting and the speed of the - * tty. But we only believe changes that are made to cooked mode! - */ - el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts); - el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts); - - if (tty__getspeed(&el->el_tty.t_ex) != el->el_tty.t_speed || - tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) { - (void) cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed); - (void) cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed); - (void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed); - (void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed); - } - if (tty__cooked_mode(&el->el_tty.t_ts)) { - if (el->el_tty.t_ts.c_cflag != el->el_tty.t_ex.c_cflag) { - el->el_tty.t_ex.c_cflag = - el->el_tty.t_ts.c_cflag; - el->el_tty.t_ex.c_cflag &= - ~el->el_tty.t_t[EX_IO][MD_CTL].t_clrmask; - el->el_tty.t_ex.c_cflag |= - el->el_tty.t_t[EX_IO][MD_CTL].t_setmask; - - el->el_tty.t_ed.c_cflag = - el->el_tty.t_ts.c_cflag; - el->el_tty.t_ed.c_cflag &= - ~el->el_tty.t_t[ED_IO][MD_CTL].t_clrmask; - el->el_tty.t_ed.c_cflag |= - el->el_tty.t_t[ED_IO][MD_CTL].t_setmask; - } - if ((el->el_tty.t_ts.c_lflag != el->el_tty.t_ex.c_lflag) && - (el->el_tty.t_ts.c_lflag != el->el_tty.t_ed.c_lflag)) { - el->el_tty.t_ex.c_lflag = - el->el_tty.t_ts.c_lflag; - el->el_tty.t_ex.c_lflag &= - ~el->el_tty.t_t[EX_IO][MD_LIN].t_clrmask; - el->el_tty.t_ex.c_lflag |= - el->el_tty.t_t[EX_IO][MD_LIN].t_setmask; - - el->el_tty.t_ed.c_lflag = - el->el_tty.t_ts.c_lflag; - el->el_tty.t_ed.c_lflag &= - ~el->el_tty.t_t[ED_IO][MD_LIN].t_clrmask; - el->el_tty.t_ed.c_lflag |= - el->el_tty.t_t[ED_IO][MD_LIN].t_setmask; - } - if ((el->el_tty.t_ts.c_iflag != el->el_tty.t_ex.c_iflag) && - (el->el_tty.t_ts.c_iflag != el->el_tty.t_ed.c_iflag)) { - el->el_tty.t_ex.c_iflag = - el->el_tty.t_ts.c_iflag; - el->el_tty.t_ex.c_iflag &= - ~el->el_tty.t_t[EX_IO][MD_INP].t_clrmask; - el->el_tty.t_ex.c_iflag |= - el->el_tty.t_t[EX_IO][MD_INP].t_setmask; - - el->el_tty.t_ed.c_iflag = - el->el_tty.t_ts.c_iflag; - el->el_tty.t_ed.c_iflag &= - ~el->el_tty.t_t[ED_IO][MD_INP].t_clrmask; - el->el_tty.t_ed.c_iflag |= - el->el_tty.t_t[ED_IO][MD_INP].t_setmask; - } - if ((el->el_tty.t_ts.c_oflag != el->el_tty.t_ex.c_oflag) && - (el->el_tty.t_ts.c_oflag != el->el_tty.t_ed.c_oflag)) { - el->el_tty.t_ex.c_oflag = - el->el_tty.t_ts.c_oflag; - el->el_tty.t_ex.c_oflag &= - ~el->el_tty.t_t[EX_IO][MD_OUT].t_clrmask; - el->el_tty.t_ex.c_oflag |= - el->el_tty.t_t[EX_IO][MD_OUT].t_setmask; - - el->el_tty.t_ed.c_oflag = - el->el_tty.t_ts.c_oflag; - el->el_tty.t_ed.c_oflag &= - ~el->el_tty.t_t[ED_IO][MD_OUT].t_clrmask; - el->el_tty.t_ed.c_oflag |= - el->el_tty.t_t[ED_IO][MD_OUT].t_setmask; - } - if (tty__gettabs(&el->el_tty.t_ex) == 0) - el->el_tty.t_tabs = 0; - else - el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0; - - { - int i; - - tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]); - /* - * Check if the user made any changes. - * If he did, then propagate the changes to the - * edit and execute data structures. - */ - for (i = 0; i < C_NCC; i++) - if (el->el_tty.t_c[TS_IO][i] != - el->el_tty.t_c[EX_IO][i]) - break; - - if (i != C_NCC) { - /* - * Propagate changes only to the unprotected - * chars that have been modified just now. - */ - for (i = 0; i < C_NCC; i++) { - if (!((el->el_tty.t_t[ED_IO][MD_CHAR].t_setmask & C_SH(i))) - && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i])) - el->el_tty.t_c[ED_IO][i] = el->el_tty.t_c[TS_IO][i]; - if (el->el_tty.t_t[ED_IO][MD_CHAR].t_clrmask & C_SH(i)) - el->el_tty.t_c[ED_IO][i] = el->el_tty.t_vdisable; - } - tty_bind_char(el, 0); - tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]); - - for (i = 0; i < C_NCC; i++) { - if (!((el->el_tty.t_t[EX_IO][MD_CHAR].t_setmask & C_SH(i))) - && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i])) - el->el_tty.t_c[EX_IO][i] = el->el_tty.t_c[TS_IO][i]; - if (el->el_tty.t_t[EX_IO][MD_CHAR].t_clrmask & C_SH(i)) - el->el_tty.t_c[EX_IO][i] = el->el_tty.t_vdisable; - } - tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]); - } - } - } - if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) { -#ifdef DEBUG_TTY - (void) fprintf(el->el_errfile, "tty_rawmode: tty_setty: %s\n", - strerror(errno)); -#endif /* DEBUG_TTY */ - return -1; - } - el->el_tty.t_mode = ED_IO; - return 0; -} - - -/* tty_cookedmode(): - * Set the tty back to normal mode - */ -protected int -tty_cookedmode(EditLine *el) -{ /* set tty in normal setup */ - - if (el->el_tty.t_mode == EX_IO) - return 0; - - if (el->el_flags & EDIT_DISABLED) - return 0; - - if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) { -#ifdef DEBUG_TTY - (void) fprintf(el->el_errfile, - "tty_cookedmode: tty_setty: %s\n", - strerror(errno)); -#endif /* DEBUG_TTY */ - return -1; - } - el->el_tty.t_mode = EX_IO; - return 0; -} - - -/* tty_quotemode(): - * Turn on quote mode - */ -protected int -tty_quotemode(EditLine *el) -{ - if (el->el_tty.t_mode == QU_IO) - return 0; - - el->el_tty.t_qu = el->el_tty.t_ed; - - el->el_tty.t_qu.c_iflag &= ~el->el_tty.t_t[QU_IO][MD_INP].t_clrmask; - el->el_tty.t_qu.c_iflag |= el->el_tty.t_t[QU_IO][MD_INP].t_setmask; - - el->el_tty.t_qu.c_oflag &= ~el->el_tty.t_t[QU_IO][MD_OUT].t_clrmask; - el->el_tty.t_qu.c_oflag |= el->el_tty.t_t[QU_IO][MD_OUT].t_setmask; - - el->el_tty.t_qu.c_cflag &= ~el->el_tty.t_t[QU_IO][MD_CTL].t_clrmask; - el->el_tty.t_qu.c_cflag |= el->el_tty.t_t[QU_IO][MD_CTL].t_setmask; - - el->el_tty.t_qu.c_lflag &= ~el->el_tty.t_t[QU_IO][MD_LIN].t_clrmask; - el->el_tty.t_qu.c_lflag |= el->el_tty.t_t[QU_IO][MD_LIN].t_setmask; - - if (tty_setty(el, TCSADRAIN, &el->el_tty.t_qu) == -1) { -#ifdef DEBUG_TTY - (void) fprintf(el->el_errfile, "QuoteModeOn: tty_setty: %s\n", - strerror(errno)); -#endif /* DEBUG_TTY */ - return -1; - } - el->el_tty.t_mode = QU_IO; - return 0; -} - - -/* tty_noquotemode(): - * Turn off quote mode - */ -protected int -tty_noquotemode(EditLine *el) -{ - - if (el->el_tty.t_mode != QU_IO) - return 0; - if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) { -#ifdef DEBUG_TTY - (void) fprintf(el->el_errfile, "QuoteModeOff: tty_setty: %s\n", - strerror(errno)); -#endif /* DEBUG_TTY */ - return -1; - } - el->el_tty.t_mode = ED_IO; - return 0; -} - - -/* tty_stty(): - * Stty builtin - */ -protected int -/*ARGSUSED*/ -tty_stty(EditLine *el, int argc __attribute__((__unused__)), const Char **argv) -{ - const ttymodes_t *m; - char x; - int aflag = 0; - const Char *s, *d; - char name[EL_BUFSIZ]; - struct termios *tios = &el->el_tty.t_ex; - int z = EX_IO; - - if (argv == NULL) - return -1; - strncpy(name, ct_encode_string(*argv++, &el->el_scratch), sizeof(name)); - name[sizeof(name) - 1] = '\0'; - - while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0') - switch (argv[0][1]) { - case 'a': - aflag++; - argv++; - break; - case 'd': - argv++; - tios = &el->el_tty.t_ed; - z = ED_IO; - break; - case 'x': - argv++; - tios = &el->el_tty.t_ex; - z = EX_IO; - break; - case 'q': - argv++; - tios = &el->el_tty.t_ts; - z = QU_IO; - break; - default: - (void) fprintf(el->el_errfile, - "%s: Unknown switch `%c'.\n", - name, (int) argv[0][1]); - return -1; - } - - if (!argv || !*argv) { - int i = -1; - size_t len = 0, st = 0, cu; - for (m = ttymodes; m->m_name; m++) { - if (m->m_type != i) { - (void) fprintf(el->el_outfile, "%s%s", - i != -1 ? "\n" : "", - el->el_tty.t_t[z][m->m_type].t_name); - i = m->m_type; - st = len = - strlen(el->el_tty.t_t[z][m->m_type].t_name); - } - if (i != -1) { - x = (el->el_tty.t_t[z][i].t_setmask & m->m_value) - ? '+' : '\0'; - - if (el->el_tty.t_t[z][i].t_clrmask & m->m_value) - x = '-'; - } else { - x = '\0'; - } - - if (x != '\0' || aflag) { - - cu = strlen(m->m_name) + (x != '\0') + 1; - - if (len + cu >= (size_t)el->el_terminal.t_size.h) { - (void) fprintf(el->el_outfile, "\n%*s", - (int)st, ""); - len = st + cu; - } else - len += cu; - - if (x != '\0') - (void) fprintf(el->el_outfile, "%c%s ", - x, m->m_name); - else - (void) fprintf(el->el_outfile, "%s ", - m->m_name); - } - } - (void) fprintf(el->el_outfile, "\n"); - return 0; - } - while (argv && (s = *argv++)) { - const Char *p; - switch (*s) { - case '+': - case '-': - x = (char)*s++; - break; - default: - x = '\0'; - break; - } - d = s; - p = Strchr(s, '='); - for (m = ttymodes; m->m_name; m++) - if ((p ? strncmp(m->m_name, ct_encode_string(d, &el->el_scratch), (size_t)(p - d)) : - strcmp(m->m_name, ct_encode_string(d, &el->el_scratch))) == 0 && - (p == NULL || m->m_type == MD_CHAR)) - break; - - if (!m->m_name) { - (void) fprintf(el->el_errfile, - "%s: Invalid argument `" FSTR "'.\n", name, d); - return -1; - } - if (p) { - int c = ffs((int)m->m_value); - int v = *++p ? parse__escape(&p) : - el->el_tty.t_vdisable; - assert(c != 0); - c--; - c = tty__getcharindex(c); - assert(c != -1); - tios->c_cc[c] = (cc_t)v; - continue; - } - switch (x) { - case '+': - el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value; - el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value; - break; - case '-': - el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value; - el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value; - break; - default: - el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value; - el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value; - break; - } - } - - if (el->el_tty.t_mode == z) { - if (tty_setty(el, TCSADRAIN, tios) == -1) { -#ifdef DEBUG_TTY - (void) fprintf(el->el_errfile, - "tty_stty: tty_setty: %s\n", strerror(errno)); -#endif /* DEBUG_TTY */ - return -1; - } - } - - return 0; -} - - -#ifdef notyet -/* tty_printchar(): - * DEbugging routine to print the tty characters - */ -private void -tty_printchar(EditLine *el, unsigned char *s) -{ - ttyperm_t *m; - int i; - - for (i = 0; i < C_NCC; i++) { - for (m = el->el_tty.t_t; m->m_name; m++) - if (m->m_type == MD_CHAR && C_SH(i) == m->m_value) - break; - if (m->m_name) - (void) fprintf(el->el_errfile, "%s ^%c ", - m->m_name, s[i] + 'A' - 1); - if (i % 5 == 0) - (void) fprintf(el->el_errfile, "\n"); - } - (void) fprintf(el->el_errfile, "\n"); -} -#endif /* notyet */ diff --git a/cmd-line-utils/libedit/tty.h b/cmd-line-utils/libedit/tty.h deleted file mode 100644 index 04485eb83ad..00000000000 --- a/cmd-line-utils/libedit/tty.h +++ /dev/null @@ -1,481 +0,0 @@ -/* $NetBSD: tty.h,v 1.13 2011/08/16 16:25:15 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)tty.h 8.1 (Berkeley) 6/4/93 - */ - -/* - * el.tty.h: Local terminal header - */ -#ifndef _h_el_tty -#define _h_el_tty - -#include "sys.h" -#include "histedit.h" -#include -#include - -/* Define our own since everyone gets it wrong! */ -#define CONTROL(A) ((A) & 037) - -/* - * Aix compatible names - */ -# if defined(VWERSE) && !defined(VWERASE) -# define VWERASE VWERSE -# endif /* VWERSE && !VWERASE */ - -# if defined(VDISCRD) && !defined(VDISCARD) -# define VDISCARD VDISCRD -# endif /* VDISCRD && !VDISCARD */ - -# if defined(VFLUSHO) && !defined(VDISCARD) -# define VDISCARD VFLUSHO -# endif /* VFLUSHO && VDISCARD */ - -# if defined(VSTRT) && !defined(VSTART) -# define VSTART VSTRT -# endif /* VSTRT && ! VSTART */ - -# if defined(VSTAT) && !defined(VSTATUS) -# define VSTATUS VSTAT -# endif /* VSTAT && ! VSTATUS */ - -# ifndef ONLRET -# define ONLRET 0 -# endif /* ONLRET */ - -# ifndef TAB3 -# ifdef OXTABS -# define TAB3 OXTABS -# else -# define TAB3 0 -# endif /* OXTABS */ -# endif /* !TAB3 */ - -# if defined(OXTABS) && !defined(XTABS) -# define XTABS OXTABS -# endif /* OXTABS && !XTABS */ - -# ifndef ONLCR -# define ONLCR 0 -# endif /* ONLCR */ - -# ifndef IEXTEN -# define IEXTEN 0 -# endif /* IEXTEN */ - -# ifndef ECHOCTL -# define ECHOCTL 0 -# endif /* ECHOCTL */ - -# ifndef PARENB -# define PARENB 0 -# endif /* PARENB */ - -# ifndef EXTPROC -# define EXTPROC 0 -# endif /* EXTPROC */ - -# ifndef FLUSHO -# define FLUSHO 0 -# endif /* FLUSHO */ - - -# if defined(VDISABLE) && !defined(_POSIX_VDISABLE) -# define _POSIX_VDISABLE VDISABLE -# endif /* VDISABLE && ! _POSIX_VDISABLE */ - -/* - * Work around ISC's definition of IEXTEN which is - * XCASE! - */ -# ifdef ISC -# if defined(IEXTEN) && defined(XCASE) -# if IEXTEN == XCASE -# undef IEXTEN -# define IEXTEN 0 -# endif /* IEXTEN == XCASE */ -# endif /* IEXTEN && XCASE */ -# if defined(IEXTEN) && !defined(XCASE) -# define XCASE IEXTEN -# undef IEXTEN -# define IEXTEN 0 -# endif /* IEXTEN && !XCASE */ -# endif /* ISC */ - -/* - * Work around convex weirdness where turning off IEXTEN makes us - * lose all postprocessing! - */ -#if defined(convex) || defined(__convex__) -# if defined(IEXTEN) && IEXTEN != 0 -# undef IEXTEN -# define IEXTEN 0 -# endif /* IEXTEN != 0 */ -#endif /* convex || __convex__ */ - -/* - * So that we don't lose job control. - */ -#ifdef __SVR4 -# undef CSWTCH -#endif - -#ifndef _POSIX_VDISABLE -# define _POSIX_VDISABLE ((unsigned char) -1) -#endif /* _POSIX_VDISABLE */ - -#if !defined(CREPRINT) && defined(CRPRNT) -# define CREPRINT CRPRNT -#endif /* !CREPRINT && CRPRNT */ -#if !defined(CDISCARD) && defined(CFLUSH) -# define CDISCARD CFLUSH -#endif /* !CDISCARD && CFLUSH */ - -#ifndef CINTR -# define CINTR CONTROL('c') -#endif /* CINTR */ -#ifndef CQUIT -# define CQUIT 034 /* ^\ */ -#endif /* CQUIT */ -#ifndef CERASE -# define CERASE 0177 /* ^? */ -#endif /* CERASE */ -#ifndef CKILL -# define CKILL CONTROL('u') -#endif /* CKILL */ -#ifndef CEOF -# define CEOF CONTROL('d') -#endif /* CEOF */ -#ifndef CEOL -# define CEOL _POSIX_VDISABLE -#endif /* CEOL */ -#ifndef CEOL2 -# define CEOL2 _POSIX_VDISABLE -#endif /* CEOL2 */ -#ifndef CSWTCH -# define CSWTCH _POSIX_VDISABLE -#endif /* CSWTCH */ -#ifndef CDSWTCH -# define CDSWTCH _POSIX_VDISABLE -#endif /* CDSWTCH */ -#ifndef CERASE2 -# define CERASE2 _POSIX_VDISABLE -#endif /* CERASE2 */ -#ifndef CSTART -# define CSTART CONTROL('q') -#endif /* CSTART */ -#ifndef CSTOP -# define CSTOP CONTROL('s') -#endif /* CSTOP */ -#ifndef CSUSP -# define CSUSP CONTROL('z') -#endif /* CSUSP */ -#ifndef CDSUSP -# define CDSUSP CONTROL('y') -#endif /* CDSUSP */ - -#ifdef hpux - -# ifndef CREPRINT -# define CREPRINT _POSIX_VDISABLE -# endif /* CREPRINT */ -# ifndef CDISCARD -# define CDISCARD _POSIX_VDISABLE -# endif /* CDISCARD */ -# ifndef CLNEXT -# define CLNEXT _POSIX_VDISABLE -# endif /* CLNEXT */ -# ifndef CWERASE -# define CWERASE _POSIX_VDISABLE -# endif /* CWERASE */ - -#else /* !hpux */ - -# ifndef CREPRINT -# define CREPRINT CONTROL('r') -# endif /* CREPRINT */ -# ifndef CDISCARD -# define CDISCARD CONTROL('o') -# endif /* CDISCARD */ -# ifndef CLNEXT -# define CLNEXT CONTROL('v') -# endif /* CLNEXT */ -# ifndef CWERASE -# define CWERASE CONTROL('w') -# endif /* CWERASE */ - -#endif /* hpux */ - -#ifndef CSTATUS -# define CSTATUS CONTROL('t') -#endif /* CSTATUS */ -#ifndef CPAGE -# define CPAGE ' ' -#endif /* CPAGE */ -#ifndef CPGOFF -# define CPGOFF CONTROL('m') -#endif /* CPGOFF */ -#ifndef CKILL2 -# define CKILL2 _POSIX_VDISABLE -#endif /* CKILL2 */ -#ifndef CBRK -# ifndef masscomp -# define CBRK 0377 -# else -# define CBRK '\0' -# endif /* masscomp */ -#endif /* CBRK */ -#ifndef CMIN -# define CMIN CEOF -#endif /* CMIN */ -#ifndef CTIME -# define CTIME CEOL -#endif /* CTIME */ - -/* - * Fix for sun inconsistency. On termio VSUSP and the rest of the - * ttychars > NCC are defined. So we undefine them. - */ -#if defined(TERMIO) || defined(POSIX) -# if defined(POSIX) && defined(NCCS) -# define NUMCC NCCS -# else -# ifdef NCC -# define NUMCC NCC -# endif /* NCC */ -# endif /* POSIX && NCCS */ -# ifdef NUMCC -# ifdef VINTR -# if NUMCC <= VINTR -# undef VINTR -# endif /* NUMCC <= VINTR */ -# endif /* VINTR */ -# ifdef VQUIT -# if NUMCC <= VQUIT -# undef VQUIT -# endif /* NUMCC <= VQUIT */ -# endif /* VQUIT */ -# ifdef VERASE -# if NUMCC <= VERASE -# undef VERASE -# endif /* NUMCC <= VERASE */ -# endif /* VERASE */ -# ifdef VKILL -# if NUMCC <= VKILL -# undef VKILL -# endif /* NUMCC <= VKILL */ -# endif /* VKILL */ -# ifdef VEOF -# if NUMCC <= VEOF -# undef VEOF -# endif /* NUMCC <= VEOF */ -# endif /* VEOF */ -# ifdef VEOL -# if NUMCC <= VEOL -# undef VEOL -# endif /* NUMCC <= VEOL */ -# endif /* VEOL */ -# ifdef VEOL2 -# if NUMCC <= VEOL2 -# undef VEOL2 -# endif /* NUMCC <= VEOL2 */ -# endif /* VEOL2 */ -# ifdef VSWTCH -# if NUMCC <= VSWTCH -# undef VSWTCH -# endif /* NUMCC <= VSWTCH */ -# endif /* VSWTCH */ -# ifdef VDSWTCH -# if NUMCC <= VDSWTCH -# undef VDSWTCH -# endif /* NUMCC <= VDSWTCH */ -# endif /* VDSWTCH */ -# ifdef VERASE2 -# if NUMCC <= VERASE2 -# undef VERASE2 -# endif /* NUMCC <= VERASE2 */ -# endif /* VERASE2 */ -# ifdef VSTART -# if NUMCC <= VSTART -# undef VSTART -# endif /* NUMCC <= VSTART */ -# endif /* VSTART */ -# ifdef VSTOP -# if NUMCC <= VSTOP -# undef VSTOP -# endif /* NUMCC <= VSTOP */ -# endif /* VSTOP */ -# ifdef VWERASE -# if NUMCC <= VWERASE -# undef VWERASE -# endif /* NUMCC <= VWERASE */ -# endif /* VWERASE */ -# ifdef VSUSP -# if NUMCC <= VSUSP -# undef VSUSP -# endif /* NUMCC <= VSUSP */ -# endif /* VSUSP */ -# ifdef VDSUSP -# if NUMCC <= VDSUSP -# undef VDSUSP -# endif /* NUMCC <= VDSUSP */ -# endif /* VDSUSP */ -# ifdef VREPRINT -# if NUMCC <= VREPRINT -# undef VREPRINT -# endif /* NUMCC <= VREPRINT */ -# endif /* VREPRINT */ -# ifdef VDISCARD -# if NUMCC <= VDISCARD -# undef VDISCARD -# endif /* NUMCC <= VDISCARD */ -# endif /* VDISCARD */ -# ifdef VLNEXT -# if NUMCC <= VLNEXT -# undef VLNEXT -# endif /* NUMCC <= VLNEXT */ -# endif /* VLNEXT */ -# ifdef VSTATUS -# if NUMCC <= VSTATUS -# undef VSTATUS -# endif /* NUMCC <= VSTATUS */ -# endif /* VSTATUS */ -# ifdef VPAGE -# if NUMCC <= VPAGE -# undef VPAGE -# endif /* NUMCC <= VPAGE */ -# endif /* VPAGE */ -# ifdef VPGOFF -# if NUMCC <= VPGOFF -# undef VPGOFF -# endif /* NUMCC <= VPGOFF */ -# endif /* VPGOFF */ -# ifdef VKILL2 -# if NUMCC <= VKILL2 -# undef VKILL2 -# endif /* NUMCC <= VKILL2 */ -# endif /* VKILL2 */ -# ifdef VBRK -# if NUMCC <= VBRK -# undef VBRK -# endif /* NUMCC <= VBRK */ -# endif /* VBRK */ -# ifdef VMIN -# if NUMCC <= VMIN -# undef VMIN -# endif /* NUMCC <= VMIN */ -# endif /* VMIN */ -# ifdef VTIME -# if NUMCC <= VTIME -# undef VTIME -# endif /* NUMCC <= VTIME */ -# endif /* VTIME */ -# endif /* NUMCC */ -#endif /* !POSIX */ - -#define C_INTR 0 -#define C_QUIT 1 -#define C_ERASE 2 -#define C_KILL 3 -#define C_EOF 4 -#define C_EOL 5 -#define C_EOL2 6 -#define C_SWTCH 7 -#define C_DSWTCH 8 -#define C_ERASE2 9 -#define C_START 10 -#define C_STOP 11 -#define C_WERASE 12 -#define C_SUSP 13 -#define C_DSUSP 14 -#define C_REPRINT 15 -#define C_DISCARD 16 -#define C_LNEXT 17 -#define C_STATUS 18 -#define C_PAGE 19 -#define C_PGOFF 20 -#define C_KILL2 21 -#define C_BRK 22 -#define C_MIN 23 -#define C_TIME 24 -#define C_NCC 25 -#define C_SH(A) ((unsigned int)(1 << (A))) - -/* - * Terminal dependend data structures - */ -#define EX_IO 0 /* while we are executing */ -#define ED_IO 1 /* while we are editing */ -#define TS_IO 2 /* new mode from terminal */ -#define QU_IO 2 /* used only for quoted chars */ -#define NN_IO 3 /* The number of entries */ - -#define MD_INP 0 -#define MD_OUT 1 -#define MD_CTL 2 -#define MD_LIN 3 -#define MD_CHAR 4 -#define MD_NN 5 - -typedef struct { - const char *t_name; - unsigned int t_setmask; - unsigned int t_clrmask; -} ttyperm_t[NN_IO][MD_NN]; - -typedef unsigned char ttychar_t[NN_IO][C_NCC]; - -protected int tty_init(EditLine *); -protected void tty_end(EditLine *); -protected int tty_stty(EditLine *, int, const Char **); -protected int tty_rawmode(EditLine *); -protected int tty_cookedmode(EditLine *); -protected int tty_quotemode(EditLine *); -protected int tty_noquotemode(EditLine *); -protected void tty_bind_char(EditLine *, int); - -typedef struct { - ttyperm_t t_t; - ttychar_t t_c; - struct termios t_ex, t_ed, t_ts; - int t_tabs; - int t_eight; - speed_t t_speed; - int t_mode; - unsigned char t_vdisable; -} el_tty_t; - - -#endif /* _h_el_tty */ diff --git a/cmd-line-utils/libedit/vi.c b/cmd-line-utils/libedit/vi.c deleted file mode 100644 index 9a4b97a977e..00000000000 --- a/cmd-line-utils/libedit/vi.c +++ /dev/null @@ -1,1173 +0,0 @@ -/* $NetBSD: vi.c,v 1.41 2011/10/04 15:27:04 christos Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#include -#include -#include -#include - -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)vi.c 8.1 (Berkeley) 6/4/93"; -#else -#endif -#endif /* not lint && not SCCSID */ - -/* - * vi.c: Vi mode commands. - */ -#include "el.h" - -private el_action_t cv_action(EditLine *, Int); -private el_action_t cv_paste(EditLine *, Int); - -/* cv_action(): - * Handle vi actions. - */ -private el_action_t -cv_action(EditLine *el, Int c) -{ - - if (el->el_chared.c_vcmd.action != NOP) { - /* 'cc', 'dd' and (possibly) friends */ - if (c != (Int)el->el_chared.c_vcmd.action) - return CC_ERROR; - - if (!(c & YANK)) - cv_undo(el); - cv_yank(el, el->el_line.buffer, - (int)(el->el_line.lastchar - el->el_line.buffer)); - el->el_chared.c_vcmd.action = NOP; - el->el_chared.c_vcmd.pos = 0; - if (!(c & YANK)) { - el->el_line.lastchar = el->el_line.buffer; - el->el_line.cursor = el->el_line.buffer; - } - if (c & INSERT) - el->el_map.current = el->el_map.key; - - return CC_REFRESH; - } - el->el_chared.c_vcmd.pos = el->el_line.cursor; - el->el_chared.c_vcmd.action = c; - return CC_ARGHACK; -} - -/* cv_paste(): - * Paste previous deletion before or after the cursor - */ -private el_action_t -cv_paste(EditLine *el, Int c) -{ - c_kill_t *k = &el->el_chared.c_kill; - size_t len = (size_t)(k->last - k->buf); - - if (k->buf == NULL || len == 0) - return CC_ERROR; -#ifdef DEBUG_PASTE - (void) fprintf(el->el_errfile, "Paste: \"%.*s\"\n", (int)len, k->buf); -#endif - - cv_undo(el); - - if (!c && el->el_line.cursor < el->el_line.lastchar) - el->el_line.cursor++; - - c_insert(el, (int)len); - if (el->el_line.cursor + len > el->el_line.lastchar) - return CC_ERROR; - (void) memcpy(el->el_line.cursor, k->buf, len * - sizeof(*el->el_line.cursor)); - - return CC_REFRESH; -} - - -/* vi_paste_next(): - * Vi paste previous deletion to the right of the cursor - * [p] - */ -protected el_action_t -/*ARGSUSED*/ -vi_paste_next(EditLine *el, Int c __attribute__((__unused__))) -{ - - return cv_paste(el, 0); -} - - -/* vi_paste_prev(): - * Vi paste previous deletion to the left of the cursor - * [P] - */ -protected el_action_t -/*ARGSUSED*/ -vi_paste_prev(EditLine *el, Int c __attribute__((__unused__))) -{ - - return cv_paste(el, 1); -} - - -/* vi_prev_big_word(): - * Vi move to the previous space delimited word - * [B] - */ -protected el_action_t -/*ARGSUSED*/ -vi_prev_big_word(EditLine *el, Int c __attribute__((__unused__))) -{ - - if (el->el_line.cursor == el->el_line.buffer) - return CC_ERROR; - - el->el_line.cursor = cv_prev_word(el->el_line.cursor, - el->el_line.buffer, - el->el_state.argument, - cv__isWord); - - if (el->el_chared.c_vcmd.action != NOP) { - cv_delfini(el); - return CC_REFRESH; - } - return CC_CURSOR; -} - - -/* vi_prev_word(): - * Vi move to the previous word - * [b] - */ -protected el_action_t -/*ARGSUSED*/ -vi_prev_word(EditLine *el, Int c __attribute__((__unused__))) -{ - - if (el->el_line.cursor == el->el_line.buffer) - return CC_ERROR; - - el->el_line.cursor = cv_prev_word(el->el_line.cursor, - el->el_line.buffer, - el->el_state.argument, - cv__isword); - - if (el->el_chared.c_vcmd.action != NOP) { - cv_delfini(el); - return CC_REFRESH; - } - return CC_CURSOR; -} - - -/* vi_next_big_word(): - * Vi move to the next space delimited word - * [W] - */ -protected el_action_t -/*ARGSUSED*/ -vi_next_big_word(EditLine *el, Int c __attribute__((__unused__))) -{ - - if (el->el_line.cursor >= el->el_line.lastchar - 1) - return CC_ERROR; - - el->el_line.cursor = cv_next_word(el, el->el_line.cursor, - el->el_line.lastchar, el->el_state.argument, cv__isWord); - - if (el->el_map.type == MAP_VI) - if (el->el_chared.c_vcmd.action != NOP) { - cv_delfini(el); - return CC_REFRESH; - } - return CC_CURSOR; -} - - -/* vi_next_word(): - * Vi move to the next word - * [w] - */ -protected el_action_t -/*ARGSUSED*/ -vi_next_word(EditLine *el, Int c __attribute__((__unused__))) -{ - - if (el->el_line.cursor >= el->el_line.lastchar - 1) - return CC_ERROR; - - el->el_line.cursor = cv_next_word(el, el->el_line.cursor, - el->el_line.lastchar, el->el_state.argument, cv__isword); - - if (el->el_map.type == MAP_VI) - if (el->el_chared.c_vcmd.action != NOP) { - cv_delfini(el); - return CC_REFRESH; - } - return CC_CURSOR; -} - - -/* vi_change_case(): - * Vi change case of character under the cursor and advance one character - * [~] - */ -protected el_action_t -vi_change_case(EditLine *el, Int c) -{ - int i; - - if (el->el_line.cursor >= el->el_line.lastchar) - return CC_ERROR; - cv_undo(el); - for (i = 0; i < el->el_state.argument; i++) { - - c = *el->el_line.cursor; - if (Isupper(c)) - *el->el_line.cursor = Tolower(c); - else if (Islower(c)) - *el->el_line.cursor = Toupper(c); - - if (++el->el_line.cursor >= el->el_line.lastchar) { - el->el_line.cursor--; - re_fastaddc(el); - break; - } - re_fastaddc(el); - } - return CC_NORM; -} - - -/* vi_change_meta(): - * Vi change prefix command - * [c] - */ -protected el_action_t -/*ARGSUSED*/ -vi_change_meta(EditLine *el, Int c __attribute__((__unused__))) -{ - - /* - * Delete with insert == change: first we delete and then we leave in - * insert mode. - */ - return cv_action(el, DELETE | INSERT); -} - - -/* vi_insert_at_bol(): - * Vi enter insert mode at the beginning of line - * [I] - */ -protected el_action_t -/*ARGSUSED*/ -vi_insert_at_bol(EditLine *el, Int c __attribute__((__unused__))) -{ - - el->el_line.cursor = el->el_line.buffer; - cv_undo(el); - el->el_map.current = el->el_map.key; - return CC_CURSOR; -} - - -/* vi_replace_char(): - * Vi replace character under the cursor with the next character typed - * [r] - */ -protected el_action_t -/*ARGSUSED*/ -vi_replace_char(EditLine *el, Int c __attribute__((__unused__))) -{ - - if (el->el_line.cursor >= el->el_line.lastchar) - return CC_ERROR; - - el->el_map.current = el->el_map.key; - el->el_state.inputmode = MODE_REPLACE_1; - cv_undo(el); - return CC_ARGHACK; -} - - -/* vi_replace_mode(): - * Vi enter replace mode - * [R] - */ -protected el_action_t -/*ARGSUSED*/ -vi_replace_mode(EditLine *el, Int c __attribute__((__unused__))) -{ - - el->el_map.current = el->el_map.key; - el->el_state.inputmode = MODE_REPLACE; - cv_undo(el); - return CC_NORM; -} - - -/* vi_substitute_char(): - * Vi replace character under the cursor and enter insert mode - * [s] - */ -protected el_action_t -/*ARGSUSED*/ -vi_substitute_char(EditLine *el, Int c __attribute__((__unused__))) -{ - - c_delafter(el, el->el_state.argument); - el->el_map.current = el->el_map.key; - return CC_REFRESH; -} - - -/* vi_substitute_line(): - * Vi substitute entire line - * [S] - */ -protected el_action_t -/*ARGSUSED*/ -vi_substitute_line(EditLine *el, Int c __attribute__((__unused__))) -{ - - cv_undo(el); - cv_yank(el, el->el_line.buffer, - (int)(el->el_line.lastchar - el->el_line.buffer)); - (void) em_kill_line(el, 0); - el->el_map.current = el->el_map.key; - return CC_REFRESH; -} - - -/* vi_change_to_eol(): - * Vi change to end of line - * [C] - */ -protected el_action_t -/*ARGSUSED*/ -vi_change_to_eol(EditLine *el, Int c __attribute__((__unused__))) -{ - - cv_undo(el); - cv_yank(el, el->el_line.cursor, - (int)(el->el_line.lastchar - el->el_line.cursor)); - (void) ed_kill_line(el, 0); - el->el_map.current = el->el_map.key; - return CC_REFRESH; -} - - -/* vi_insert(): - * Vi enter insert mode - * [i] - */ -protected el_action_t -/*ARGSUSED*/ -vi_insert(EditLine *el, Int c __attribute__((__unused__))) -{ - - el->el_map.current = el->el_map.key; - cv_undo(el); - return CC_NORM; -} - - -/* vi_add(): - * Vi enter insert mode after the cursor - * [a] - */ -protected el_action_t -/*ARGSUSED*/ -vi_add(EditLine *el, Int c __attribute__((__unused__))) -{ - int ret; - - el->el_map.current = el->el_map.key; - if (el->el_line.cursor < el->el_line.lastchar) { - el->el_line.cursor++; - if (el->el_line.cursor > el->el_line.lastchar) - el->el_line.cursor = el->el_line.lastchar; - ret = CC_CURSOR; - } else - ret = CC_NORM; - - cv_undo(el); - - return (el_action_t)ret; -} - - -/* vi_add_at_eol(): - * Vi enter insert mode at end of line - * [A] - */ -protected el_action_t -/*ARGSUSED*/ -vi_add_at_eol(EditLine *el, Int c __attribute__((__unused__))) -{ - - el->el_map.current = el->el_map.key; - el->el_line.cursor = el->el_line.lastchar; - cv_undo(el); - return CC_CURSOR; -} - - -/* vi_delete_meta(): - * Vi delete prefix command - * [d] - */ -protected el_action_t -/*ARGSUSED*/ -vi_delete_meta(EditLine *el, Int c __attribute__((__unused__))) -{ - - return cv_action(el, DELETE); -} - - -/* vi_end_big_word(): - * Vi move to the end of the current space delimited word - * [E] - */ -protected el_action_t -/*ARGSUSED*/ -vi_end_big_word(EditLine *el, Int c __attribute__((__unused__))) -{ - - if (el->el_line.cursor == el->el_line.lastchar) - return CC_ERROR; - - el->el_line.cursor = cv__endword(el->el_line.cursor, - el->el_line.lastchar, el->el_state.argument, cv__isWord); - - if (el->el_chared.c_vcmd.action != NOP) { - el->el_line.cursor++; - cv_delfini(el); - return CC_REFRESH; - } - return CC_CURSOR; -} - - -/* vi_end_word(): - * Vi move to the end of the current word - * [e] - */ -protected el_action_t -/*ARGSUSED*/ -vi_end_word(EditLine *el, Int c __attribute__((__unused__))) -{ - - if (el->el_line.cursor == el->el_line.lastchar) - return CC_ERROR; - - el->el_line.cursor = cv__endword(el->el_line.cursor, - el->el_line.lastchar, el->el_state.argument, cv__isword); - - if (el->el_chared.c_vcmd.action != NOP) { - el->el_line.cursor++; - cv_delfini(el); - return CC_REFRESH; - } - return CC_CURSOR; -} - - -/* vi_undo(): - * Vi undo last change - * [u] - */ -protected el_action_t -/*ARGSUSED*/ -vi_undo(EditLine *el, Int c __attribute__((__unused__))) -{ - c_undo_t un = el->el_chared.c_undo; - - if (un.len == -1) - return CC_ERROR; - - /* switch line buffer and undo buffer */ - el->el_chared.c_undo.buf = el->el_line.buffer; - el->el_chared.c_undo.len = el->el_line.lastchar - el->el_line.buffer; - el->el_chared.c_undo.cursor = - (int)(el->el_line.cursor - el->el_line.buffer); - el->el_line.limit = un.buf + (el->el_line.limit - el->el_line.buffer); - el->el_line.buffer = un.buf; - el->el_line.cursor = un.buf + un.cursor; - el->el_line.lastchar = un.buf + un.len; - - return CC_REFRESH; -} - - -/* vi_command_mode(): - * Vi enter command mode (use alternative key bindings) - * [] - */ -protected el_action_t -/*ARGSUSED*/ -vi_command_mode(EditLine *el, Int c __attribute__((__unused__))) -{ - - /* [Esc] cancels pending action */ - el->el_chared.c_vcmd.action = NOP; - el->el_chared.c_vcmd.pos = 0; - - el->el_state.doingarg = 0; - - el->el_state.inputmode = MODE_INSERT; - el->el_map.current = el->el_map.alt; -#ifdef VI_MOVE - if (el->el_line.cursor > el->el_line.buffer) - el->el_line.cursor--; -#endif - return CC_CURSOR; -} - - -/* vi_zero(): - * Vi move to the beginning of line - * [0] - */ -protected el_action_t -vi_zero(EditLine *el, Int c) -{ - - if (el->el_state.doingarg) - return ed_argument_digit(el, c); - - el->el_line.cursor = el->el_line.buffer; - if (el->el_chared.c_vcmd.action != NOP) { - cv_delfini(el); - return CC_REFRESH; - } - return CC_CURSOR; -} - - -/* vi_delete_prev_char(): - * Vi move to previous character (backspace) - * [^H] in insert mode only - */ -protected el_action_t -/*ARGSUSED*/ -vi_delete_prev_char(EditLine *el, Int c __attribute__((__unused__))) -{ - - if (el->el_line.cursor <= el->el_line.buffer) - return CC_ERROR; - - c_delbefore1(el); - el->el_line.cursor--; - return CC_REFRESH; -} - - -/* vi_list_or_eof(): - * Vi list choices for completion or indicate end of file if empty line - * [^D] - */ -protected el_action_t -/*ARGSUSED*/ -vi_list_or_eof(EditLine *el, Int c) -{ - - if (el->el_line.cursor == el->el_line.lastchar) { - if (el->el_line.cursor == el->el_line.buffer) { - terminal_writec(el, c); /* then do a EOF */ - return CC_EOF; - } else { - /* - * Here we could list completions, but it is an - * error right now - */ - terminal_beep(el); - return CC_ERROR; - } - } else { -#ifdef notyet - re_goto_bottom(el); - *el->el_line.lastchar = '\0'; /* just in case */ - return CC_LIST_CHOICES; -#else - /* - * Just complain for now. - */ - terminal_beep(el); - return CC_ERROR; -#endif - } -} - - -/* vi_kill_line_prev(): - * Vi cut from beginning of line to cursor - * [^U] - */ -protected el_action_t -/*ARGSUSED*/ -vi_kill_line_prev(EditLine *el, Int c __attribute__((__unused__))) -{ - Char *kp, *cp; - - cp = el->el_line.buffer; - kp = el->el_chared.c_kill.buf; - while (cp < el->el_line.cursor) - *kp++ = *cp++; /* copy it */ - el->el_chared.c_kill.last = kp; - c_delbefore(el, (int)(el->el_line.cursor - el->el_line.buffer)); - el->el_line.cursor = el->el_line.buffer; /* zap! */ - return CC_REFRESH; -} - - -/* vi_search_prev(): - * Vi search history previous - * [?] - */ -protected el_action_t -/*ARGSUSED*/ -vi_search_prev(EditLine *el, Int c __attribute__((__unused__))) -{ - - return cv_search(el, ED_SEARCH_PREV_HISTORY); -} - - -/* vi_search_next(): - * Vi search history next - * [/] - */ -protected el_action_t -/*ARGSUSED*/ -vi_search_next(EditLine *el, Int c __attribute__((__unused__))) -{ - - return cv_search(el, ED_SEARCH_NEXT_HISTORY); -} - - -/* vi_repeat_search_next(): - * Vi repeat current search in the same search direction - * [n] - */ -protected el_action_t -/*ARGSUSED*/ -vi_repeat_search_next(EditLine *el, Int c __attribute__((__unused__))) -{ - - if (el->el_search.patlen == 0) - return CC_ERROR; - else - return cv_repeat_srch(el, el->el_search.patdir); -} - - -/* vi_repeat_search_prev(): - * Vi repeat current search in the opposite search direction - * [N] - */ -/*ARGSUSED*/ -protected el_action_t -vi_repeat_search_prev(EditLine *el, Int c __attribute__((__unused__))) -{ - - if (el->el_search.patlen == 0) - return CC_ERROR; - else - return (cv_repeat_srch(el, - el->el_search.patdir == ED_SEARCH_PREV_HISTORY ? - ED_SEARCH_NEXT_HISTORY : ED_SEARCH_PREV_HISTORY)); -} - - -/* vi_next_char(): - * Vi move to the character specified next - * [f] - */ -protected el_action_t -/*ARGSUSED*/ -vi_next_char(EditLine *el, Int c __attribute__((__unused__))) -{ - return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 0); -} - - -/* vi_prev_char(): - * Vi move to the character specified previous - * [F] - */ -protected el_action_t -/*ARGSUSED*/ -vi_prev_char(EditLine *el, Int c __attribute__((__unused__))) -{ - return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 0); -} - - -/* vi_to_next_char(): - * Vi move up to the character specified next - * [t] - */ -protected el_action_t -/*ARGSUSED*/ -vi_to_next_char(EditLine *el, Int c __attribute__((__unused__))) -{ - return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 1); -} - - -/* vi_to_prev_char(): - * Vi move up to the character specified previous - * [T] - */ -protected el_action_t -/*ARGSUSED*/ -vi_to_prev_char(EditLine *el, Int c __attribute__((__unused__))) -{ - return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 1); -} - - -/* vi_repeat_next_char(): - * Vi repeat current character search in the same search direction - * [;] - */ -protected el_action_t -/*ARGSUSED*/ -vi_repeat_next_char(EditLine *el, Int c __attribute__((__unused__))) -{ - - return cv_csearch(el, el->el_search.chadir, el->el_search.chacha, - el->el_state.argument, el->el_search.chatflg); -} - - -/* vi_repeat_prev_char(): - * Vi repeat current character search in the opposite search direction - * [,] - */ -protected el_action_t -/*ARGSUSED*/ -vi_repeat_prev_char(EditLine *el, Int c __attribute__((__unused__))) -{ - el_action_t r; - int dir = el->el_search.chadir; - - r = cv_csearch(el, -dir, el->el_search.chacha, - el->el_state.argument, el->el_search.chatflg); - el->el_search.chadir = dir; - return r; -} - - -/* vi_match(): - * Vi go to matching () {} or [] - * [%] - */ -protected el_action_t -/*ARGSUSED*/ -vi_match(EditLine *el, Int c __attribute__((__unused__))) -{ - const Char match_chars[] = STR("()[]{}"); - Char *cp; - size_t delta, i, count; - Char o_ch, c_ch; - - *el->el_line.lastchar = '\0'; /* just in case */ - - i = Strcspn(el->el_line.cursor, match_chars); - o_ch = el->el_line.cursor[i]; - if (o_ch == 0) - return CC_ERROR; - delta = (size_t)(Strchr(match_chars, o_ch) - match_chars); - c_ch = match_chars[delta ^ 1]; - count = 1; - delta = 1 - (delta & 1) * 2; - - for (cp = &el->el_line.cursor[i]; count; ) { - cp += delta; - if (cp < el->el_line.buffer || cp >= el->el_line.lastchar) - return CC_ERROR; - if (*cp == o_ch) - count++; - else if (*cp == c_ch) - count--; - } - - el->el_line.cursor = cp; - - if (el->el_chared.c_vcmd.action != NOP) { - /* NB posix says char under cursor should NOT be deleted - for -ve delta - this is different to netbsd vi. */ - if (delta > 0) - el->el_line.cursor++; - cv_delfini(el); - return CC_REFRESH; - } - return CC_CURSOR; -} - -/* vi_undo_line(): - * Vi undo all changes to line - * [U] - */ -protected el_action_t -/*ARGSUSED*/ -vi_undo_line(EditLine *el, Int c __attribute__((__unused__))) -{ - - cv_undo(el); - return hist_get(el); -} - -/* vi_to_column(): - * Vi go to specified column - * [|] - * NB netbsd vi goes to screen column 'n', posix says nth character - */ -protected el_action_t -/*ARGSUSED*/ -vi_to_column(EditLine *el, Int c __attribute__((__unused__))) -{ - - el->el_line.cursor = el->el_line.buffer; - el->el_state.argument--; - return ed_next_char(el, 0); -} - -/* vi_yank_end(): - * Vi yank to end of line - * [Y] - */ -protected el_action_t -/*ARGSUSED*/ -vi_yank_end(EditLine *el, Int c __attribute__((__unused__))) -{ - - cv_yank(el, el->el_line.cursor, - (int)(el->el_line.lastchar - el->el_line.cursor)); - return CC_REFRESH; -} - -/* vi_yank(): - * Vi yank - * [y] - */ -protected el_action_t -/*ARGSUSED*/ -vi_yank(EditLine *el, Int c __attribute__((__unused__))) -{ - - return cv_action(el, YANK); -} - -/* vi_comment_out(): - * Vi comment out current command - * [#] - */ -protected el_action_t -/*ARGSUSED*/ -vi_comment_out(EditLine *el, Int c __attribute__((__unused__))) -{ - - el->el_line.cursor = el->el_line.buffer; - c_insert(el, 1); - *el->el_line.cursor = '#'; - re_refresh(el); - return ed_newline(el, 0); -} - -/* vi_alias(): - * Vi include shell alias - * [@] - * NB: posix implies that we should enter insert mode, however - * this is against historical precedent... - */ -#if defined(__weak_reference) && !defined(__FreeBSD__) -__weakref_visible char *my_get_alias_text(const char *) - __weak_reference(get_alias_text); -#endif -protected el_action_t -/*ARGSUSED*/ -vi_alias(EditLine *el __attribute__((__unused__)), - Int c __attribute__((__unused__))) -{ -#if defined(__weak_reference) && !defined(__FreeBSD__) - char alias_name[3]; - char *alias_text; - - if (my_get_alias_text == 0) { - return CC_ERROR; - } - - alias_name[0] = '_'; - alias_name[2] = 0; - if (el_getc(el, &alias_name[1]) != 1) - return CC_ERROR; - - alias_text = my_get_alias_text(alias_name); - if (alias_text != NULL) - FUN(el,push)(el, ct_decode_string(alias_text, &el->el_scratch)); - return CC_NORM; -#else - return CC_ERROR; -#endif -} - -/* vi_to_history_line(): - * Vi go to specified history file line. - * [G] - */ -protected el_action_t -/*ARGSUSED*/ -vi_to_history_line(EditLine *el, Int c __attribute__((__unused__))) -{ - int sv_event_no = el->el_history.eventno; - el_action_t rval; - - - if (el->el_history.eventno == 0) { - (void) Strncpy(el->el_history.buf, el->el_line.buffer, - EL_BUFSIZ); - el->el_history.last = el->el_history.buf + - (el->el_line.lastchar - el->el_line.buffer); - } - - /* Lack of a 'count' means oldest, not 1 */ - if (!el->el_state.doingarg) { - el->el_history.eventno = 0x7fffffff; - hist_get(el); - } else { - /* This is brain dead, all the rest of this code counts - * upwards going into the past. Here we need count in the - * other direction (to match the output of fc -l). - * I could change the world, but this seems to suffice. - */ - el->el_history.eventno = 1; - if (hist_get(el) == CC_ERROR) - return CC_ERROR; - el->el_history.eventno = 1 + el->el_history.ev.num - - el->el_state.argument; - if (el->el_history.eventno < 0) { - el->el_history.eventno = sv_event_no; - return CC_ERROR; - } - } - rval = hist_get(el); - if (rval == CC_ERROR) - el->el_history.eventno = sv_event_no; - return rval; -} - -/* vi_histedit(): - * Vi edit history line with vi - * [v] - */ -protected el_action_t -/*ARGSUSED*/ -vi_histedit(EditLine *el, Int c __attribute__((__unused__))) -{ - int fd; - pid_t pid; - ssize_t st; - int status; - char tempfile[] = "/tmp/histedit.XXXXXXXXXX"; - char *cp; - size_t len; - Char *line; - mbstate_t state; - - memset(&state, 0, sizeof(mbstate_t)); - if (el->el_state.doingarg) { - if (vi_to_history_line(el, 0) == CC_ERROR) - return CC_ERROR; - } - - fd = mkstemp(tempfile); - if (fd < 0) - return CC_ERROR; - len = (size_t)(el->el_line.lastchar - el->el_line.buffer); -#define TMP_BUFSIZ (EL_BUFSIZ * MB_LEN_MAX) - cp = el_malloc(TMP_BUFSIZ * sizeof(*cp)); - if (cp == NULL) { - unlink(tempfile); - close(fd); - return CC_ERROR; - } - line = el_malloc(len * sizeof(*line)); - if (line == NULL) { - el_free(cp); - return CC_ERROR; - } - Strncpy(line, el->el_line.buffer, len); - line[len] = '\0'; - wcsrtombs(cp, (const wchar_t **) &line, TMP_BUFSIZ - 1, &state); - cp[TMP_BUFSIZ - 1] = '\0'; - len = strlen(cp); - if (write(fd, cp, len) == -1) - goto error; - if (write(fd, "\n", (size_t)1) == -1) - goto error; - pid = fork(); - switch (pid) { - case -1: - close(fd); - unlink(tempfile); - el_free(cp); - el_free(line); - return CC_ERROR; - case 0: - close(fd); - execlp("vi", "vi", tempfile, (char *)NULL); - exit(0); - /*NOTREACHED*/ - default: - while (waitpid(pid, &status, 0) != pid) - continue; - lseek(fd, (off_t)0, SEEK_SET); - st = read(fd, cp, TMP_BUFSIZ); - if (st > 0) { - len = (size_t)(el->el_line.lastchar - - el->el_line.buffer); - memset(&state, 0, sizeof(mbstate_t)); - len = mbsrtowcs(el->el_line.buffer, - (const char**) &cp, len, &state); - if (len > 0 && el->el_line.buffer[len -1] == '\n') - --len; - } - else - len = 0; - el->el_line.cursor = el->el_line.buffer; - el->el_line.lastchar = el->el_line.buffer + len; - el_free(cp); - el_free(line); - break; - } - - close(fd); - unlink(tempfile); - /* return CC_REFRESH; */ - return ed_newline(el, 0); - -/* XXXMYSQL: Avoid compiler warnings. */ -error: - close(fd); - unlink(tempfile); - return CC_ERROR; -} - -/* vi_history_word(): - * Vi append word from previous input line - * [_] - * Who knows where this one came from! - * '_' in vi means 'entire current line', so 'cc' is a synonym for 'c_' - */ -protected el_action_t -/*ARGSUSED*/ -vi_history_word(EditLine *el, Int c __attribute__((__unused__))) -{ - const Char *wp = HIST_FIRST(el); - const Char *wep, *wsp; - int len; - Char *cp; - const Char *lim; - - if (wp == NULL) - return CC_ERROR; - - wep = wsp = 0; - do { - while (Isspace(*wp)) - wp++; - if (*wp == 0) - break; - wsp = wp; - while (*wp && !Isspace(*wp)) - wp++; - wep = wp; - } while ((!el->el_state.doingarg || --el->el_state.argument > 0) - && *wp != 0); - - if (wsp == 0 || (el->el_state.doingarg && el->el_state.argument != 0)) - return CC_ERROR; - - cv_undo(el); - len = (int)(wep - wsp); - if (el->el_line.cursor < el->el_line.lastchar) - el->el_line.cursor++; - c_insert(el, len + 1); - cp = el->el_line.cursor; - lim = el->el_line.limit; - if (cp < lim) - *cp++ = ' '; - while (wsp < wep && cp < lim) - *cp++ = *wsp++; - el->el_line.cursor = cp; - - el->el_map.current = el->el_map.key; - return CC_REFRESH; -} - -/* vi_redo(): - * Vi redo last non-motion command - * [.] - */ -protected el_action_t -/*ARGSUSED*/ -vi_redo(EditLine *el, Int c __attribute__((__unused__))) -{ - c_redo_t *r = &el->el_chared.c_redo; - - if (!el->el_state.doingarg && r->count) { - el->el_state.doingarg = 1; - el->el_state.argument = r->count; - } - - el->el_chared.c_vcmd.pos = el->el_line.cursor; - el->el_chared.c_vcmd.action = r->action; - if (r->pos != r->buf) { - if (r->pos + 1 > r->lim) - /* sanity */ - r->pos = r->lim - 1; - r->pos[0] = 0; - FUN(el,push)(el, r->buf); - } - - el->el_state.thiscmd = r->cmd; - el->el_state.thisch = r->ch; - return (*el->el_map.func[r->cmd])(el, r->ch); -} diff --git a/cmd-line-utils/readline/CMakeLists.txt b/extra/readline/CMakeLists.txt similarity index 96% rename from cmd-line-utils/readline/CMakeLists.txt rename to extra/readline/CMakeLists.txt index c06b9c08c47..e245a2cd435 100644 --- a/cmd-line-utils/readline/CMakeLists.txt +++ b/extra/readline/CMakeLists.txt @@ -14,7 +14,7 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include - ${CMAKE_SOURCE_DIR}/cmd-line-utils) + ${CMAKE_SOURCE_DIR}/extra) ADD_DEFINITIONS(-DHAVE_CONFIG_H -DNO_KILL_INTR) diff --git a/cmd-line-utils/readline/COPYING b/extra/readline/COPYING similarity index 100% rename from cmd-line-utils/readline/COPYING rename to extra/readline/COPYING diff --git a/cmd-line-utils/readline/INSTALL b/extra/readline/INSTALL similarity index 100% rename from cmd-line-utils/readline/INSTALL rename to extra/readline/INSTALL diff --git a/cmd-line-utils/readline/README b/extra/readline/README similarity index 100% rename from cmd-line-utils/readline/README rename to extra/readline/README diff --git a/cmd-line-utils/readline/ansi_stdlib.h b/extra/readline/ansi_stdlib.h similarity index 100% rename from cmd-line-utils/readline/ansi_stdlib.h rename to extra/readline/ansi_stdlib.h diff --git a/cmd-line-utils/readline/bind.c b/extra/readline/bind.c similarity index 100% rename from cmd-line-utils/readline/bind.c rename to extra/readline/bind.c diff --git a/cmd-line-utils/readline/callback.c b/extra/readline/callback.c similarity index 100% rename from cmd-line-utils/readline/callback.c rename to extra/readline/callback.c diff --git a/cmd-line-utils/readline/chardefs.h b/extra/readline/chardefs.h similarity index 100% rename from cmd-line-utils/readline/chardefs.h rename to extra/readline/chardefs.h diff --git a/cmd-line-utils/readline/compat.c b/extra/readline/compat.c similarity index 100% rename from cmd-line-utils/readline/compat.c rename to extra/readline/compat.c diff --git a/cmd-line-utils/readline/complete.c b/extra/readline/complete.c similarity index 100% rename from cmd-line-utils/readline/complete.c rename to extra/readline/complete.c diff --git a/cmd-line-utils/readline/config_readline.h b/extra/readline/config_readline.h similarity index 100% rename from cmd-line-utils/readline/config_readline.h rename to extra/readline/config_readline.h diff --git a/cmd-line-utils/readline/configure.in b/extra/readline/configure.in similarity index 100% rename from cmd-line-utils/readline/configure.in rename to extra/readline/configure.in diff --git a/cmd-line-utils/readline/display.c b/extra/readline/display.c similarity index 100% rename from cmd-line-utils/readline/display.c rename to extra/readline/display.c diff --git a/cmd-line-utils/readline/emacs_keymap.c b/extra/readline/emacs_keymap.c similarity index 100% rename from cmd-line-utils/readline/emacs_keymap.c rename to extra/readline/emacs_keymap.c diff --git a/cmd-line-utils/readline/funmap.c b/extra/readline/funmap.c similarity index 100% rename from cmd-line-utils/readline/funmap.c rename to extra/readline/funmap.c diff --git a/cmd-line-utils/readline/histexpand.c b/extra/readline/histexpand.c similarity index 100% rename from cmd-line-utils/readline/histexpand.c rename to extra/readline/histexpand.c diff --git a/cmd-line-utils/readline/histfile.c b/extra/readline/histfile.c similarity index 100% rename from cmd-line-utils/readline/histfile.c rename to extra/readline/histfile.c diff --git a/cmd-line-utils/readline/histlib.h b/extra/readline/histlib.h similarity index 100% rename from cmd-line-utils/readline/histlib.h rename to extra/readline/histlib.h diff --git a/cmd-line-utils/readline/history.c b/extra/readline/history.c similarity index 100% rename from cmd-line-utils/readline/history.c rename to extra/readline/history.c diff --git a/cmd-line-utils/readline/history.h b/extra/readline/history.h similarity index 100% rename from cmd-line-utils/readline/history.h rename to extra/readline/history.h diff --git a/cmd-line-utils/readline/histsearch.c b/extra/readline/histsearch.c similarity index 100% rename from cmd-line-utils/readline/histsearch.c rename to extra/readline/histsearch.c diff --git a/cmd-line-utils/readline/input.c b/extra/readline/input.c similarity index 100% rename from cmd-line-utils/readline/input.c rename to extra/readline/input.c diff --git a/cmd-line-utils/readline/isearch.c b/extra/readline/isearch.c similarity index 100% rename from cmd-line-utils/readline/isearch.c rename to extra/readline/isearch.c diff --git a/cmd-line-utils/readline/keymaps.c b/extra/readline/keymaps.c similarity index 100% rename from cmd-line-utils/readline/keymaps.c rename to extra/readline/keymaps.c diff --git a/cmd-line-utils/readline/keymaps.h b/extra/readline/keymaps.h similarity index 100% rename from cmd-line-utils/readline/keymaps.h rename to extra/readline/keymaps.h diff --git a/cmd-line-utils/readline/kill.c b/extra/readline/kill.c similarity index 100% rename from cmd-line-utils/readline/kill.c rename to extra/readline/kill.c diff --git a/cmd-line-utils/readline/macro.c b/extra/readline/macro.c similarity index 100% rename from cmd-line-utils/readline/macro.c rename to extra/readline/macro.c diff --git a/cmd-line-utils/readline/mbutil.c b/extra/readline/mbutil.c similarity index 100% rename from cmd-line-utils/readline/mbutil.c rename to extra/readline/mbutil.c diff --git a/cmd-line-utils/readline/misc.c b/extra/readline/misc.c similarity index 100% rename from cmd-line-utils/readline/misc.c rename to extra/readline/misc.c diff --git a/cmd-line-utils/readline/nls.c b/extra/readline/nls.c similarity index 100% rename from cmd-line-utils/readline/nls.c rename to extra/readline/nls.c diff --git a/cmd-line-utils/readline/parens.c b/extra/readline/parens.c similarity index 100% rename from cmd-line-utils/readline/parens.c rename to extra/readline/parens.c diff --git a/cmd-line-utils/readline/posixdir.h b/extra/readline/posixdir.h similarity index 100% rename from cmd-line-utils/readline/posixdir.h rename to extra/readline/posixdir.h diff --git a/cmd-line-utils/readline/posixjmp.h b/extra/readline/posixjmp.h similarity index 100% rename from cmd-line-utils/readline/posixjmp.h rename to extra/readline/posixjmp.h diff --git a/cmd-line-utils/readline/posixstat.h b/extra/readline/posixstat.h similarity index 100% rename from cmd-line-utils/readline/posixstat.h rename to extra/readline/posixstat.h diff --git a/cmd-line-utils/readline/readline.c b/extra/readline/readline.c similarity index 100% rename from cmd-line-utils/readline/readline.c rename to extra/readline/readline.c diff --git a/cmd-line-utils/readline/readline.h b/extra/readline/readline.h similarity index 100% rename from cmd-line-utils/readline/readline.h rename to extra/readline/readline.h diff --git a/cmd-line-utils/readline/rlconf.h b/extra/readline/rlconf.h similarity index 100% rename from cmd-line-utils/readline/rlconf.h rename to extra/readline/rlconf.h diff --git a/cmd-line-utils/readline/rldefs.h b/extra/readline/rldefs.h similarity index 100% rename from cmd-line-utils/readline/rldefs.h rename to extra/readline/rldefs.h diff --git a/cmd-line-utils/readline/rlmbutil.h b/extra/readline/rlmbutil.h similarity index 100% rename from cmd-line-utils/readline/rlmbutil.h rename to extra/readline/rlmbutil.h diff --git a/cmd-line-utils/readline/rlprivate.h b/extra/readline/rlprivate.h similarity index 100% rename from cmd-line-utils/readline/rlprivate.h rename to extra/readline/rlprivate.h diff --git a/cmd-line-utils/readline/rlshell.h b/extra/readline/rlshell.h similarity index 100% rename from cmd-line-utils/readline/rlshell.h rename to extra/readline/rlshell.h diff --git a/cmd-line-utils/readline/rlstdc.h b/extra/readline/rlstdc.h similarity index 100% rename from cmd-line-utils/readline/rlstdc.h rename to extra/readline/rlstdc.h diff --git a/cmd-line-utils/readline/rltty.c b/extra/readline/rltty.c similarity index 100% rename from cmd-line-utils/readline/rltty.c rename to extra/readline/rltty.c diff --git a/cmd-line-utils/readline/rltty.h b/extra/readline/rltty.h similarity index 100% rename from cmd-line-utils/readline/rltty.h rename to extra/readline/rltty.h diff --git a/cmd-line-utils/readline/rltypedefs.h b/extra/readline/rltypedefs.h similarity index 100% rename from cmd-line-utils/readline/rltypedefs.h rename to extra/readline/rltypedefs.h diff --git a/cmd-line-utils/readline/rlwinsize.h b/extra/readline/rlwinsize.h similarity index 100% rename from cmd-line-utils/readline/rlwinsize.h rename to extra/readline/rlwinsize.h diff --git a/cmd-line-utils/readline/savestring.c b/extra/readline/savestring.c similarity index 100% rename from cmd-line-utils/readline/savestring.c rename to extra/readline/savestring.c diff --git a/cmd-line-utils/readline/search.c b/extra/readline/search.c similarity index 100% rename from cmd-line-utils/readline/search.c rename to extra/readline/search.c diff --git a/cmd-line-utils/readline/shell.c b/extra/readline/shell.c similarity index 100% rename from cmd-line-utils/readline/shell.c rename to extra/readline/shell.c diff --git a/cmd-line-utils/readline/signals.c b/extra/readline/signals.c similarity index 100% rename from cmd-line-utils/readline/signals.c rename to extra/readline/signals.c diff --git a/cmd-line-utils/readline/tcap.h b/extra/readline/tcap.h similarity index 100% rename from cmd-line-utils/readline/tcap.h rename to extra/readline/tcap.h diff --git a/cmd-line-utils/readline/terminal.c b/extra/readline/terminal.c similarity index 100% rename from cmd-line-utils/readline/terminal.c rename to extra/readline/terminal.c diff --git a/cmd-line-utils/readline/text.c b/extra/readline/text.c similarity index 100% rename from cmd-line-utils/readline/text.c rename to extra/readline/text.c diff --git a/cmd-line-utils/readline/tilde.c b/extra/readline/tilde.c similarity index 100% rename from cmd-line-utils/readline/tilde.c rename to extra/readline/tilde.c diff --git a/cmd-line-utils/readline/tilde.h b/extra/readline/tilde.h similarity index 100% rename from cmd-line-utils/readline/tilde.h rename to extra/readline/tilde.h diff --git a/cmd-line-utils/readline/undo.c b/extra/readline/undo.c similarity index 100% rename from cmd-line-utils/readline/undo.c rename to extra/readline/undo.c diff --git a/cmd-line-utils/readline/util.c b/extra/readline/util.c similarity index 100% rename from cmd-line-utils/readline/util.c rename to extra/readline/util.c diff --git a/cmd-line-utils/readline/vi_keymap.c b/extra/readline/vi_keymap.c similarity index 100% rename from cmd-line-utils/readline/vi_keymap.c rename to extra/readline/vi_keymap.c diff --git a/cmd-line-utils/readline/vi_mode.c b/extra/readline/vi_mode.c similarity index 100% rename from cmd-line-utils/readline/vi_mode.c rename to extra/readline/vi_mode.c diff --git a/cmd-line-utils/readline/xmalloc.c b/extra/readline/xmalloc.c similarity index 100% rename from cmd-line-utils/readline/xmalloc.c rename to extra/readline/xmalloc.c diff --git a/cmd-line-utils/readline/xmalloc.h b/extra/readline/xmalloc.h similarity index 100% rename from cmd-line-utils/readline/xmalloc.h rename to extra/readline/xmalloc.h From b054e4bdb109c6ec7459c26cc81ba964e52cb090 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 19 Sep 2014 12:51:33 +0200 Subject: [PATCH 060/153] bugfix: disabling partitioning in already built tree that didn't quite work, WITH_PARTITION_STORAGE_ENGINE was not undefined --- cmake/plugin.cmake | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmake/plugin.cmake b/cmake/plugin.cmake index 2dc88782937..ad309c51066 100644 --- a/cmake/plugin.cmake +++ b/cmake/plugin.cmake @@ -104,6 +104,7 @@ MACRO(MYSQL_ADD_PLUGIN) ELSE() SET(with_var "WITH_${plugin}") ENDIF() + UNSET(${with_var} CACHE) IF(NOT ARG_DEPENDENCIES) SET(ARG_DEPENDENCIES) @@ -218,8 +219,6 @@ MACRO(MYSQL_ADD_PLUGIN) ENDIF() ADD_DEPENDENCIES(${target} GenError ${ARG_DEPENDENCIES}) - UNSET(${with_var} CACHE) - SET_TARGET_PROPERTIES(${target} PROPERTIES OUTPUT_NAME "${ARG_MODULE_OUTPUT_NAME}") # Install dynamic library From 1a731af1941f9df57c90dbad8614c76b65ba688d Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 19 Sep 2014 21:10:06 +0200 Subject: [PATCH 061/153] cleanup: remove redundant clauses from sys_vars.cc --- sql/sys_vars.cc | 34 +++++++++++----------------------- sql/sys_vars.h | 4 ++-- 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 0c68409dd25..959e65557c5 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -1000,8 +1000,7 @@ static Sys_var_session_lexstring Sys_default_master_connection( "Master connection to use for all slave variables and slave commands", SESSION_ONLY(default_master_connection), NO_CMD_LINE, IN_SYSTEM_CHARSET, - DEFAULT(""), MAX_CONNECTION_NAME, ON_CHECK(check_master_connection), - ON_UPDATE(0)); + DEFAULT(""), MAX_CONNECTION_NAME, ON_CHECK(check_master_connection)); #endif static Sys_var_charptr Sys_init_file( @@ -2790,8 +2789,7 @@ static Sys_var_replicate_events_marked_for_skip Replicate_events_marked_for_skip "@@skip_replication=1 will be filtered on the master and never be sent to " "the slave).", GLOBAL_VAR(opt_replicate_events_marked_for_skip), CMD_LINE(REQUIRED_ARG), - replicate_events_marked_for_skip_names, DEFAULT(RPL_SKIP_REPLICATE), - NO_MUTEX_GUARD, NOT_IN_BINLOG); + replicate_events_marked_for_skip_names, DEFAULT(RPL_SKIP_REPLICATE)); #endif @@ -2936,7 +2934,7 @@ static Sys_var_set Sys_old_behavior( "old_mode", "Used to emulate old behavior from earlier MariaDB or MySQL versions", SESSION_VAR(old_behavior), CMD_LINE(REQUIRED_ARG), - old_mode_names, DEFAULT(0), NO_MUTEX_GUARD, NOT_IN_BINLOG); + old_mode_names, DEFAULT(0)); #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) #define SSL_OPT(X) CMD_LINE(REQUIRED_ARG,X) @@ -3270,8 +3268,7 @@ static Sys_var_plugin Sys_storage_engine( static Sys_var_plugin Sys_default_tmp_storage_engine( "default_tmp_storage_engine", "The default storage engine for user-created temporary tables", SESSION_VAR(tmp_table_plugin), NO_CMD_LINE, - MYSQL_STORAGE_ENGINE_PLUGIN, DEFAULT(&default_tmp_storage_engine), - NO_MUTEX_GUARD, NOT_IN_BINLOG); + MYSQL_STORAGE_ENGINE_PLUGIN, DEFAULT(&default_tmp_storage_engine)); #if defined(ENABLED_DEBUG_SYNC) /* @@ -4212,9 +4209,7 @@ static Sys_var_uint Sys_slave_net_timeout( "slave_net_timeout", "Number of seconds to wait for more data " "from any master/slave connection before aborting the read", GLOBAL_VAR(slave_net_timeout), CMD_LINE(REQUIRED_ARG), - VALID_RANGE(1, LONG_TIMEOUT), DEFAULT(SLAVE_NET_TIMEOUT), BLOCK_SIZE(1), - NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), - ON_UPDATE(0)); + VALID_RANGE(1, LONG_TIMEOUT), DEFAULT(SLAVE_NET_TIMEOUT), BLOCK_SIZE(1)); /* @@ -4461,8 +4456,7 @@ static Sys_var_charptr Sys_wsrep_provider_options( static Sys_var_charptr Sys_wsrep_data_home_dir( "wsrep_data_home_dir", "home directory for wsrep provider", READ_ONLY GLOBAL_VAR(wsrep_data_home_dir), CMD_LINE(REQUIRED_ARG), - IN_FS_CHARSET, DEFAULT(""), - NO_MUTEX_GUARD, NOT_IN_BINLOG); + IN_FS_CHARSET, DEFAULT("")); static Sys_var_charptr Sys_wsrep_cluster_name( "wsrep_cluster_name", "Name for the cluster", @@ -4499,8 +4493,7 @@ static Sys_var_charptr Sys_wsrep_node_address ( static Sys_var_charptr Sys_wsrep_node_incoming_address( "wsrep_node_incoming_address", "Client connection address", PREALLOCATED GLOBAL_VAR(wsrep_node_incoming_address),CMD_LINE(REQUIRED_ARG), - IN_FS_CHARSET, DEFAULT(WSREP_NODE_INCOMING_AUTO), - NO_MUTEX_GUARD, NOT_IN_BINLOG); + IN_FS_CHARSET, DEFAULT(WSREP_NODE_INCOMING_AUTO)); static Sys_var_ulong Sys_wsrep_slave_threads( "wsrep_slave_threads", "Number of slave appliers to launch", @@ -4513,8 +4506,7 @@ static Sys_var_ulong Sys_wsrep_slave_threads( static Sys_var_charptr Sys_wsrep_dbug_option( "wsrep_dbug_option", "DBUG options to provider library", GLOBAL_VAR(wsrep_dbug_option),CMD_LINE(REQUIRED_ARG), - IN_FS_CHARSET, DEFAULT(""), - NO_MUTEX_GUARD, NOT_IN_BINLOG); + IN_FS_CHARSET, DEFAULT("")); static Sys_var_mybool Sys_wsrep_debug( "wsrep_debug", "To enable debug level logging", @@ -4611,7 +4603,7 @@ static Sys_var_ulong Sys_wsrep_max_ws_rows ( static Sys_var_charptr Sys_wsrep_notify_cmd( "wsrep_notify_cmd", "", GLOBAL_VAR(wsrep_notify_cmd),CMD_LINE(REQUIRED_ARG), - IN_FS_CHARSET, DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG); + IN_FS_CHARSET, DEFAULT("")); static Sys_var_mybool Sys_wsrep_certify_nonPK( "wsrep_certify_nonPK", "Certify tables with no primary key", @@ -4640,9 +4632,7 @@ static const char *wsrep_OSU_method_names[]= { "TOI", "RSU", NullS }; static Sys_var_enum Sys_wsrep_OSU_method( "wsrep_OSU_method", "Method for Online Schema Upgrade", GLOBAL_VAR(wsrep_OSU_method_options), CMD_LINE(OPT_ARG), - wsrep_OSU_method_names, DEFAULT(WSREP_OSU_TOI), - NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), - ON_UPDATE(0)); + wsrep_OSU_method_names, DEFAULT(WSREP_OSU_TOI)); static PolyLock_mutex PLock_wsrep_desync(&LOCK_wsrep_desync); static Sys_var_mybool Sys_wsrep_desync ( @@ -4657,9 +4647,7 @@ static Sys_var_enum Sys_wsrep_forced_binlog_format( "wsrep_forced_binlog_format", "binlog format to take effect over user's choice", GLOBAL_VAR(wsrep_forced_binlog_format), CMD_LINE(REQUIRED_ARG, OPT_BINLOG_FORMAT), - wsrep_binlog_format_names, DEFAULT(BINLOG_FORMAT_UNSPEC), - NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), - ON_UPDATE(0)); + wsrep_binlog_format_names, DEFAULT(BINLOG_FORMAT_UNSPEC)); static Sys_var_mybool Sys_wsrep_recover_datadir( "wsrep_recover", "Recover database state after crash and exit", diff --git a/sql/sys_vars.h b/sql/sys_vars.h index cbf924ee036..7abea13f1b9 100644 --- a/sql/sys_vars.h +++ b/sql/sys_vars.h @@ -1981,8 +1981,8 @@ public: Sys_var_replicate_events_marked_for_skip(const char *name_arg, const char *comment, int flag_args, ptrdiff_t off, size_t size, CMD_LINE getopt, - const char *values[], uint def_val, PolyLock *lock, - enum binlog_status_enum binlog_status_arg) + const char *values[], uint def_val, PolyLock *lock= 0, + enum binlog_status_enum binlog_status_arg= VARIABLE_NOT_IN_BINLOG) :Sys_var_enum(name_arg, comment, flag_args, off, size, getopt, values, def_val, lock, binlog_status_arg) {} From b04f848176b0d8af41eb3627ba1b6ed4dd3327e3 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 20 Sep 2014 21:36:51 +0200 Subject: [PATCH 062/153] cleanup: use is_supported_parser_charset --- sql/sql_class.h | 4 ++++ sql/sql_parse.h | 5 ----- sql/sys_vars.cc | 3 +-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/sql/sql_class.h b/sql/sql_class.h index 3424a3380f0..1154f0ac486 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -801,6 +801,10 @@ mysqld_collation_get_by_name(const char *name, return cs; } +inline bool is_supported_parser_charset(CHARSET_INFO *cs) +{ + return MY_TEST(cs->mbminlen == 1); +} #ifdef MYSQL_SERVER diff --git a/sql/sql_parse.h b/sql/sql_parse.h index 87f8854e050..3bbddc8ba4d 100644 --- a/sql/sql_parse.h +++ b/sql/sql_parse.h @@ -198,9 +198,4 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables, bool check_global_access(THD *thd, ulong want_access, bool no_errors= false); -inline bool is_supported_parser_charset(CHARSET_INFO *cs) -{ - return MY_TEST(cs->mbminlen == 1); -} - #endif /* SQL_PARSE_INCLUDED */ diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 959e65557c5..e40dfbe8675 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -622,8 +622,7 @@ static bool check_cs_client(sys_var *self, THD *thd, set_var *var) if (check_charset_not_null(self, thd, var)) return true; - // Currently, UCS-2 cannot be used as a client character set - if (((CHARSET_INFO *)(var->save_result.ptr))->mbminlen > 1) + if (!is_supported_parser_charset((CHARSET_INFO *)(var->save_result.ptr))) return true; return false; From 3620910eeac8f118c9a6cb8a1c0ec23e56fb5d98 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 25 Sep 2014 23:00:45 +0200 Subject: [PATCH 063/153] cleanup: galera merge, simple changes --- .gitignore | 7 + CMakeLists.txt | 7 +- client/client_priv.h | 1 - client/mysqldump.c | 2 +- cmake/cpack_rpm.cmake | 7 +- cmake/plugin.cmake | 17 +- cmake/wsrep.cmake | 51 ++--- config.h.cmake | 6 + debian/dist/Debian/control | 6 +- debian/dist/Ubuntu/control | 6 +- include/wsrep.h | 4 +- mysql-test/include/have_wsrep_enabled.inc | 8 +- mysql-test/include/write_result_to_file.inc | 3 +- mysql-test/lib/My/ConfigFactory.pm | 3 - mysql-test/r/have_wsrep.require | 2 - mysql-test/suite/galera/galera_2nodes.cnf | 4 + .../suite/roles/set_default_role_for.result | 12 +- .../suite/roles/set_default_role_for.test | 12 +- mysql-test/t/mysql_tzinfo_to_sql_symlink.test | 5 - mysys/CMakeLists.txt | 4 - sql/CMakeLists.txt | 1 - sql/event_data_objects.cc | 10 +- sql/ha_partition.cc | 9 - sql/ha_partition.h | 3 - sql/handler.cc | 28 +-- sql/handler.h | 10 +- sql/item_func.cc | 9 +- sql/log.cc | 35 ++-- sql/log_event.cc | 2 +- sql/mdl.cc | 6 +- sql/mdl.h | 2 - sql/mysqld.cc | 196 +++--------------- sql/mysqld.h | 12 -- sql/protocol.cc | 2 +- sql/rpl_record.cc | 2 - sql/set_var.cc | 4 - sql/set_var.h | 6 - sql/slave.cc | 2 - sql/sp.cc | 21 +- sql/sp.h | 2 +- sql/sql_acl.cc | 4 +- sql/sql_base.cc | 2 - sql/sql_builtin.cc.in | 4 +- sql/sql_class.cc | 37 +--- sql/sql_class.h | 4 +- sql/sql_delete.cc | 9 +- sql/sql_insert.cc | 20 +- sql/sql_parse.cc | 194 +++++++---------- sql/sql_prepare.cc | 2 + sql/sql_reload.cc | 2 - sql/sql_table.cc | 3 +- sql/sql_trigger.cc | 4 +- sql/sql_truncate.cc | 7 +- sql/sql_update.cc | 9 +- sql/sql_yacc.yy | 4 - sql/sys_vars.cc | 57 ++--- sql/table.cc | 1 - sql/transaction.cc | 28 --- sql/wsrep_mysqld.cc | 110 ++++++++-- sql/wsrep_mysqld.h | 42 +++- sql/wsrep_sst.h | 13 +- sql/wsrep_thd.h | 13 +- sql/wsrep_var.cc | 47 +++-- sql/wsrep_var.h | 19 +- storage/innobase/wsrep/md5.cc | 5 +- storage/perfschema/CMakeLists.txt | 4 - storage/xtradb/wsrep/md5.cc | 5 +- support-files/mysql.server.sh | 10 +- wsrep/CMakeLists.txt | 3 - 69 files changed, 492 insertions(+), 699 deletions(-) delete mode 100644 mysql-test/r/have_wsrep.require diff --git a/.gitignore b/.gitignore index 24d82cb758c..2ed53e5365d 100644 --- a/.gitignore +++ b/.gitignore @@ -106,6 +106,11 @@ scripts/mysqld_safe scripts/mysqldumpslow scripts/mysqlhotcopy scripts/mytop +scripts/wsrep_sst_common +scripts/wsrep_sst_mysqldump +scripts/wsrep_sst_rsync +scripts/wsrep_sst_xtrabackup +scripts/wsrep_sst_xtrabackup-v2 sql-bench/bench-count-distinct sql-bench/bench-init.pl sql-bench/compare-results @@ -200,6 +205,8 @@ support-files/mysql.server support-files/mysql.spec support-files/mysqld_multi.server support-files/ndb-config-2-node.ini +support-files/wsrep.cnf +support-files/wsrep_notify tags tests/async_queries tests/bug25714 diff --git a/CMakeLists.txt b/CMakeLists.txt index 68f3b01eb28..0c54152420f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -376,9 +376,6 @@ ADD_SUBDIRECTORY(vio) ADD_SUBDIRECTORY(mysys) ADD_SUBDIRECTORY(mysys_ssl) ADD_SUBDIRECTORY(libmysql) -IF(WITH_WSREP) - ADD_SUBDIRECTORY(wsrep) -ENDIF() ADD_SUBDIRECTORY(client) ADD_SUBDIRECTORY(extra) ADD_SUBDIRECTORY(libservices) @@ -395,6 +392,10 @@ IF(NOT WITHOUT_SERVER) ADD_SUBDIRECTORY(libmysqld/examples) ENDIF(WITH_EMBEDDED_SERVER) + IF(WITH_WSREP) + ADD_SUBDIRECTORY(wsrep) + ENDIF() + ADD_SUBDIRECTORY(mysql-test) ADD_SUBDIRECTORY(mysql-test/lib/My/SafeProcess) ADD_SUBDIRECTORY(sql-bench) diff --git a/client/client_priv.h b/client/client_priv.h index ef93818829e..656c8fcf32a 100644 --- a/client/client_priv.h +++ b/client/client_priv.h @@ -92,7 +92,6 @@ enum options_client OPT_REPORT_PROGRESS, OPT_SKIP_ANNOTATE_ROWS_EVENTS, OPT_SSL_CRL, OPT_SSL_CRLPATH, - OPT_GALERA_SST_MODE, OPT_MAX_CLIENT_OPTION /* should be always the last */ }; diff --git a/client/mysqldump.c b/client/mysqldump.c index b8d04014552..98f6f15b46e 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -347,7 +347,7 @@ static struct my_option my_long_options[] = {"force", 'f', "Continue even if we get an SQL error.", &ignore_errors, &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"galera-sst-mode", OPT_GALERA_SST_MODE, + {"galera-sst-mode", 0, "This mode should normally be used in mysqldump snapshot state transfer " "(SST) in a Galera cluster. If enabled, mysqldump additionally dumps " "commands to turn off binary logging and SET global gtid_binlog_state " diff --git a/cmake/cpack_rpm.cmake b/cmake/cpack_rpm.cmake index d8f659ec5ea..738f0a2ecd1 100644 --- a/cmake/cpack_rpm.cmake +++ b/cmake/cpack_rpm.cmake @@ -149,8 +149,13 @@ SETA(CPACK_RPM_test_PACKAGE_PROVIDES SETA(CPACK_RPM_server_PACKAGE_REQUIRES "${CPACK_RPM_PACKAGE_REQUIRES}" - "MariaDB-client" "galera" "rsync" "lsof" "socat" "grep" "gawk" "iproute" + "MariaDB-client") + +IF(WITH_WSREP) +SETA(CPACK_RPM_server_PACKAGE_REQUIRES + "galera" "rsync" "lsof" "socat" "grep" "gawk" "iproute" "coreutils" "findutils") +ENDIF() SET(CPACK_RPM_server_PRE_INSTALL_SCRIPT_FILE ${CMAKE_SOURCE_DIR}/support-files/rpm/server-prein.sh) SET(CPACK_RPM_server_PRE_UNINSTALL_SCRIPT_FILE ${CMAKE_SOURCE_DIR}/support-files/rpm/server-preun.sh) diff --git a/cmake/plugin.cmake b/cmake/plugin.cmake index ad309c51066..632c4cfe442 100644 --- a/cmake/plugin.cmake +++ b/cmake/plugin.cmake @@ -155,14 +155,6 @@ MACRO(MYSQL_ADD_PLUGIN) ENDIF() ENDIF() - IF (WITH_WSREP) - # Set compile definitions for non-embedded plugins - LIST(APPEND wsrep_definitions "WITH_WSREP") - LIST(APPEND wsrep_definitions "WSREP_PROC_INFO") - SET_TARGET_PROPERTIES(${target} PROPERTIES - COMPILE_DEFINITIONS "${wsrep_definitions}") - ENDIF() - IF(ARG_STATIC_OUTPUT_NAME) SET_TARGET_PROPERTIES(${target} PROPERTIES OUTPUT_NAME ${ARG_STATIC_OUTPUT_NAME}) @@ -195,15 +187,8 @@ MACRO(MYSQL_ADD_PLUGIN) ADD_LIBRARY(${target} MODULE ${SOURCES}) DTRACE_INSTRUMENT(${target}) - LIST(APPEND dyn_compile_definitions "MYSQL_DYNAMIC_PLUGIN") - - IF (WITH_WSREP) - LIST(APPEND dyn_compile_definitions "WITH_WSREP") - LIST(APPEND dyn_compile_definitions "WSREP_PROC_INFO") - ENDIF() - SET_TARGET_PROPERTIES (${target} PROPERTIES PREFIX "" - COMPILE_DEFINITIONS "${dyn_compile_definitions}") + COMPILE_DEFINITIONS "MYSQL_DYNAMIC_PLUGIN") TARGET_LINK_LIBRARIES (${target} mysqlservices ${ARG_LINK_LIBRARIES}) diff --git a/cmake/wsrep.cmake b/cmake/wsrep.cmake index d3c8da6a72a..211ed30ff4c 100644 --- a/cmake/wsrep.cmake +++ b/cmake/wsrep.cmake @@ -14,6 +14,17 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# +# Galera library does not compile with windows +# +IF(UNIX) + SET(with_wsrep_default ON) +ELSE() + SET(with_wsrep_default OFF) +ENDIF() + +OPTION(WITH_WSREP "WSREP replication API (to use, e.g. Galera Replication library)" ${with_wsrep_default}) + # Set the patch version SET(WSREP_PATCH_VERSION "10") @@ -32,42 +43,14 @@ IF (DEFINED ENV{WSREP_REV}) SET(WSREP_PATCH_REVNO $ENV{WSREP_REV}) ENDIF() -# Obtain wsrep API version -EXECUTE_PROCESS( - COMMAND sh -c "grep WSREP_INTERFACE_VERSION ${MySQL_SOURCE_DIR}/wsrep/wsrep_api.h | cut -d '\"' -f 2" - OUTPUT_VARIABLE WSREP_API_VERSION - RESULT_VARIABLE RESULT -) -#FILE(WRITE "wsrep_config" "Debug: WSREP_API_VERSION result: ${RESULT}\n") -STRING(REGEX REPLACE "(\r?\n)+$" "" WSREP_API_VERSION "${WSREP_API_VERSION}") +SET(WSREP_INTERFACE_VERSION 25) -IF(NOT WSREP_PATCH_REVNO) - MESSAGE(WARNING "Could not determine bzr revision number, WSREP_VERSION will " - "not contain the revision number.") - SET(WSREP_VERSION - "${WSREP_API_VERSION}.${WSREP_PATCH_VERSION}" - ) -ELSE() - SET(WSREP_VERSION - "${WSREP_API_VERSION}.${WSREP_PATCH_VERSION}.r${WSREP_PATCH_REVNO}" - ) -ENDIF() +SET(WSREP_VERSION + "${WSREP_INTERFACE_VERSION}.${WSREP_PATCH_VERSION}.r${WSREP_PATCH_REVNO}") -# -# Galera library does not compile with windows and solaris -# -IF(UNIX) -OPTION(WITH_WSREP "WSREP replication API (to use, e.g. Galera Replication library)" ON) -ELSE() -OPTION(WITH_WSREP "WSREP replication API (to use, e.g. Galera Replication library)" OFF) -ENDIF() +SET(WSREP_PROC_INFO ${WITH_WSREP}) -MACRO (BUILD_WITH_WSREP) - SET(WSREP_C_FLAGS "-DWITH_WSREP -DWSREP_PROC_INFO -DMYSQL_MAX_VARIABLE_VALUE_LEN=2048") - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WSREP_C_FLAGS}") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WSREP_C_FLAGS}") +IF(WITH_WSREP) SET(COMPILATION_COMMENT "${COMPILATION_COMMENT}, wsrep_${WSREP_VERSION}") - #SET(WITH_EMBEDDED_SERVER OFF CACHE INTERNAL "" FORCE) -ENDMACRO() +ENDIF() -# diff --git a/config.h.cmake b/config.h.cmake index f7a5451c9a8..57d53975ac7 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -642,6 +642,12 @@ #cmakedefine SIZEOF_TIME_T @SIZEOF_TIME_T@ #cmakedefine TIME_T_UNSIGNED @TIME_T_UNSIGNED@ +#ifndef EMBEDDED_LIBRARY +#cmakedefine WSREP_INTERFACE_VERSION "@WSREP_INTERFACE_VERSION@" +#cmakedefine WITH_WSREP 1 +#cmakedefine WSREP_PROC_INFO 1 +#endif + #ifdef _AIX /* AIX includes inttypes.h from sys/types.h diff --git a/debian/dist/Debian/control b/debian/dist/Debian/control index 5fd6b1eac16..4468917ca34 100644 --- a/debian/dist/Debian/control +++ b/debian/dist/Debian/control @@ -192,7 +192,11 @@ Architecture: any Suggests: tinyca, mailx, mariadb-test Recommends: libhtml-template-perl Pre-Depends: mariadb-common, adduser (>= 3.40), debconf -Depends: mariadb-client-10.1 (>= ${source:Version}), libdbi-perl, perl (>= 5.6), ${shlibs:Depends}, ${misc:Depends}, psmisc, passwd, lsb-base (>= 3.0-10), mariadb-server-core-10.1 (>= ${binary:Version}), galera (>=25.2), rsync, lsof, socat, grep, gawk, iproute, coreutils, findutils +Depends: mariadb-client-10.1 (>= ${source:Version}), libdbi-perl, + perl (>= 5.6), ${shlibs:Depends}, ${misc:Depends}, psmisc, passwd, + lsb-base (>= 3.0-10), mariadb-server-core-10.1 (>= ${binary:Version}), + galera (>=25.2), rsync, lsof, socat | netcat, grep, gawk, iproute, + coreutils, findutils Provides: mariadb-server, mysql-server, virtual-mysql-server Conflicts: mariadb-server (<< ${source:Version}), mysql-server (<< ${source:Version}), mysql-server-4.1, mysql-server-5.0, mysql-server-5.1, mysql-server-5.5, diff --git a/debian/dist/Ubuntu/control b/debian/dist/Ubuntu/control index c5f417d121b..698b81eae00 100644 --- a/debian/dist/Ubuntu/control +++ b/debian/dist/Ubuntu/control @@ -186,7 +186,11 @@ Architecture: any Suggests: tinyca, mailx, mariadb-test Recommends: libhtml-template-perl Pre-Depends: mariadb-common, adduser (>= 3.40), debconf -Depends: mariadb-client-10.1 (>= ${source:Version}), libdbi-perl, perl (>= 5.6), ${shlibs:Depends}, ${misc:Depends}, psmisc, passwd, lsb-base (>= 3.0-10), mariadb-server-core-10.1 (>= ${binary:Version}), galera (>=25.2), rsync, lsof, socat, grep, gawk, iproute, coreutils, findutils +Depends: mariadb-client-10.1 (>= ${source:Version}), libdbi-perl, + perl (>= 5.6), ${shlibs:Depends}, ${misc:Depends}, psmisc, passwd, + lsb-base (>= 3.0-10), mariadb-server-core-10.1 (>= ${binary:Version}), + galera (>=25.2), rsync, lsof, socat | netcat, grep, gawk, iproute, + coreutils, findutils Provides: mariadb-server, mysql-server, virtual-mysql-server Conflicts: mariadb-server (<< ${source:Version}), mysql-server (<< ${source:Version}), mysql-server-4.1, mysql-server-5.0, mysql-server-5.1, mysql-server-5.5, diff --git a/include/wsrep.h b/include/wsrep.h index 9e0f052b340..443806e4c64 100644 --- a/include/wsrep.h +++ b/include/wsrep.h @@ -13,8 +13,10 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include + #ifndef WSREP_INCLUDED -#define WSERP_INCLUDED +#define WSREP_INCLUDED #ifdef WITH_WSREP #define IF_WSREP(A,B) A diff --git a/mysql-test/include/have_wsrep_enabled.inc b/mysql-test/include/have_wsrep_enabled.inc index edb919fd852..439e13e1eb9 100644 --- a/mysql-test/include/have_wsrep_enabled.inc +++ b/mysql-test/include/have_wsrep_enabled.inc @@ -3,7 +3,7 @@ --source include/have_wsrep.inc ---require r/have_wsrep.require -disable_query_log; -SHOW VARIABLES LIKE 'wsrep_on'; -enable_query_log; +if (`SELECT COUNT(*)=0 FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME = 'wsrep_on' AND VARIABLE_VALUE='ON'`) +{ + --skip Test requires wsrep_on=ON +} diff --git a/mysql-test/include/write_result_to_file.inc b/mysql-test/include/write_result_to_file.inc index db5d546750c..3e2ddf48957 100644 --- a/mysql-test/include/write_result_to_file.inc +++ b/mysql-test/include/write_result_to_file.inc @@ -33,8 +33,7 @@ --let _WRTF_SERVER_NUMBER= $server_number if (!$server_number) { - # Note: 2 extra ports are reserved per server for galera use. - --let _WRTF_SERVER_NUMBER= `SELECT 1 + FLOOR((@@PORT - $MASTER_MYPORT) / 3)` + --let _WRTF_SERVER_NUMBER= `SELECT 1 + @@PORT - $MASTER_MYPORT` } --let $_write_result_msg= [server=$_WRTF_SERVER_NUMBER] diff --git a/mysql-test/lib/My/ConfigFactory.pm b/mysql-test/lib/My/ConfigFactory.pm index 488b0823763..4e8507a5c4a 100644 --- a/mysql-test/lib/My/ConfigFactory.pm +++ b/mysql-test/lib/My/ConfigFactory.pm @@ -238,9 +238,6 @@ my @mysqld_rules= { 'pid-file' => \&fix_pidfile }, { '#host' => \&fix_host }, { 'port' => \&fix_port }, - # galera base_port and port used during SST - { '#galera_port' => \&fix_port }, - { '#sst_port' => \&fix_port }, { 'socket' => \&fix_socket }, { '#log-error' => \&fix_log_error }, { 'general-log' => 1 }, diff --git a/mysql-test/r/have_wsrep.require b/mysql-test/r/have_wsrep.require deleted file mode 100644 index af32ac7dca7..00000000000 --- a/mysql-test/r/have_wsrep.require +++ /dev/null @@ -1,2 +0,0 @@ -Variable_name Value -wsrep_on ON diff --git a/mysql-test/suite/galera/galera_2nodes.cnf b/mysql-test/suite/galera/galera_2nodes.cnf index c0d5b3add3f..024ced1d20b 100644 --- a/mysql-test/suite/galera/galera_2nodes.cnf +++ b/mysql-test/suite/galera/galera_2nodes.cnf @@ -3,6 +3,8 @@ [mysqld.1] binlog-format=row +#galera_port=OPT.port +#sst_port=OPT.port wsrep_provider=@ENV.WSREP_PROVIDER wsrep_cluster_address='gcomm://' wsrep_provider_options='base_port=@mysqld.1.#galera_port' @@ -12,6 +14,8 @@ wsrep_causal_reads=ON [mysqld.2] binlog-format=row +#galera_port=OPT.port +#sst_port=OPT.port wsrep_provider=@ENV.WSREP_PROVIDER wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port' wsrep_provider_options='base_port=@mysqld.2.#galera_port' diff --git a/mysql-test/suite/roles/set_default_role_for.result b/mysql-test/suite/roles/set_default_role_for.result index 3e444a5f537..7289319a428 100644 --- a/mysql-test/suite/roles/set_default_role_for.result +++ b/mysql-test/suite/roles/set_default_role_for.result @@ -21,17 +21,17 @@ Grants for user_a@localhost GRANT role_a TO 'user_a'@'localhost' GRANT USAGE ON *.* TO 'user_a'@'localhost' GRANT SELECT ON *.* TO 'role_a' -select user, host, default_role from mysql.user where user like 'user_%' order by user; +select user, host, default_role from mysql.user where user like 'user_%'; user host default_role user_a localhost role_a user_b localhost role_b set default role NONE for current_user; -select user, host, default_role from mysql.user where user like 'user_%' order by user; +select user, host, default_role from mysql.user where user like 'user_%'; user host default_role user_a localhost user_b localhost role_b set default role current_role for current_user; -select user, host, default_role from mysql.user where user like 'user_%' order by user; +select user, host, default_role from mysql.user where user like 'user_%'; user host default_role user_a localhost role_a user_b localhost role_b @@ -42,7 +42,7 @@ Grants for user_b@localhost GRANT role_b TO 'user_b'@'localhost' GRANT USAGE ON *.* TO 'user_b'@'localhost' GRANT INSERT, UPDATE ON *.* TO 'role_b' -select user, host, default_role from mysql.user where user like 'user_%' order by user; +select user, host, default_role from mysql.user where user like 'user_%'; ERROR 42000: SELECT command denied to user 'user_b'@'localhost' for table 'user' insert into mysql.user (user, host) values ('someuser', 'somehost'); Warnings: @@ -56,10 +56,10 @@ Grants for user_a@localhost GRANT role_a TO 'user_a'@'localhost' GRANT USAGE ON *.* TO 'user_a'@'localhost' GRANT INSERT, UPDATE ON *.* TO 'role_b' -select user, host, default_role from mysql.user where user like 'user_%' order by user; +select user, host, default_role from mysql.user where user like 'user_%'; ERROR 42000: SELECT command denied to user 'user_a'@'localhost' for table 'user' drop role role_a; drop role role_b; -delete from mysql.user where user = 'someuser' && host = 'somehost' order by user; +delete from mysql.user where user = 'someuser' && host = 'somehost'; drop user user_a@localhost; drop user user_b@localhost; diff --git a/mysql-test/suite/roles/set_default_role_for.test b/mysql-test/suite/roles/set_default_role_for.test index 2e798b49733..d7a3372ae23 100644 --- a/mysql-test/suite/roles/set_default_role_for.test +++ b/mysql-test/suite/roles/set_default_role_for.test @@ -44,13 +44,13 @@ set default role role_b for user_b@localhost; change_user 'user_a'; show grants; -select user, host, default_role from mysql.user where user like 'user_%' order by user; +select user, host, default_role from mysql.user where user like 'user_%'; set default role NONE for current_user; -select user, host, default_role from mysql.user where user like 'user_%' order by user; +select user, host, default_role from mysql.user where user like 'user_%'; set default role current_role for current_user; -select user, host, default_role from mysql.user where user like 'user_%' order by user; +select user, host, default_role from mysql.user where user like 'user_%'; # Make sure we can't set a default role not granted to us, using current_user --error ER_INVALID_ROLE @@ -60,7 +60,7 @@ change_user 'user_b'; show grants; --error ER_TABLEACCESS_DENIED_ERROR -select user, host, default_role from mysql.user where user like 'user_%' order by user; +select user, host, default_role from mysql.user where user like 'user_%'; # Make sure the default role setting worked from root. insert into mysql.user (user, host) values ('someuser', 'somehost'); @@ -73,12 +73,12 @@ change_user 'user_a'; # There is no default role set any more. show grants; --error ER_TABLEACCESS_DENIED_ERROR -select user, host, default_role from mysql.user where user like 'user_%' order by user; +select user, host, default_role from mysql.user where user like 'user_%'; change_user 'root'; drop role role_a; drop role role_b; -delete from mysql.user where user = 'someuser' && host = 'somehost' order by user; +delete from mysql.user where user = 'someuser' && host = 'somehost'; drop user user_a@localhost; drop user user_b@localhost; diff --git a/mysql-test/t/mysql_tzinfo_to_sql_symlink.test b/mysql-test/t/mysql_tzinfo_to_sql_symlink.test index 0c70315c93b..13a4eaaf605 100644 --- a/mysql-test/t/mysql_tzinfo_to_sql_symlink.test +++ b/mysql-test/t/mysql_tzinfo_to_sql_symlink.test @@ -7,11 +7,6 @@ # the updated result. (lp:1161432) --source include/not_wsrep.inc -# Note: The output of mysql_tzinfo_to_sql is different if server is compiled -# with wsrep. Hence a copy of this test has been placed under wsrep suite with -# the updated result. (lp:1161432) ---source include/not_wsrep.inc - --echo # --echo # MDEV-5226 mysql_tzinfo_to_sql errors with tzdata 2013f and above --echo # diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index e342427c737..f0d25dae6b9 100644 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -15,10 +15,6 @@ INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/mysys) -IF(WITH_WSREP) - BUILD_WITH_WSREP() -ENDIF() - SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c my_default.c errors.c hash.c list.c mf_cache.c mf_dirname.c mf_fn_ext.c diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 803e14988d2..b02389ccc17 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -15,7 +15,6 @@ IF(WITH_WSREP AND NOT EMBEDDED_LIBRARY) - BUILD_WITH_WSREP() SET(WSREP_INCLUDES ${CMAKE_SOURCE_DIR}/wsrep) SET(WSREP_SOURCES wsrep_check_opts.cc diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc index 26d2e1ef985..bf824a98310 100644 --- a/sql/event_data_objects.cc +++ b/sql/event_data_objects.cc @@ -1472,19 +1472,11 @@ end: bool save_tx_read_only= thd->tx_read_only; thd->tx_read_only= false; -#ifdef WITH_WSREP if (WSREP(thd)) { - // sql_print_information("sizeof(LEX) = %d", sizeof(struct LEX)); - // sizeof(LEX) = 4512, so it's relatively safe to allocate it on stack. - LEX lex; - LEX* saved = thd->lex; - lex.sql_command = SQLCOM_DROP_EVENT; - thd->lex = &lex; + thd->lex->sql_command = SQLCOM_DROP_EVENT; WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); - thd->lex = saved; } -#endif ret= Events::drop_event(thd, dbname, name, FALSE); diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 15cbb03978e..da7f3aeff89 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -388,15 +388,6 @@ const char *ha_partition::table_type() const } -#if defined(WITH_WSREP) && !defined(EMBEDDED_LIBRARY) -int ha_partition::wsrep_db_type() const -{ - // we can do this since we only support a single engine type - return partition_ht()->db_type; -} -#endif /* WITH_WSREP && !EMBEDDED_LIBRARY */ - - /* Destructor method diff --git a/sql/ha_partition.h b/sql/ha_partition.h index c3c72394374..07a0b0de145 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -1282,9 +1282,6 @@ public: DBUG_ASSERT(h == m_file[i]->ht); return h; } -#if defined(WITH_WSREP) && !defined(EMBEDDED_LIBRARY) - virtual int wsrep_db_type() const; -#endif /* WITH_WSREP && !EMBEDDED_LIBRARY */ friend int cmp_key_rowid_part_id(void *ptr, uchar *ref1, uchar *ref2); }; diff --git a/sql/handler.cc b/sql/handler.cc index 253883cc114..68762061053 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1384,7 +1384,7 @@ int ha_commit_trans(THD *thd, bool all) mdl_request.init(MDL_key::COMMIT, "", "", MDL_INTENTION_EXCLUSIVE, MDL_EXPLICIT); - if (IF_WSREP(!WSREP(thd),1) && + if (!WSREP(thd) && thd->mdl_context.acquire_lock(&mdl_request, thd->variables.lock_wait_timeout)) { @@ -1462,13 +1462,11 @@ int ha_commit_trans(THD *thd, bool all) DEBUG_SYNC(thd, "ha_commit_trans_after_prepare"); DBUG_EXECUTE_IF("crash_commit_after_prepare", DBUG_SUICIDE();); -#ifdef WITH_WSREP if (!error && WSREP_ON && wsrep_is_wsrep_xid(&thd->transaction.xid_state.xid)) { // xid was rewritten by wsrep xid= wsrep_xid_seqno(&thd->transaction.xid_state.xid); } -#endif // WITH_WSREP if (!is_real_trans) { @@ -1846,10 +1844,9 @@ static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin, got, hton_name(hton)->str); for (int i=0; i < got; i ++) { - my_xid x= IF_WSREP(WSREP_ON && wsrep_is_wsrep_xid(&info->list[i]) ? + my_xid x= WSREP_ON && wsrep_is_wsrep_xid(&info->list[i]) ? wsrep_xid_seqno(&info->list[i]) : - info->list[i].get_my_xid(), - info->list[i].get_my_xid()); + info->list[i].get_my_xid(); if (!x) // not "mine" - that is generated by external TM { #ifndef DBUG_OFF @@ -3134,7 +3131,7 @@ int handler::update_auto_increment() variables->auto_increment_increment); auto_inc_intervals_count++; /* Row-based replication does not need to store intervals in binlog */ - if (IF_WSREP(((WSREP(thd) && wsrep_emulate_bin_log ) || mysql_bin_log.is_open()), mysql_bin_log.is_open()) + if (((WSREP(thd) && wsrep_emulate_bin_log ) || mysql_bin_log.is_open()) && !thd->is_current_stmt_binlog_format_row()) thd->auto_inc_intervals_in_cur_stmt_for_binlog. append(auto_inc_interval_for_cur_row.minimum(), @@ -5754,13 +5751,13 @@ static bool check_table_binlog_row_based(THD *thd, TABLE *table) DBUG_ASSERT(table->s->cached_row_logging_check == 0 || table->s->cached_row_logging_check == 1); - return (thd->is_current_stmt_binlog_format_row() && + return thd->is_current_stmt_binlog_format_row() && table->s->cached_row_logging_check && (thd->variables.option_bits & OPTION_BIN_LOG) && /* applier and replayer should not binlog */ - (IF_WSREP((WSREP_EMULATE_BINLOG(thd) && - (thd->wsrep_exec_mode != REPL_RECV)) || - mysql_bin_log.is_open(), mysql_bin_log.is_open()))); + ((IF_WSREP(WSREP_EMULATE_BINLOG(thd) && + thd->wsrep_exec_mode != REPL_RECV, 0)) || + mysql_bin_log.is_open()); } @@ -5860,12 +5857,11 @@ static int binlog_log_row(TABLE* table, bool error= 0; THD *const thd= table->in_use; -#ifdef WITH_WSREP /* only InnoDB tables will be replicated through binlog emulation */ if (WSREP_EMULATE_BINLOG(thd) && table->file->partition_ht()->db_type != DB_TYPE_INNODB) return 0; -#endif /* WITH_WSREP */ + if (check_table_binlog_row_based(thd, table)) { MY_BITMAP cols; @@ -6226,11 +6222,9 @@ int ha_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal) { handlerton *hton= ha_info->ht(); if (!hton->abort_transaction) - { - WSREP_WARN("cannot abort transaction"); - } + WSREP_WARN("cannot abort transaction"); else - hton->abort_transaction(hton, bf_thd, victim_thd, signal); + hton->abort_transaction(hton, bf_thd, victim_thd, signal); ha_info_next= ha_info->next(); ha_info->reset(); /* keep it conveniently zero-filled */ } diff --git a/sql/handler.h b/sql/handler.h index 169ed209403..703d1c615b3 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -3967,9 +3967,6 @@ bool key_uses_partial_cols(TABLE_SHARE *table, uint keyno); extern const char *ha_row_type[]; extern MYSQL_PLUGIN_IMPORT const char *tx_isolation_names[]; extern MYSQL_PLUGIN_IMPORT const char *binlog_format_names[]; -#ifdef WITH_WSREP -extern MYSQL_PLUGIN_IMPORT const char *wsrep_binlog_format_names[]; -#endif /* WITH_WSREP */ extern TYPELIB tx_isolation_typelib; extern const char *myisam_stats_method_names[]; extern ulong total_ha, total_ha_2pc; @@ -4091,7 +4088,9 @@ int ha_release_savepoint(THD *thd, SAVEPOINT *sv); #ifdef WITH_WSREP int ha_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal); void ha_fake_trx_id(THD *thd); -#endif /* WITH_WSREP */ +#else +inline void ha_fake_trx_id(THD *thd) { } +#endif /* these are called by storage engines */ void trans_register_ha(THD *thd, bool all, handlerton *ht); @@ -4122,9 +4121,6 @@ int ha_binlog_end(THD *thd); #define ha_binlog_wait(a) do {} while (0) #define ha_binlog_end(a) do {} while (0) #endif -#ifdef WITH_WSREP -void wsrep_brute_force_aborts(); -#endif const char *get_canonical_filename(handler *file, const char *path, char *tmp_path); diff --git a/sql/item_func.cc b/sql/item_func.cc index 13803cff2d6..2b89aa04295 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2771,12 +2771,13 @@ void Item_func_rand::seed_random(Item *arg) */ uint32 tmp; #ifdef WITH_WSREP - if (WSREP(current_thd)) + THD *thd= current_thd; + if (WSREP(thd)) { - if (current_thd->wsrep_exec_mode==REPL_RECV) - tmp= current_thd->wsrep_rand; + if (thd->wsrep_exec_mode==REPL_RECV) + tmp= thd->wsrep_rand; else - tmp= current_thd->wsrep_rand= (uint32) arg->val_int(); + tmp= thd->wsrep_rand= (uint32) arg->val_int(); } else #endif /* WITH_WSREP */ diff --git a/sql/log.cc b/sql/log.cc index 4f80b38e497..9c6de086a13 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -52,7 +52,6 @@ #include "sql_plugin.h" #include "rpl_handler.h" -#include "wsrep_mysqld.h" #include "debug_sync.h" #include "sql_show.h" #include "my_pthread.h" @@ -1577,8 +1576,7 @@ binlog_trans_log_savepos(THD *thd, my_off_t *pos) DBUG_ENTER("binlog_trans_log_savepos"); DBUG_ASSERT(pos != NULL); binlog_cache_mngr *const cache_mngr= thd->binlog_setup_trx_data(); - DBUG_ASSERT_IF_WSREP(((WSREP(thd) && wsrep_emulate_bin_log)) || mysql_bin_log.is_open()); - DBUG_ASSERT(IF_WSREP(1, mysql_bin_log.is_open())); + DBUG_ASSERT((WSREP(thd) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()); *pos= cache_mngr->trx_cache.get_byte_position(); DBUG_PRINT("return", ("*pos: %lu", (ulong) *pos)); DBUG_VOID_RETURN; @@ -1626,8 +1624,8 @@ binlog_trans_log_truncate(THD *thd, my_off_t pos) int binlog_init(void *p) { binlog_hton= (handlerton *)p; - binlog_hton->state=IF_WSREP(WSREP_ON || opt_bin_log, opt_bin_log) ? - SHOW_OPTION_YES : SHOW_OPTION_NO; + binlog_hton->state= (WSREP_ON || opt_bin_log) ? SHOW_OPTION_YES + : SHOW_OPTION_NO; binlog_hton->db_type=DB_TYPE_BINLOG; binlog_hton->savepoint_offset= sizeof(my_off_t); binlog_hton->close_connection= binlog_close_connection; @@ -1939,13 +1937,12 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all) DBUG_ENTER("binlog_commit"); binlog_cache_mngr *const cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); -#ifdef WITH_WSREP + if (!cache_mngr) { DBUG_ASSERT(WSREP(thd)); DBUG_RETURN(0); } -#endif /* WITH_WSREP */ DBUG_PRINT("debug", ("all: %d, in_transaction: %s, all.modified_non_trans_table: %s, stmt.modified_non_trans_table: %s", @@ -2002,15 +1999,13 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) int error= 0; binlog_cache_mngr *const cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); -#ifdef WITH_WSREP + if (!cache_mngr) { DBUG_ASSERT(WSREP(thd)); DBUG_RETURN(0); } -#endif /* WITH_WSREP */ - DBUG_PRINT("debug", ("all: %s, all.modified_non_trans_table: %s, stmt.modified_non_trans_table: %s", YESNO(all), YESNO(thd->transaction.all.modified_non_trans_table), @@ -2038,8 +2033,7 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) cache_mngr->reset(false, true); DBUG_RETURN(error); } - if (IF_WSREP(!wsrep_emulate_bin_log,1) && - mysql_bin_log.check_write_error(thd)) + if (!wsrep_emulate_bin_log && mysql_bin_log.check_write_error(thd)) { /* "all == true" means that a "rollback statement" triggered the error and @@ -2180,10 +2174,8 @@ static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv) int error= 1; DBUG_ENTER("binlog_savepoint_set"); -#ifdef WITH_WSREP if (wsrep_emulate_bin_log) DBUG_RETURN(0); -#endif /* WITH_WSREP */ char buf[1024]; String log_query(buf, sizeof(buf), &my_charset_bin); @@ -2222,7 +2214,7 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) non-transactional table. Otherwise, truncate the binlog cache starting from the SAVEPOINT command. */ - if (IF_WSREP(!wsrep_emulate_bin_log, 1) && + if (!wsrep_emulate_bin_log && unlikely(trans_has_updated_non_trans_table(thd) || (thd->variables.option_bits & OPTION_KEEP_LOG))) { @@ -2238,7 +2230,7 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) DBUG_RETURN(mysql_bin_log.write(&qinfo)); } - if (IF_WSREP(!wsrep_emulate_bin_log, 1)) + if (!wsrep_emulate_bin_log) binlog_trans_log_truncate(thd, *(my_off_t*)sv); DBUG_RETURN(0); @@ -5369,7 +5361,7 @@ int THD::binlog_write_table_map(TABLE *table, bool is_transactional, /* Pre-conditions */ DBUG_ASSERT(is_current_stmt_binlog_format_row()); - DBUG_ASSERT(IF_WSREP(WSREP_EMULATE_BINLOG(this), 0) || mysql_bin_log.is_open()); + DBUG_ASSERT(WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open()); DBUG_ASSERT(table->s->table_map_id != ULONG_MAX); Table_map_log_event @@ -5502,7 +5494,7 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd, bool is_transactional) { DBUG_ENTER("MYSQL_BIN_LOG::flush_and_set_pending_rows_event(event)"); - DBUG_ASSERT(IF_WSREP(WSREP_EMULATE_BINLOG(thd),0) || mysql_bin_log.is_open()); + DBUG_ASSERT(WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()); DBUG_PRINT("enter", ("event: 0x%lx", (long) event)); int error= 0; @@ -5829,7 +5821,8 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate) could have changed since. */ /* applier and replayer can skip writing binlog events */ - if (IF_WSREP((WSREP_EMULATE_BINLOG(thd) && (thd->wsrep_exec_mode != REPL_RECV)) || is_open(), likely(is_open()))) + if ((WSREP_EMULATE_BINLOG(thd) && + IF_WSREP(thd->wsrep_exec_mode != REPL_RECV, 0)) || is_open()) { my_off_t UNINIT_VAR(my_org_b_tell); #ifdef HAVE_REPLICATION @@ -6168,7 +6161,6 @@ int MYSQL_BIN_LOG::rotate(bool force_rotate, bool* check_purge) int error= 0; DBUG_ENTER("MYSQL_BIN_LOG::rotate"); -#ifdef WITH_WSREP if (wsrep_to_isolation) { DBUG_ASSERT(WSREP_ON); @@ -6177,7 +6169,6 @@ int MYSQL_BIN_LOG::rotate(bool force_rotate, bool* check_purge) wsrep_to_isolation); DBUG_RETURN(0); } -#endif //todo: fix the macro def and restore safe_mutex_assert_owner(&LOCK_log); *check_purge= false; @@ -6724,10 +6715,8 @@ MYSQL_BIN_LOG::write_transaction_to_binlog(THD *thd, Ha_trx_info *ha_info; DBUG_ENTER("MYSQL_BIN_LOG::write_transaction_to_binlog"); -#ifdef WITH_WSREP if (wsrep_emulate_bin_log) DBUG_RETURN(0); -#endif /* WITH_WSREP */ entry.thd= thd; entry.cache_mngr= cache_mngr; diff --git a/sql/log_event.cc b/sql/log_event.cc index c19faf21647..ee35acadd9b 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -10812,7 +10812,7 @@ check_table_map(rpl_group_info *rgi, RPL_TABLE_LIST *table_list) DBUG_ENTER("check_table_map"); enum_tbl_map_status res= OK_TO_PROCESS; Relay_log_info *rli= rgi->rli; - if ((rgi->thd->slave_thread /* filtering is for slave only */ || + if ((rgi->thd->slave_thread /* filtering is for slave only */ || IF_WSREP((WSREP(rgi->thd) && rgi->thd->wsrep_applier), 0)) && (!rli->mi->rpl_filter->db_ok(table_list->db) || (rli->mi->rpl_filter->is_on() && !rli->mi->rpl_filter->tables_ok("", table_list)))) diff --git a/sql/mdl.cc b/sql/mdl.cc index 07130b4d002..15428c96d73 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -1939,11 +1939,10 @@ MDL_lock::can_grant_lock(enum_mdl_type type_arg, #endif /* WITH_WSREP */ } } - if ((ticket == NULL) && IF_WSREP(wsrep_can_grant, 1)) + if ((ticket == NULL) && wsrep_can_grant) can_grant= TRUE; /* Incompatible locks are our own. */ } } -#ifdef WITH_WSREP else { if (wsrep_thd_is_BF((void *)(requestor_ctx->get_thd()), false) && @@ -1955,7 +1954,6 @@ MDL_lock::can_grant_lock(enum_mdl_type type_arg, can_grant = true; } } -#endif /* WITH_WSREP */ return can_grant; } @@ -3310,7 +3308,6 @@ void MDL_context::set_transaction_duration_for_all_locks() } -#ifdef WITH_WSREP void MDL_context::release_explicit_locks() { @@ -3318,6 +3315,7 @@ void MDL_context::release_explicit_locks() } +#ifdef WITH_WSREP void MDL_ticket::wsrep_report(bool debug) { if (debug) diff --git a/sql/mdl.h b/sql/mdl.h index 231f95d7419..27289e621ef 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -793,9 +793,7 @@ public: void release_statement_locks(); void release_transactional_locks(); -#ifdef WITH_WSREP void release_explicit_locks(); -#endif void rollback_to_savepoint(const MDL_savepoint &mdl_savepoint); MDL_context_owner *get_owner() { return m_owner; } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 0794d7fee61..f842c835f24 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -738,27 +738,6 @@ mysql_cond_t COND_server_started; int mysqld_server_started=0, mysqld_server_initialized= 0; File_parser_dummy_hook file_parser_dummy_hook; -#ifdef WITH_WSREP -mysql_mutex_t LOCK_wsrep_ready; -mysql_cond_t COND_wsrep_ready; -mysql_mutex_t LOCK_wsrep_sst; -mysql_cond_t COND_wsrep_sst; -mysql_mutex_t LOCK_wsrep_sst_init; -mysql_cond_t COND_wsrep_sst_init; -mysql_mutex_t LOCK_wsrep_rollback; -mysql_cond_t COND_wsrep_rollback; -wsrep_aborting_thd_t wsrep_aborting_thd= NULL; -mysql_mutex_t LOCK_wsrep_replaying; -mysql_cond_t COND_wsrep_replaying; -mysql_mutex_t LOCK_wsrep_slave_threads; -mysql_mutex_t LOCK_wsrep_desync; -int wsrep_replaying= 0; -ulong wsrep_running_threads = 0; // # of currently running wsrep threads -ulong my_bind_addr; -const char *wsrep_binlog_format_names[]= - {"MIXED", "STATEMENT", "ROW", "NONE", NullS}; -#endif /* WITH_WSREP */ - /* replication parameters, if master_host is not NULL, we are a slave */ uint report_port= 0; ulong master_retry_count=0; @@ -896,12 +875,6 @@ PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list, key_LOCK_error_messages, key_LOG_INFO_lock, key_LOCK_thread_count, key_LOCK_thread_cache, key_PARTITION_LOCK_auto_inc; -#ifdef WITH_WSREP -PSI_mutex_key key_LOCK_wsrep_rollback, key_LOCK_wsrep_thd, - key_LOCK_wsrep_replaying, key_LOCK_wsrep_ready, key_LOCK_wsrep_sst, - key_LOCK_wsrep_sst_thread, key_LOCK_wsrep_sst_init, - key_LOCK_wsrep_slave_threads, key_LOCK_wsrep_desync; -#endif PSI_mutex_key key_RELAYLOG_LOCK_index; PSI_mutex_key key_LOCK_slave_state, key_LOCK_binlog_state, key_LOCK_rpl_thread, key_LOCK_rpl_thread_pool, key_LOCK_parallel_entry; @@ -976,18 +949,6 @@ static PSI_mutex_info all_server_mutexes[]= { &key_LOCK_prepare_ordered, "LOCK_prepare_ordered", PSI_FLAG_GLOBAL}, { &key_LOCK_commit_ordered, "LOCK_commit_ordered", PSI_FLAG_GLOBAL}, { &key_LOG_INFO_lock, "LOG_INFO::lock", 0}, -#ifdef WITH_WSREP - { &key_LOCK_wsrep_ready, "LOCK_wsrep_ready", PSI_FLAG_GLOBAL}, - { &key_LOCK_wsrep_sst, "LOCK_wsrep_sst", PSI_FLAG_GLOBAL}, - { &key_LOCK_wsrep_sst_thread, "wsrep_sst_thread", 0}, - { &key_LOCK_wsrep_sst_init, "LOCK_wsrep_sst_init", PSI_FLAG_GLOBAL}, - { &key_LOCK_wsrep_sst, "LOCK_wsrep_sst", PSI_FLAG_GLOBAL}, - { &key_LOCK_wsrep_rollback, "LOCK_wsrep_rollback", PSI_FLAG_GLOBAL}, - { &key_LOCK_wsrep_thd, "THD::LOCK_wsrep_thd", 0}, - { &key_LOCK_wsrep_replaying, "LOCK_wsrep_replaying", PSI_FLAG_GLOBAL}, - { &key_LOCK_wsrep_slave_threads, "LOCK_wsrep_slave_threads", PSI_FLAG_GLOBAL}, - { &key_LOCK_wsrep_desync, "LOCK_wsrep_desync", PSI_FLAG_GLOBAL}, -#endif { &key_LOCK_thread_count, "LOCK_thread_count", PSI_FLAG_GLOBAL}, { &key_LOCK_thread_cache, "LOCK_thread_cache", PSI_FLAG_GLOBAL}, { &key_PARTITION_LOCK_auto_inc, "HA_DATA_PARTITION::LOCK_auto_inc", 0}, @@ -1034,11 +995,6 @@ PSI_cond_key key_BINLOG_COND_xid_list, key_BINLOG_update_cond, key_TABLE_SHARE_cond, key_user_level_lock_cond, key_COND_thread_count, key_COND_thread_cache, key_COND_flush_thread_cache, key_BINLOG_COND_queue_busy; -#ifdef WITH_WSREP -PSI_cond_key key_COND_wsrep_rollback, key_COND_wsrep_thd, - key_COND_wsrep_replaying, key_COND_wsrep_ready, key_COND_wsrep_sst, - key_COND_wsrep_sst_init, key_COND_wsrep_sst_thread; -#endif /* WITH_WSREP */ PSI_cond_key key_RELAYLOG_update_cond, key_COND_wakeup_ready, key_COND_wait_commit; PSI_cond_key key_RELAYLOG_COND_queue_busy; @@ -1088,15 +1044,6 @@ static PSI_cond_info all_server_conds[]= { &key_user_level_lock_cond, "User_level_lock::cond", 0}, { &key_COND_thread_count, "COND_thread_count", PSI_FLAG_GLOBAL}, { &key_COND_thread_cache, "COND_thread_cache", PSI_FLAG_GLOBAL}, -#ifdef WITH_WSREP - { &key_COND_wsrep_ready, "COND_wsrep_ready", PSI_FLAG_GLOBAL}, - { &key_COND_wsrep_sst, "COND_wsrep_sst", PSI_FLAG_GLOBAL}, - { &key_COND_wsrep_sst_init, "COND_wsrep_sst_init", PSI_FLAG_GLOBAL}, - { &key_COND_wsrep_sst_thread, "wsrep_sst_thread", 0}, - { &key_COND_wsrep_rollback, "COND_wsrep_rollback", PSI_FLAG_GLOBAL}, - { &key_COND_wsrep_thd, "THD::COND_wsrep_thd", 0}, - { &key_COND_wsrep_replaying, "COND_wsrep_replaying", PSI_FLAG_GLOBAL}, -#endif { &key_COND_flush_thread_cache, "COND_flush_thread_cache", PSI_FLAG_GLOBAL}, { &key_COND_rpl_thread, "COND_rpl_thread", 0}, { &key_COND_rpl_thread_queue, "COND_rpl_thread_queue", 0}, @@ -1945,17 +1892,13 @@ static void __cdecl kill_server(int sig_ptr) } #endif -#ifdef WITH_WSREP if (WSREP_ON) wsrep_stop_replication(NULL); -#endif close_connections(); -#ifdef WITH_WSREP if (wsrep_inited == 1) wsrep_deinit(true); -#endif if (sig != MYSQL_KILL_SIGNAL && sig != 0) @@ -2062,10 +2005,9 @@ extern "C" void unireg_abort(int exit_code) */ wsrep_close_client_connections(FALSE); shutdown_in_progress= 1; - THD *thd(0); wsrep->disconnect(wsrep); WSREP_INFO("Service disconnected."); - wsrep_close_threads(thd); /* this won't close all threads */ + wsrep_close_threads(NULL); /* this won't close all threads */ sleep(1); /* so give some time to exit for those which can */ WSREP_INFO("Some threads may fail to exit."); @@ -2294,20 +2236,6 @@ static void clean_up_mutexes() mysql_cond_destroy(&COND_thread_count); mysql_cond_destroy(&COND_thread_cache); mysql_cond_destroy(&COND_flush_thread_cache); -#ifdef WITH_WSREP - (void) mysql_mutex_destroy(&LOCK_wsrep_ready); - (void) mysql_cond_destroy(&COND_wsrep_ready); - (void) mysql_mutex_destroy(&LOCK_wsrep_sst); - (void) mysql_cond_destroy(&COND_wsrep_sst); - (void) mysql_mutex_destroy(&LOCK_wsrep_sst_init); - (void) mysql_cond_destroy(&COND_wsrep_sst_init); - (void) mysql_mutex_destroy(&LOCK_wsrep_rollback); - (void) mysql_cond_destroy(&COND_wsrep_rollback); - (void) mysql_mutex_destroy(&LOCK_wsrep_replaying); - (void) mysql_cond_destroy(&COND_wsrep_replaying); - (void) mysql_mutex_destroy(&LOCK_wsrep_slave_threads); - (void) mysql_mutex_destroy(&LOCK_wsrep_desync); -#endif mysql_mutex_destroy(&LOCK_server_started); mysql_cond_destroy(&COND_server_started); mysql_mutex_destroy(&LOCK_prepare_ordered); @@ -2321,7 +2249,12 @@ static void clean_up_mutexes() ** Init IP and UNIX socket ****************************************************************************/ -#ifndef EMBEDDED_LIBRARY +#ifdef EMBEDDED_LIBRARY +static void set_ports() +{ +} + +#else static void set_ports() { char *env; @@ -2623,10 +2556,10 @@ static MYSQL_SOCKET activate_tcp_port(uint port) socket_errno); unireg_abort(1); } -#if defined(WITH_WSREP) && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) - if (WSREP_ON) - (void) fcntl(mysql_socket_getfd(ip_sock), F_SETFD, FD_CLOEXEC); -#endif /* WITH_WSREP */ + +#ifdef FD_CLOEXEC + (void) fcntl(mysql_socket_getfd(ip_sock), F_SETFD, FD_CLOEXEC); +#endif DBUG_RETURN(ip_sock); } @@ -2754,10 +2687,9 @@ static void network_init(void) if (mysql_socket_listen(unix_sock,(int) back_log) < 0) sql_print_warning("listen() on Unix socket failed with error %d", socket_errno); -#if defined(WITH_WSREP) && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) - if (WSREP_ON) - (void) fcntl(mysql_socket_getfd(unix_sock), F_SETFD, FD_CLOEXEC); -#endif /* WITH_WSREP */ +#ifdef FD_CLOEXEC + (void) fcntl(mysql_socket_getfd(unix_sock), F_SETFD, FD_CLOEXEC); +#endif } #endif DBUG_PRINT("info",("server started")); @@ -3012,15 +2944,13 @@ static bool cache_thread() bool one_thread_per_connection_end(THD *thd, bool put_in_cache) { DBUG_ENTER("one_thread_per_connection_end"); -#ifdef WITH_WSREP - const bool wsrep_applier(thd->wsrep_applier); -#endif + const bool wsrep_applier= IF_WSREP(thd->wsrep_applier, false); unlink_thd(thd); /* Mark that current_thd is not valid anymore */ set_current_thd(0); - if (put_in_cache && cache_thread() && IF_WSREP(!wsrep_applier, 1)) + if (put_in_cache && cache_thread() && !wsrep_applier) DBUG_RETURN(0); // Thread is reused /* @@ -4145,7 +4075,7 @@ static int init_common_variables() opt_log_basename= glob_hostname; #ifdef WITH_WSREP - if (0 == wsrep_node_name || 0 == wsrep_node_name[0]) + if (wsrep_node_name == 0 || wsrep_node_name[0] == 0) { my_free((void *)wsrep_node_name); wsrep_node_name= my_strdup(glob_hostname, MYF(MY_WME)); @@ -4616,28 +4546,6 @@ static int init_thread_environment() rpl_init_gtid_waiting(); #endif -#ifdef WITH_WSREP - mysql_mutex_init(key_LOCK_wsrep_ready, - &LOCK_wsrep_ready, MY_MUTEX_INIT_FAST); - mysql_cond_init(key_COND_wsrep_ready, &COND_wsrep_ready, NULL); - mysql_mutex_init(key_LOCK_wsrep_sst, - &LOCK_wsrep_sst, MY_MUTEX_INIT_FAST); - mysql_cond_init(key_COND_wsrep_sst, &COND_wsrep_sst, NULL); - mysql_mutex_init(key_LOCK_wsrep_sst_init, - &LOCK_wsrep_sst_init, MY_MUTEX_INIT_FAST); - mysql_cond_init(key_COND_wsrep_sst_init, &COND_wsrep_sst_init, NULL); - mysql_mutex_init(key_LOCK_wsrep_rollback, - &LOCK_wsrep_rollback, MY_MUTEX_INIT_FAST); - mysql_cond_init(key_COND_wsrep_rollback, &COND_wsrep_rollback, NULL); - mysql_mutex_init(key_LOCK_wsrep_replaying, - &LOCK_wsrep_replaying, MY_MUTEX_INIT_FAST); - mysql_cond_init(key_COND_wsrep_replaying, &COND_wsrep_replaying, NULL); - mysql_mutex_init(key_LOCK_wsrep_slave_threads, - &LOCK_wsrep_slave_threads, MY_MUTEX_INIT_FAST); - mysql_mutex_init(key_LOCK_wsrep_desync, - &LOCK_wsrep_desync, MY_MUTEX_INIT_FAST); -#endif - DBUG_RETURN(0); } @@ -4935,10 +4843,10 @@ static int init_server_components() /* need to configure logging before initializing storage engines */ if (!opt_bin_log_used) { - if (IF_WSREP(!WSREP_ON,1) && opt_log_slave_updates) + if (!WSREP_ON && opt_log_slave_updates) sql_print_warning("You need to use --log-bin to make " "--log-slave-updates work."); - if (IF_WSREP(!WSREP_ON, 1) && binlog_format_used) + if (!WSREP_ON && binlog_format_used) sql_print_warning("You need to use --log-bin to make " "--binlog-format work."); } @@ -5010,10 +4918,9 @@ a file name for --log-bin-index option", opt_binlog_index_name); opt_log_basename, ln); } if (ln == buf) - { opt_bin_logname= my_once_strdup(buf, MYF(MY_WME)); - } -#ifdef WITH_WSREP /* WSREP BEFORE SE */ + } + /* Wsrep initialization must happen at this point, because: - opt_bin_logname must be known when starting replication @@ -5021,19 +4928,19 @@ a file name for --log-bin-index option", opt_binlog_index_name); - SST may modify binlog index file, so it must be opened after SST has happened */ - } - if (WSREP_ON && !wsrep_recovery) + if (WSREP_ON && !wsrep_recovery) /* WSREP BEFORE SE */ { if (opt_bootstrap) // bootsrap option given - disable wsrep functionality { wsrep_provider_init(WSREP_NONE); - if (wsrep_init()) unireg_abort(1); + if (wsrep_init()) + unireg_abort(1); } else // full wsrep initialization { // add basedir/bin to PATH to resolve wsrep script names - char* const tmp_path((char*)alloca(strlen(mysql_home) + - strlen("/bin") + 1)); + char* const tmp_path= (char*)my_alloca(strlen(mysql_home) + + strlen("/bin") + 1); if (tmp_path) { strcpy(tmp_path, mysql_home); @@ -5044,6 +4951,7 @@ a file name for --log-bin-index option", opt_binlog_index_name); { WSREP_ERROR("Could not append %s/bin to PATH", mysql_home); } + my_afree(tmp_path); if (wsrep_before_SE()) { @@ -5053,27 +4961,14 @@ a file name for --log-bin-index option", opt_binlog_index_name); } } } + if (opt_bin_log) { - /* - Variable ln is not defined at this scope. We use opt_bin_logname instead. - It should be the same as ln since - - mysql_bin_log.generate_name() returns first argument if new log name - is not generated - - if new log name is generated, return value is assigned to ln and copied - to opt_bin_logname above - */ if (mysql_bin_log.open_index_file(opt_binlog_index_name, opt_bin_logname, TRUE)) { unireg_abort(1); } -#else - if (mysql_bin_log.open_index_file(opt_binlog_index_name, ln, TRUE)) - { - unireg_abort(1); - } -#endif /* WITH_WSREP */ } /* call ha_init_key_cache() on all key caches to init them */ @@ -5206,7 +5101,6 @@ a file name for --log-bin-index option", opt_binlog_index_name); tc_log= get_tc_log_implementation(); -#ifdef WITH_WSREP if (WSREP_ON && tc_log == &tc_log_mmap) tc_log= &tc_log_dummy; @@ -5215,7 +5109,6 @@ a file name for --log-bin-index option", opt_binlog_index_name); (tc_log == &tc_log_mmap) ? "mmap" : (tc_log == &tc_log_dummy) ? "dummy" : "unknown" ); -#endif if (tc_log->open(opt_bin_log ? opt_bin_logname : opt_tc_log_file)) { @@ -5474,10 +5367,9 @@ int mysqld_main(int argc, char **argv) return 1; } #endif -#ifdef WITH_WSREP + if (WSREP_ON) wsrep_filter_new_cluster (&argc, argv); -#endif /* WITH_WSREP */ orig_argc= argc; orig_argv= argv; @@ -5694,14 +5586,12 @@ int mysqld_main(int argc, char **argv) } #endif -#ifdef WITH_WSREP /* WSREP AFTER SE */ if (WSREP_ON && wsrep_recovery) { select_thread_in_use= 0; wsrep_recover(); unireg_abort(0); } -#endif /* WITH_WSREP */ /* init signals & alarm @@ -5751,7 +5641,6 @@ int mysqld_main(int argc, char **argv) if (Events::init(opt_noacl || opt_bootstrap)) unireg_abort(1); -#ifdef WITH_WSREP /* WSREP AFTER SE */ if (WSREP_ON) { if (opt_bootstrap) @@ -5778,7 +5667,7 @@ int mysqld_main(int argc, char **argv) wsrep_create_appliers(wsrep_slave_threads - 1); } } -#endif /* WITH_WSREP */ + if (opt_bootstrap) { select_thread_in_use= 0; // Allow 'kill' to work @@ -6517,9 +6406,9 @@ void handle_connections_sockets() sleep(1); // Give other threads some time continue; } -#if defined(WITH_WSREP) && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) +#ifdef FD_CLOEXEC (void) fcntl(mysql_socket_getfd(new_sock), F_SETFD, FD_CLOEXEC); -#endif /* WITH_WSREP */ +#endif #ifdef HAVE_LIBWRAP { @@ -8292,21 +8181,6 @@ SHOW_VAR status_vars[]= { {"Uptime", (char*) &show_starttime, SHOW_SIMPLE_FUNC}, #ifdef ENABLED_PROFILING {"Uptime_since_flush_status",(char*) &show_flushstatustime, SHOW_SIMPLE_FUNC}, -#endif -#ifdef WITH_WSREP - {"wsrep_connected", (char*) &wsrep_connected, SHOW_BOOL}, - {"wsrep_ready", (char*) &wsrep_ready, SHOW_BOOL}, - {"wsrep_cluster_state_uuid", (char*) &wsrep_cluster_state_uuid,SHOW_CHAR_PTR}, - {"wsrep_cluster_conf_id", (char*) &wsrep_cluster_conf_id, SHOW_LONGLONG}, - {"wsrep_cluster_status", (char*) &wsrep_cluster_status, SHOW_CHAR_PTR}, - {"wsrep_cluster_size", (char*) &wsrep_cluster_size, SHOW_LONG_NOFLUSH}, - {"wsrep_local_index", (char*) &wsrep_local_index, SHOW_LONG_NOFLUSH}, - {"wsrep_local_bf_aborts", (char*) &wsrep_show_bf_aborts, SHOW_SIMPLE_FUNC}, - {"wsrep_provider_name", (char*) &wsrep_provider_name, SHOW_CHAR_PTR}, - {"wsrep_provider_version", (char*) &wsrep_provider_version, SHOW_CHAR_PTR}, - {"wsrep_provider_vendor", (char*) &wsrep_provider_vendor, SHOW_CHAR_PTR}, - {"wsrep_thread_count", (char*) &wsrep_running_threads, SHOW_LONG_NOFLUSH}, - {"wsrep", (char*) &wsrep_show_status, SHOW_FUNC}, #endif {NullS, NullS, SHOW_LONG} }; @@ -8651,10 +8525,10 @@ static int mysql_init_variables(void) tmpenv = DEFAULT_MYSQL_HOME; strmake_buf(mysql_home, tmpenv); #endif -#ifdef WITH_WSREP + if (WSREP_ON && wsrep_init_vars()) return 1; -#endif + return 0; } @@ -8902,14 +8776,12 @@ mysqld_get_one_option(int optid, case OPT_LOWER_CASE_TABLE_NAMES: lower_case_table_names_used= 1; break; -#ifdef WITH_WSREP case OPT_WSREP_START_POSITION: wsrep_start_position_init (argument); break; case OPT_WSREP_SST_AUTH: wsrep_sst_auth_init (argument); break; -#endif #if defined(ENABLED_DEBUG_SYNC) case OPT_DEBUG_SYNC_TIMEOUT: /* diff --git a/sql/mysqld.h b/sql/mysqld.h index 39b77b441bb..1f7a48050f4 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -242,11 +242,6 @@ extern PSI_mutex_key key_PAGE_lock, key_LOCK_sync, key_LOCK_active, key_LOCK_pool, key_LOCK_pending_checkpoint; #endif /* HAVE_MMAP */ -#ifdef WITH_WSREP -extern PSI_mutex_key key_LOCK_wsrep_thd; -extern PSI_cond_key key_COND_wsrep_thd; -#endif /* WITH_WSREP */ - #ifdef HAVE_OPENSSL extern PSI_mutex_key key_LOCK_des_key_file; #endif @@ -604,15 +599,8 @@ enum options_mysqld OPT_WANT_CORE, OPT_MYSQL_COMPATIBILITY, OPT_MYSQL_TO_BE_IMPLEMENTED, -#ifdef WITH_WSREP - OPT_WSREP_PROVIDER, - OPT_WSREP_PROVIDER_OPTIONS, - OPT_WSREP_CLUSTER_ADDRESS, OPT_WSREP_START_POSITION, OPT_WSREP_SST_AUTH, - OPT_WSREP_RECOVER, -#endif /* WITH_WSREP */ - OPT_which_is_always_the_last }; #endif diff --git a/sql/protocol.cc b/sql/protocol.cc index caa00dd80e3..fde90102e61 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -489,7 +489,7 @@ static uchar *net_store_length_fast(uchar *packet, uint length) void Protocol::end_statement() { /* sanity check*/ - DBUG_ASSERT_IF_WSREP(!(WSREP_ON && WSREP(thd) && thd->wsrep_conflict_state == REPLAYING)); + DBUG_ASSERT_IF_WSREP(!(WSREP(thd) && thd->wsrep_conflict_state == REPLAYING)); DBUG_ENTER("Protocol::end_statement"); DBUG_ASSERT(! thd->get_stmt_da()->is_sent()); bool error= FALSE; diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index 29a1b9728e5..b1cca04d947 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -315,7 +315,6 @@ unpack_row(rpl_group_info *rgi, (int) (pack_ptr - old_pack_ptr))); if (!pack_ptr) { -#ifdef WITH_WSREP if (WSREP_ON) { /* @@ -331,7 +330,6 @@ unpack_row(rpl_group_info *rgi, (table_found) ? "found" : "not found", (ulong)row_end ); } -#endif /* WITH_WSREP */ rgi->rli->report(ERROR_LEVEL, ER_SLAVE_CORRUPT_EVENT, "Could not read field '%s' of table '%s.%s'", diff --git a/sql/set_var.cc b/sql/set_var.cc index 7ad5dc31f6e..5c1e00af33e 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -556,11 +556,7 @@ int mysql_del_sys_var_chain(sys_var *first) static int show_cmp(SHOW_VAR *a, SHOW_VAR *b) { -#ifdef WITH_WSREP - return my_strcasecmp(system_charset_info, a->name, b->name); -#else return strcmp(a->name, b->name); -#endif /* WITH_WSREP */ } diff --git a/sql/set_var.h b/sql/set_var.h index e72a8af6210..bb92e555aa7 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -249,9 +249,6 @@ public: int check(THD *thd); int update(THD *thd); int light_check(THD *thd); -#ifdef WITH_WSREP - int wsrep_store_variable(THD *thd); -#endif }; @@ -358,9 +355,6 @@ extern sys_var *Sys_autocommit_ptr; CHARSET_INFO *get_old_charset_by_name(const char *old_name); -#ifdef WITH_WSREP -int sql_set_wsrep_variables(THD *thd, List *var_list); -#endif int sys_var_init(); int sys_var_add_options(DYNAMIC_ARRAY *long_options, int parse_flags); void sys_var_end(void); diff --git a/sql/slave.cc b/sql/slave.cc index 44107c02724..110283ce4b4 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -4621,12 +4621,10 @@ log '%s' at position %s, relay log '%s' position: %s%s", RPL_LOG_NAME, if (!sql_slave_killed(serial_rgi)) { slave_output_error_info(rli, thd); -#ifdef WITH_WSREP if (WSREP_ON && rli->last_error().number == ER_UNKNOWN_COM_ERROR) { wsrep_node_dropped= TRUE; } -#endif /* WITH_WSREP */ } goto err; } diff --git a/sql/sp.cc b/sql/sp.cc index 261299464c5..b25117019c0 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -32,19 +32,6 @@ #include -bool -create_string(THD *thd, String *buf, - stored_procedure_type sp_type, - const char *db, ulong dblen, - const char *name, ulong namelen, - const char *params, ulong paramslen, - const char *returns, ulong returnslen, - const char *body, ulong bodylen, - st_sp_chistics *chistics, - const LEX_STRING *definer_user, - const LEX_STRING *definer_host, - ulonglong sql_mode); - static int db_load_routine(THD *thd, stored_procedure_type type, sp_name *name, sp_head **sphp, @@ -844,7 +831,7 @@ db_load_routine(THD *thd, stored_procedure_type type, definition for SHOW CREATE PROCEDURE later. */ - if (!create_string(thd, &defstr, + if (!show_create_sp(thd, &defstr, type, NULL, 0, name->m_name.str, name->m_name.length, @@ -1186,7 +1173,7 @@ sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp) String log_query; log_query.set_charset(system_charset_info); - if (!create_string(thd, &log_query, + if (!show_create_sp(thd, &log_query, sp->m_type, (sp->m_explicit_name ? sp->m_db.str : NULL), (sp->m_explicit_name ? sp->m_db.length : 0), @@ -2127,7 +2114,7 @@ int sp_cache_routine(THD *thd, enum stored_procedure_type type, sp_name *name, Returns TRUE on success, FALSE on (alloc) failure. */ bool -create_string(THD *thd, String *buf, +show_create_sp(THD *thd, String *buf, stored_procedure_type type, const char *db, ulong dblen, const char *name, ulong namelen, @@ -2253,7 +2240,7 @@ sp_load_for_information_schema(THD *thd, TABLE *proc_table, String *db, sp_body= (type == TYPE_ENUM_FUNCTION ? "RETURN NULL" : "BEGIN END"); bzero((char*) &sp_chistics, sizeof(sp_chistics)); defstr.set_charset(creation_ctx->get_client_cs()); - if (!create_string(thd, &defstr, type, + if (!show_create_sp(thd, &defstr, type, sp_db_str.str, sp_db_str.length, sp_name_obj.m_name.str, sp_name_obj.m_name.length, params, strlen(params), diff --git a/sql/sp.h b/sql/sp.h index de32b5454f8..eb3291fb1a9 100644 --- a/sql/sp.h +++ b/sql/sp.h @@ -218,7 +218,7 @@ void sp_returns_type(THD *thd, String &result, sp_head *sp); -bool create_string(THD *thd, String *buf, +bool show_create_sp(THD *thd, String *buf, stored_procedure_type type, const char *db, ulong dblen, const char *name, ulong namelen, diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index bae2d15ba20..5e30b148ad7 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2657,9 +2657,7 @@ bool change_password(THD *thd, const char *host, const char *user, if (WSREP(thd) && !thd->wsrep_applier) { query_length= sprintf(buff, "SET PASSWORD FOR '%-.120s'@'%-.120s'='%-.120s'", - user ? user : "", - host ? host : "", - new_password); + safe_str(user), safe_str(host), new_password); thd->set_query_inner(buff, query_length, system_charset_info); WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, (char*)"user", NULL); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 68f325e20ab..00689aad1f3 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -9019,14 +9019,12 @@ bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use, if (!thd_table->needs_reopen()) { signalled|= mysql_lock_abort_for_thread(thd, thd_table); -#ifdef WITH_WSREP if (thd && WSREP(thd) && wsrep_thd_is_BF((void *)thd, true)) { WSREP_DEBUG("remove_table_from_cache: %llu", (unsigned long long) thd->real_id); wsrep_abort_thd((void *)thd, (void *)in_use, FALSE); } -#endif } } mysql_mutex_unlock(&in_use->LOCK_thd_data); diff --git a/sql/sql_builtin.cc.in b/sql/sql_builtin.cc.in index 2de475b0a76..5bf0a682369 100644 --- a/sql/sql_builtin.cc.in +++ b/sql/sql_builtin.cc.in @@ -27,7 +27,7 @@ builtin_maria_plugin @mysql_mandatory_plugins@ @mysql_optional_plugins@ builtin_maria_binlog_plugin, #ifdef WITH_WSREP - builtin_wsrep_plugin@mysql_plugin_defs@, + builtin_wsrep_plugin, #endif /* WITH_WSREP */ builtin_maria_mysql_password_plugin; @@ -40,7 +40,7 @@ struct st_maria_plugin *mysql_mandatory_plugins[]= { builtin_maria_binlog_plugin, builtin_maria_mysql_password_plugin, #ifdef WITH_WSREP - builtin_wsrep_plugin@mysql_plugin_defs@, + builtin_wsrep_plugin, #endif /* WITH_WSREP */ @mysql_mandatory_plugins@ 0 }; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 919361b4b30..82e4f99eed0 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -861,7 +861,7 @@ bool Drop_table_error_handler::handle_condition(THD *thd, } -THD::THD(bool is_applier) +THD::THD(bool is_wsrep_applier) :Statement(&main_lex, &main_mem_root, STMT_CONVENTIONAL_EXECUTION, /* statement id */ 0), rli_fake(0), rgi_fake(0), rgi_slave(NULL), @@ -892,13 +892,12 @@ THD::THD(bool is_applier) derived_tables_processing(FALSE), spcont(NULL), #ifdef WITH_WSREP - wsrep_applier(is_applier), + wsrep_applier(is_wsrep_applier), wsrep_applier_closing(false), wsrep_client_thread(false), wsrep_apply_toi(false), wsrep_po_handle(WSREP_PO_INITIALIZER), wsrep_po_cnt(0), -// wsrep_po_in_trans(false), wsrep_apply_format(0), #endif m_parser_state(NULL), @@ -1435,15 +1434,8 @@ void THD::init(void) wsrep_TOI_pre_query = NULL; wsrep_TOI_pre_query_len = 0; - - /* - @@wsrep_causal_reads is now being handled via wsrep_sync_wait, update it - appropriately. - */ - if (variables.wsrep_causal_reads) - variables.wsrep_sync_wait|= WSREP_SYNC_WAIT_BEFORE_READ; - #endif + if (variables.sql_log_bin) variables.option_bits|= OPTION_BIN_LOG; else @@ -1958,14 +1950,12 @@ bool THD::notify_shared_lock(MDL_context_owner *ctx_in_use, if (!thd_table->needs_reopen()) { signalled|= mysql_lock_abort_for_thread(this, thd_table); -#if WITH_WSREP if (this && WSREP(this) && wsrep_thd_is_BF((void *)this, FALSE)) { WSREP_DEBUG("remove_table_from_cache: %llu", (unsigned long long) this->real_id); wsrep_abort_thd((void *)this, (void *)in_use, FALSE); } -#endif /* WITH_WSREP */ } } mysql_mutex_unlock(&in_use->LOCK_thd_data); @@ -4328,8 +4318,7 @@ extern "C" int thd_non_transactional_update(const MYSQL_THD thd) extern "C" int thd_binlog_format(const MYSQL_THD thd) { - if (IF_WSREP(((WSREP(thd) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()), - mysql_bin_log.is_open()) && + if (((WSREP(thd) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()) && thd->variables.option_bits & OPTION_BIN_LOG) return (int) WSREP_FORMAT(thd->variables.binlog_format); else @@ -5671,8 +5660,7 @@ int THD::binlog_write_row(TABLE* table, bool is_trans, { DBUG_ASSERT(is_current_stmt_binlog_format_row() && - IF_WSREP(((WSREP(this) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()), - mysql_bin_log.is_open())); + ((WSREP(this) && wsrep_emulate_bin_log) || mysql_bin_log.is_open())); /* Pack records into format for transfer. We are allocating more memory than needed, but that doesn't matter. @@ -5706,8 +5694,7 @@ int THD::binlog_update_row(TABLE* table, bool is_trans, const uchar *after_record) { DBUG_ASSERT(is_current_stmt_binlog_format_row() && - IF_WSREP(((WSREP(this) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()), - mysql_bin_log.is_open())); + ((WSREP(this) && wsrep_emulate_bin_log) || mysql_bin_log.is_open())); size_t const before_maxlen = max_row_length(table, before_record); size_t const after_maxlen = max_row_length(table, after_record); @@ -5757,8 +5744,7 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans, uchar const *record) { DBUG_ASSERT(is_current_stmt_binlog_format_row() && - IF_WSREP(((WSREP(this) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()), - mysql_bin_log.is_open())); + ((WSREP(this) && wsrep_emulate_bin_log) || mysql_bin_log.is_open())); /* Pack records into format for transfer. We are allocating more @@ -5793,8 +5779,7 @@ int THD::binlog_remove_pending_rows_event(bool clear_maps, { DBUG_ENTER("THD::binlog_remove_pending_rows_event"); - if(IF_WSREP(!(WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open()), - !mysql_bin_log.is_open())) + if(!WSREP_EMULATE_BINLOG(this) && !mysql_bin_log.is_open()) DBUG_RETURN(0); /* Ensure that all events in a GTID group are in the same cache */ @@ -5817,8 +5802,7 @@ int THD::binlog_flush_pending_rows_event(bool stmt_end, bool is_transactional) mode: it might be the case that we left row-based mode before flushing anything (e.g., if we have explicitly locked tables). */ - if(IF_WSREP(!(WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open()), - !mysql_bin_log.is_open())) + if(!WSREP_EMULATE_BINLOG(this) && !mysql_bin_log.is_open()) DBUG_RETURN(0); /* Ensure that all events in a GTID group are in the same cache */ @@ -6072,8 +6056,7 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg, show_query_type(qtype), (int) query_len, query_arg)); DBUG_ASSERT(query_arg && - IF_WSREP((WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open()), - mysql_bin_log.is_open())); + (WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open())); /* If this is withing a BEGIN ... COMMIT group, don't log it */ if (variables.option_bits & OPTION_GTID_BEGIN) diff --git a/sql/sql_class.h b/sql/sql_class.h index 1154f0ac486..ed447d9fc8f 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2084,7 +2084,7 @@ public: int is_current_stmt_binlog_format_row() const { DBUG_ASSERT(current_stmt_binlog_format == BINLOG_FORMAT_STMT || current_stmt_binlog_format == BINLOG_FORMAT_ROW); - return (WSREP_FORMAT((ulong)current_stmt_binlog_format) == BINLOG_FORMAT_ROW); + return WSREP_FORMAT(current_stmt_binlog_format) == BINLOG_FORMAT_ROW; } enum binlog_filter_state @@ -2807,7 +2807,7 @@ public: /* Debug Sync facility. See debug_sync.cc. */ struct st_debug_sync_control *debug_sync_control; #endif /* defined(ENABLED_DEBUG_SYNC) */ - THD(bool is_applier= false); + THD(bool is_wsrep_applier= false); ~THD(); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 5eb4c405c4b..418c1db9b21 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -646,8 +646,7 @@ cleanup: /* See similar binlogging code in sql_update.cc, for comments */ if ((error < 0) || thd->transaction.stmt.modified_non_trans_table) { - if(IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), - mysql_bin_log.is_open())) + if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) { int errcode= 0; if (error < 0) @@ -1114,8 +1113,7 @@ void multi_delete::abort_result_set() /* there is only side effects; to binlog with the error */ - if (IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), - mysql_bin_log.is_open())) + if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) { int errcode= query_error_code(thd, thd->killed == NOT_KILLED); /* possible error of writing binary log is ignored deliberately */ @@ -1291,8 +1289,7 @@ bool multi_delete::send_eof() } if ((local_error == 0) || thd->transaction.stmt.modified_non_trans_table) { - if(IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), - mysql_bin_log.is_open())) + if(WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) { int errcode= 0; if (local_error == 0) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index f90e9cd2439..8b01acb2a87 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1014,8 +1014,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, thd->transaction.stmt.modified_non_trans_table || was_insert_delayed) { - if(IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), - mysql_bin_log.is_open())) + if(WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) { int errcode= 0; if (error <= 0) @@ -3197,12 +3196,10 @@ bool Delayed_insert::handle_inserts(void) } } -#ifdef WITH_WSREP if (WSREP((&thd))) thd_proc_info(&thd, "insert done"); else -#endif /* WITH_WSREP */ - thd_proc_info(&thd, 0); + thd_proc_info(&thd, 0); mysql_mutex_unlock(&mutex); /* @@ -3687,9 +3684,8 @@ bool select_insert::send_eof() events are in the transaction cache and will be written when ha_autocommit_or_rollback() is issued below. */ - if(IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), - mysql_bin_log.is_open()) && - (!error || thd->transaction.stmt.modified_non_trans_table)) + if ((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) && + (!error || thd->transaction.stmt.modified_non_trans_table)) { int errcode= 0; if (!error) @@ -3773,8 +3769,7 @@ void select_insert::abort_result_set() { if (!can_rollback_data()) thd->transaction.all.modified_non_trans_table= TRUE; - if(IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), - mysql_bin_log.is_open())) + if(WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) { int errcode= query_error_code(thd, thd->killed == NOT_KILLED); /* error of writing binary log is ignored */ @@ -4182,8 +4177,7 @@ select_create::binlog_show_create_table(TABLE **tables, uint count) create_info->table_was_deleted); DBUG_ASSERT(result == 0); /* store_create_info() always return 0 */ - if(IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), - mysql_bin_log.is_open())) + if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) { int errcode= query_error_code(thd, thd->killed == NOT_KILLED); result= thd->binlog_query(THD::STMT_QUERY_TYPE, @@ -4194,7 +4188,7 @@ select_create::binlog_show_create_table(TABLE **tables, uint count) errcode); } - IF_WSREP(ha_fake_trx_id(thd), ); + ha_fake_trx_id(thd); return result; } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4d6becff599..cdafeccd392 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -106,10 +106,8 @@ #include "wsrep_mysqld.h" #include "wsrep_thd.h" -#ifdef WITH_WSREP static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length, Parser_state *parser_state); -#endif /* WITH_WSREP */ /** @defgroup Runtime_Environment Runtime Environment @@ -875,6 +873,22 @@ void cleanup_items(Item *item) DBUG_VOID_RETURN; } + +#ifdef WITH_WSREP +static bool wsrep_node_is_ready(THD *thd) +{ + if (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready) + { + my_message(ER_UNKNOWN_COM_ERROR, + "WSREP has not yet prepared node for application use", + MYF(0)); + return false; + } + return true; +} +#endif + + #ifndef EMBEDDED_LIBRARY /** @@ -1055,15 +1069,13 @@ bool do_command(THD *thd) vio_description(net->vio), command, command_name[command].str)); -#ifdef WITH_WSREP if (WSREP(thd)) { /* * bail out if DB snapshot has not been installed. We however, * allow queries "SET" and "SHOW", they are trapped later in execute_command */ - if (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready && - command != COM_QUERY && + if (command != COM_QUERY && command != COM_PING && command != COM_QUIT && command != COM_PROCESS_INFO && @@ -1073,17 +1085,14 @@ bool do_command(THD *thd) command != COM_SLEEP && command != COM_STATISTICS && command != COM_TIME && - command != COM_END - ) { - my_message(ER_UNKNOWN_COM_ERROR, - "WSREP has not yet prepared node for application use", - MYF(0)); + command != COM_END && + !wsrep_node_is_ready(thd)) + { thd->protocol->end_statement(); return_value= FALSE; goto out; } } -#endif /* WITH_WSREP */ /* Restore read timeout value */ my_net_set_read_timeout(net, thd->variables.net_read_timeout); @@ -1143,7 +1152,7 @@ out: @retval FALSE The statement isn't updating any relevant tables. */ -my_bool deny_updates_if_read_only_option(THD *thd, +static my_bool deny_updates_if_read_only_option(THD *thd, TABLE_LIST *all_tables) { DBUG_ENTER("deny_updates_if_read_only_option"); @@ -1224,9 +1233,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd, { NET *net= &thd->net; bool error= 0; + bool do_end_of_statement= true; DBUG_ENTER("dispatch_command"); DBUG_PRINT("info", ("command: %d", command)); + inc_thread_running(); + #ifdef WITH_WSREP if (WSREP(thd)) { @@ -1254,11 +1266,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->mysys_var->abort = 0; thd->wsrep_conflict_state = NO_CONFLICT; thd->wsrep_retry_counter = 0; - /* - Increment threads running to compensate dec_thread_running() called - after dispatch_end label. - */ - inc_thread_running(); goto dispatch_end; } mysql_mutex_unlock(&thd->LOCK_wsrep_thd); @@ -1302,7 +1309,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd, */ thd->set_query_id(get_query_id()); } - inc_thread_running(); if (!(server_command_flags[command] & CF_SKIP_QUESTIONS)) statistic_increment(thd->status_var.questions, &LOCK_status); @@ -1460,11 +1466,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (parser_state.init(thd, thd->query(), thd->query_length())) break; -#ifdef WITH_WSREP if (WSREP_ON) wsrep_mysql_parse(thd, thd->query(), thd->query_length(), &parser_state); else -#endif /* WITH_WSREP */ mysql_parse(thd, thd->query(), thd->query_length(), &parser_state); while (!thd->killed && (parser_state.m_lip.found_semicolon != NULL) && @@ -1540,17 +1544,15 @@ bool dispatch_command(enum enum_server_command command, THD *thd, */ statistic_increment(thd->status_var.questions, &LOCK_status); - if(IF_WSREP(!WSREP(thd), 1)) + if(!WSREP(thd)) thd->set_time(); /* Reset the query start time. */ parser_state.reset(beginning_of_next_stmt, length); /* TODO: set thd->lex->sql_command to SQLCOM_END here */ -#ifdef WITH_WSREP if (WSREP_ON) wsrep_mysql_parse(thd, beginning_of_next_stmt, length, &parser_state); else -#endif /* WITH_WSREP */ mysql_parse(thd, beginning_of_next_stmt, length, &parser_state); } @@ -1889,6 +1891,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0)); break; } + #ifdef WITH_WSREP dispatch_end: @@ -1896,21 +1899,16 @@ bool dispatch_command(enum enum_server_command command, THD *thd, { /* wsrep BF abort in query exec phase */ mysql_mutex_lock(&thd->LOCK_wsrep_thd); - if ((thd->wsrep_conflict_state != REPLAYING) && - (thd->wsrep_conflict_state != RETRY_AUTOCOMMIT)) - { - mysql_mutex_unlock(&thd->LOCK_wsrep_thd); - thd->update_server_status(); - thd->protocol->end_statement(); - query_cache_end_of_result(thd); - } - else - { - mysql_mutex_unlock(&thd->LOCK_wsrep_thd); - } + do_end_of_statement= thd->wsrep_conflict_state != REPLAYING && + thd->wsrep_conflict_state != RETRY_AUTOCOMMIT; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); } else + do_end_of_statement= true; + #endif /* WITH_WSREP */ + + if (do_end_of_statement) { DBUG_ASSERT(thd->derived_tables == NULL && (thd->open_tables == NULL || @@ -2601,15 +2599,10 @@ mysql_execute_command(THD *thd) * bail out if DB snapshot has not been installed. We however, * allow SET and SHOW queries */ - if (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready && - lex->sql_command != SQLCOM_SET_OPTION && - !wsrep_is_show_query(lex->sql_command)) - { - my_message(ER_UNKNOWN_COM_ERROR, - "WSREP has not yet prepared node for application use", - MYF(0)); + if (lex->sql_command != SQLCOM_SET_OPTION && + !wsrep_is_show_query(lex->sql_command) && + !wsrep_node_is_ready(thd)) goto error; - } } #endif /* WITH_WSREP */ status_var_increment(thd->status_var.com_stat[lex->sql_command]); @@ -2652,14 +2645,14 @@ mysql_execute_command(THD *thd) if (!(thd->variables.option_bits & OPTION_GTID_BEGIN)) { /* Commit the normal transaction if one is active. */ - if (trans_commit_implicit(thd)) + bool commit_failed= trans_commit_implicit(thd); + /* Release metadata locks acquired in this transaction. */ + thd->mdl_context.release_transactional_locks(); + if (commit_failed) { - thd->mdl_context.release_transactional_locks(); WSREP_DEBUG("implicit commit failed, MDL released: %lu", thd->thread_id); goto error; } - /* Release metadata locks acquired in this transaction. */ - thd->mdl_context.release_transactional_locks(); } } @@ -2715,10 +2708,8 @@ mysql_execute_command(THD *thd) #endif case SQLCOM_SHOW_STATUS: { -#ifdef WITH_WSREP if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error; -#endif /* WITH_WSREP */ execute_show_status(thd, all_tables); break; } @@ -2751,11 +2742,6 @@ mysql_execute_command(THD *thd) } case SQLCOM_SHOW_STATUS_PROC: case SQLCOM_SHOW_STATUS_FUNC: -#ifdef WITH_WSREP - if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) - goto error; -#endif /* WITH_WSREP */ - case SQLCOM_SHOW_DATABASES: case SQLCOM_SHOW_TABLES: case SQLCOM_SHOW_TRIGGERS: @@ -2764,27 +2750,19 @@ mysql_execute_command(THD *thd) case SQLCOM_SHOW_PLUGINS: case SQLCOM_SHOW_FIELDS: case SQLCOM_SHOW_KEYS: -#ifndef WITH_WSREP - case SQLCOM_SHOW_VARIABLES: - case SQLCOM_SHOW_CHARSETS: - case SQLCOM_SHOW_COLLATIONS: - case SQLCOM_SHOW_STORAGE_ENGINES: - case SQLCOM_SHOW_PROFILE: -#endif /* WITH_WSREP */ case SQLCOM_SHOW_CLIENT_STATS: case SQLCOM_SHOW_USER_STATS: case SQLCOM_SHOW_TABLE_STATS: case SQLCOM_SHOW_INDEX_STATS: case SQLCOM_SELECT: -#ifdef WITH_WSREP if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error; + case SQLCOM_SHOW_VARIABLES: case SQLCOM_SHOW_CHARSETS: case SQLCOM_SHOW_COLLATIONS: case SQLCOM_SHOW_STORAGE_ENGINES: case SQLCOM_SHOW_PROFILE: -#endif /* WITH_WSREP */ { thd->status_var.last_query_cost= 0.0; @@ -3271,7 +3249,6 @@ mysql_execute_command(THD *thd) } else { -#ifdef WITH_WSREP /* in STATEMENT format, we probably have to replicate also temporary tables, like mysql replication does */ @@ -3280,7 +3257,6 @@ mysql_execute_command(THD *thd) { WSREP_TO_ISOLATION_BEGIN(create_table->db, create_table->table_name, NULL) } -#endif /* WITH_WSREP */ /* Regular CREATE TABLE */ res= mysql_create_table(thd, create_table, &create_info, &alter_info); @@ -3466,10 +3442,8 @@ end_with_restore_list: goto error; #else -#ifdef WITH_WSREP if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error; -#endif /* WITH_WSREP */ /* Access check: @@ -3533,10 +3507,8 @@ end_with_restore_list: case SQLCOM_CHECKSUM: { DBUG_ASSERT(first_table == all_tables && first_table != 0); -#ifdef WITH_WSREP if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error; -#endif /* WITH_WSREP */ if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE)) @@ -3549,11 +3521,9 @@ end_with_restore_list: { ha_rows found= 0, updated= 0; DBUG_ASSERT(first_table == all_tables && first_table != 0); -#ifdef WITH_WSREP if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE)) goto error; -#endif /* WITH_WSREP */ if (update_precheck(thd, all_tables)) break; @@ -3591,11 +3561,9 @@ end_with_restore_list: /* if we switched from normal update, rights are checked */ if (up_result != 2) { -#ifdef WITH_WSREP if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE)) goto error; -#endif /* WITH_WSREP */ if ((res= multi_update_precheck(thd, all_tables))) break; } @@ -3666,11 +3634,9 @@ end_with_restore_list: } case SQLCOM_REPLACE: { -#ifdef WITH_WSREP if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE)) goto error; -#endif /* WITH_WSREP */ #ifndef DBUG_OFF if (mysql_bin_log.is_open()) { @@ -3710,11 +3676,9 @@ end_with_restore_list: { DBUG_ASSERT(first_table == all_tables && first_table != 0); -#ifdef WITH_WSREP if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE)) goto error; -#endif /* WITH_WSREP */ /* Since INSERT DELAYED doesn't support temporary tables, we could @@ -3770,11 +3734,9 @@ end_with_restore_list: select_result *sel_result; bool explain= MY_TEST(lex->describe); DBUG_ASSERT(first_table == all_tables && first_table != 0); -#ifdef WITH_WSREP if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE)) goto error; -#endif /* WITH_WSREP */ if ((res= insert_precheck(thd, all_tables))) break; @@ -3876,11 +3838,9 @@ end_with_restore_list: { select_result *sel_result=lex->result; DBUG_ASSERT(first_table == all_tables && first_table != 0); -#ifdef WITH_WSREP if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE)) goto error; -#endif /* WITH_WSREP */ if ((res= delete_precheck(thd, all_tables))) break; @@ -3938,11 +3898,9 @@ end_with_restore_list: DBUG_ASSERT(first_table == all_tables && first_table != 0); TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first; multi_delete *result; -#ifdef WITH_WSREP if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE)) goto error; -#endif /* WITH_WSREP */ if ((res= multi_delete_precheck(thd, all_tables))) break; @@ -4013,7 +3971,6 @@ end_with_restore_list: /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */ thd->variables.option_bits|= OPTION_KEEP_LOG; } -#ifdef WITH_WSREP if (WSREP(thd)) { for (TABLE_LIST *table= all_tables; table; table= table->next_global) @@ -4027,7 +3984,6 @@ end_with_restore_list: } } } -#endif /* WITH_WSREP */ /* If we are a slave, we should add IF EXISTS if the query executed on the master without an error. This will help a slave to @@ -4783,13 +4739,13 @@ end_with_restore_list: bool tx_release= (lex->tx_release == TVL_YES || (thd->variables.completion_type == 2 && lex->tx_release != TVL_NO)); - if (trans_commit(thd)) + bool commit_failed= trans_commit(thd); + thd->mdl_context.release_transactional_locks(); + if (commit_failed) { - thd->mdl_context.release_transactional_locks(); WSREP_DEBUG("COMMIT failed, MDL released: %lu", thd->thread_id); goto error; } - thd->mdl_context.release_transactional_locks(); /* Begin transaction with the same isolation level. */ if (tx_chain) { @@ -4831,14 +4787,14 @@ end_with_restore_list: bool tx_release= (lex->tx_release == TVL_YES || (thd->variables.completion_type == 2 && lex->tx_release != TVL_NO)); + bool rollback_failed= trans_rollback(thd); + thd->mdl_context.release_transactional_locks(); - if (trans_rollback(thd)) + if (rollback_failed) { - thd->mdl_context.release_transactional_locks(); WSREP_DEBUG("rollback failed, MDL released: %lu", thd->thread_id); goto error; } - thd->mdl_context.release_transactional_locks(); /* Begin transaction with the same isolation level. */ if (tx_chain) { @@ -5376,13 +5332,14 @@ create_sp_error: my_ok(thd); break; case SQLCOM_XA_COMMIT: - if (trans_xa_commit(thd)) + { + bool commit_failed= trans_xa_commit(thd); + thd->mdl_context.release_transactional_locks(); + if (commit_failed) { - thd->mdl_context.release_transactional_locks(); WSREP_DEBUG("XA commit failed, MDL released: %lu", thd->thread_id); goto error; } - thd->mdl_context.release_transactional_locks(); /* We've just done a commit, reset transaction isolation level and access mode to the session default. @@ -5391,14 +5348,16 @@ create_sp_error: thd->tx_read_only= thd->variables.tx_read_only; my_ok(thd); break; + } case SQLCOM_XA_ROLLBACK: - if (trans_xa_rollback(thd)) + { + bool rollback_failed= trans_xa_rollback(thd); + thd->mdl_context.release_transactional_locks(); + if (rollback_failed) { - thd->mdl_context.release_transactional_locks(); WSREP_DEBUG("XA rollback failed, MDL released: %lu", thd->thread_id); goto error; } - thd->mdl_context.release_transactional_locks(); /* We've just done a rollback, reset transaction isolation level and access mode to the session default. @@ -5407,6 +5366,7 @@ create_sp_error: thd->tx_read_only= thd->variables.tx_read_only; my_ok(thd); break; + } case SQLCOM_XA_RECOVER: res= mysql_xa_recover(thd); break; @@ -5744,10 +5704,15 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables) status_var_increment(thd->status_var.empty_queries); else status_var_add(thd->status_var.rows_sent, thd->get_sent_row_count()); + #ifdef WITH_WSREP - if (WSREP_ON && lex->sql_command == SQLCOM_SHOW_STATUS) - wsrep_free_status(thd); -#endif /* WITH_WSREP */ + if (thd->wsrep_status_vars) + { + wsrep->stats_free (wsrep, thd->wsrep_status_vars); + thd->wsrep_status_vars = 0; + } +#endif + return res; } @@ -6592,19 +6557,13 @@ void THD::reset_for_next_command() transactions. Appliers and replayers are either processing ROW events or get autoinc variable values from Query_log_event. */ - if (WSREP(thd) && thd->wsrep_exec_mode == LOCAL_STATE) + if (WSREP(thd) && thd->wsrep_exec_mode == LOCAL_STATE && + wsrep_auto_increment_control) { - if (wsrep_auto_increment_control) - { - if (thd->variables.auto_increment_offset != - global_system_variables.auto_increment_offset) - thd->variables.auto_increment_offset= - global_system_variables.auto_increment_offset; - if (thd->variables.auto_increment_increment != - global_system_variables.auto_increment_increment) - thd->variables.auto_increment_increment= - global_system_variables.auto_increment_increment; - } + thd->variables.auto_increment_offset= + global_system_variables.auto_increment_offset; + thd->variables.auto_increment_increment= + global_system_variables.auto_increment_increment; } #endif /* WITH_WSREP */ thd->query_start_used= 0; @@ -6810,15 +6769,14 @@ void mysql_init_multi_delete(LEX *lex) lex->query_tables_last= &lex->query_tables; } -#ifdef WITH_WSREP static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length, - Parser_state *parser_state) + Parser_state *parser_state) { +#ifdef WITH_WSREP bool is_autocommit= !thd->in_multi_stmt_transaction_mode() && thd->wsrep_conflict_state == NO_CONFLICT && - !thd->wsrep_applier && - wsrep_read_only_option(thd, thd->lex->query_tables); + !thd->wsrep_applier; do { @@ -6911,8 +6869,8 @@ static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length, thd->wsrep_retry_query_len = 0; thd->wsrep_retry_command = COM_CONNECT; } -} #endif /* WITH_WSREP */ +} /* When you modify mysql_parse(), you may need to mofify @@ -7944,7 +7902,7 @@ kill_one_thread(THD *thd, longlong id, killed_state kill_signal, killed_type typ if (((thd->security_ctx->master_access & SUPER_ACL) || thd->security_ctx->user_matches(tmp->security_ctx)) && - IF_WSREP(!wsrep_thd_is_BF((void *)tmp, true), 1)) + !wsrep_thd_is_BF(tmp, true)) { tmp->awake(kill_signal); error=0; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index e0d1cec6a0a..86936700c7d 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -3659,6 +3659,8 @@ reexecute: case MUST_REPLAY: (void)wsrep_replay_transaction(thd); + break; + default: break; } diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc index 797c9779994..91d412a0c39 100644 --- a/sql/sql_reload.cc +++ b/sql/sql_reload.cc @@ -253,7 +253,6 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options, } if (options & REFRESH_CHECKPOINT) disable_checkpoints(thd); -#ifdef WITH_WSREP /* We need to do it second time after wsrep appliers were blocked in make_global_read_lock_block_commit(thd) above since they could have @@ -263,7 +262,6 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options, close_cached_tables(thd, tables, (options & REFRESH_FAST) ? FALSE : TRUE, TRUE)) result= 1; -#endif /* WITH_WSREP */ } else { diff --git a/sql/sql_table.cc b/sql/sql_table.cc index b86de2f6cc1..19914f31c97 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5267,7 +5267,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, #ifdef WITH_WSREP if (WSREP_ON && !thd->wsrep_applier && wsrep_create_like_table(thd, table, src_table, create_info)) - goto end; + DBUG_RETURN(res); #endif /* @@ -5532,7 +5532,6 @@ err: res= 1; } -end: DBUG_RETURN(res); } diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 268fad5d90e..443a82a9df2 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -434,8 +434,8 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) binlogged, so they share the same danger, so trust_function_creators applies to them too. */ - if (!trust_function_creators && - IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), mysql_bin_log.is_open()) && + if (!trust_function_creators && + (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) && !(thd->security_ctx->master_access & SUPER_ACL)) { my_error(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER, MYF(0)); diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc index 5e23c6ee32b..bac691e35ea 100644 --- a/sql/sql_truncate.cc +++ b/sql/sql_truncate.cc @@ -412,12 +412,9 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref) { bool hton_can_recreate; -#ifdef WITH_WSREP - if (WSREP(thd) && wsrep_to_isolation_begin(thd, - table_ref->db, - table_ref->table_name, NULL)) + if (WSREP(thd) && + wsrep_to_isolation_begin(thd, table_ref->db, table_ref->table_name, 0)) DBUG_RETURN(TRUE); -#endif /* WITH_WSREP */ if (lock_table(thd, table_ref, &hton_can_recreate)) DBUG_RETURN(TRUE); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index c458f01303d..88b6c53b00e 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -976,8 +976,7 @@ int mysql_update(THD *thd, */ if ((error < 0) || thd->transaction.stmt.modified_non_trans_table) { - if (IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), - mysql_bin_log.is_open())) + if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) { int errcode= 0; if (error < 0) @@ -2220,8 +2219,7 @@ void multi_update::abort_result_set() The query has to binlog because there's a modified non-transactional table either from the query's list or via a stored routine: bug#13270,23333 */ - if (IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), - mysql_bin_log.is_open())) + if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) { /* THD::killed status might not have been set ON at time of an error @@ -2490,8 +2488,7 @@ bool multi_update::send_eof() if (local_error == 0 || thd->transaction.stmt.modified_non_trans_table) { - if (IF_WSREP((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()), - mysql_bin_log.is_open())) + if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) { int errcode= 0; if (local_error == 0) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index a06d702f620..78a0eff935a 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7171,9 +7171,7 @@ alter: Lex->event_parse_data->identifier= $5; Lex->sql_command= SQLCOM_ALTER_EVENT; -#ifdef WITH_WSREP Lex->stmt_definition_begin= $3; -#endif } ev_alter_on_schedule_completion opt_ev_rename_to @@ -7191,9 +7189,7 @@ alter: can overwrite it */ Lex->sql_command= SQLCOM_ALTER_EVENT; -#ifdef WITH_WSREP Lex->stmt_definition_end= (char*)YYLIP->get_cpp_ptr(); -#endif } | ALTER TABLESPACE alter_tablespace_info { diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index e40dfbe8675..046f68e574e 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -3714,7 +3714,7 @@ static char *glob_hostname_ptr; static Sys_var_charptr Sys_hostname( "hostname", "Server host name", READ_ONLY GLOBAL_VAR(glob_hostname_ptr), NO_CMD_LINE, - IN_FS_CHARSET, DEFAULT(glob_hostname)); + IN_SYSTEM_CHARSET, DEFAULT(glob_hostname)); #ifndef EMBEDDED_LIBRARY static Sys_var_charptr Sys_repl_report_host( @@ -3727,21 +3727,21 @@ static Sys_var_charptr Sys_repl_report_host( "NAT and other routing issues, that IP may not be valid for connecting " "to the slave from the master or other hosts", READ_ONLY GLOBAL_VAR(report_host), CMD_LINE(REQUIRED_ARG), - IN_FS_CHARSET, DEFAULT(0)); + IN_SYSTEM_CHARSET, DEFAULT(0)); static Sys_var_charptr Sys_repl_report_user( "report_user", "The account user name of the slave to be reported to the master " "during slave registration", READ_ONLY GLOBAL_VAR(report_user), CMD_LINE(REQUIRED_ARG), - IN_FS_CHARSET, DEFAULT(0)); + IN_SYSTEM_CHARSET, DEFAULT(0)); static Sys_var_charptr Sys_repl_report_password( "report_password", "The account password of the slave to be reported to the master " "during slave registration", READ_ONLY GLOBAL_VAR(report_password), CMD_LINE(REQUIRED_ARG), - IN_FS_CHARSET, DEFAULT(0)); + IN_SYSTEM_CHARSET, DEFAULT(0)); static Sys_var_uint Sys_repl_report_port( "report_port", @@ -4439,7 +4439,7 @@ static Sys_var_tz Sys_time_zone( static Sys_var_charptr Sys_wsrep_provider( "wsrep_provider", "Path to replication provider library", - PREALLOCATED GLOBAL_VAR(wsrep_provider), CMD_LINE(REQUIRED_ARG, OPT_WSREP_PROVIDER), + PREALLOCATED GLOBAL_VAR(wsrep_provider), CMD_LINE(REQUIRED_ARG), IN_FS_CHARSET, DEFAULT(WSREP_NONE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(wsrep_provider_check), ON_UPDATE(wsrep_provider_update)); @@ -4447,8 +4447,8 @@ static Sys_var_charptr Sys_wsrep_provider( static Sys_var_charptr Sys_wsrep_provider_options( "wsrep_provider_options", "provider specific options", PREALLOCATED GLOBAL_VAR(wsrep_provider_options), - CMD_LINE(REQUIRED_ARG, OPT_WSREP_PROVIDER_OPTIONS), - IN_FS_CHARSET, DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG, + CMD_LINE(REQUIRED_ARG), + IN_SYSTEM_CHARSET, DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(wsrep_provider_options_check), ON_UPDATE(wsrep_provider_options_update)); @@ -4460,7 +4460,7 @@ static Sys_var_charptr Sys_wsrep_data_home_dir( static Sys_var_charptr Sys_wsrep_cluster_name( "wsrep_cluster_name", "Name for the cluster", PREALLOCATED GLOBAL_VAR(wsrep_cluster_name), CMD_LINE(REQUIRED_ARG), - IN_FS_CHARSET, DEFAULT(WSREP_CLUSTER_NAME), + IN_SYSTEM_CHARSET, DEFAULT(WSREP_CLUSTER_NAME), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(wsrep_cluster_name_check), ON_UPDATE(wsrep_cluster_name_update)); @@ -4469,8 +4469,8 @@ static PolyLock_mutex PLock_wsrep_slave_threads(&LOCK_wsrep_slave_threads); static Sys_var_charptr Sys_wsrep_cluster_address ( "wsrep_cluster_address", "Address to initially connect to cluster", PREALLOCATED GLOBAL_VAR(wsrep_cluster_address), - CMD_LINE(REQUIRED_ARG, OPT_WSREP_CLUSTER_ADDRESS), - IN_FS_CHARSET, DEFAULT(""), + CMD_LINE(REQUIRED_ARG), + IN_SYSTEM_CHARSET, DEFAULT(""), &PLock_wsrep_slave_threads, NOT_IN_BINLOG, ON_CHECK(wsrep_cluster_address_check), ON_UPDATE(wsrep_cluster_address_update)); @@ -4478,13 +4478,13 @@ static Sys_var_charptr Sys_wsrep_cluster_address ( static Sys_var_charptr Sys_wsrep_node_name ( "wsrep_node_name", "Node name", PREALLOCATED GLOBAL_VAR(wsrep_node_name), CMD_LINE(REQUIRED_ARG), - IN_FS_CHARSET, DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG, + IN_SYSTEM_CHARSET, DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG, wsrep_node_name_check, wsrep_node_name_update); static Sys_var_charptr Sys_wsrep_node_address ( "wsrep_node_address", "Node address", PREALLOCATED GLOBAL_VAR(wsrep_node_address), CMD_LINE(REQUIRED_ARG), - IN_FS_CHARSET, DEFAULT(""), + IN_SYSTEM_CHARSET, DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(wsrep_node_address_check), ON_UPDATE(wsrep_node_address_update)); @@ -4492,7 +4492,7 @@ static Sys_var_charptr Sys_wsrep_node_address ( static Sys_var_charptr Sys_wsrep_node_incoming_address( "wsrep_node_incoming_address", "Client connection address", PREALLOCATED GLOBAL_VAR(wsrep_node_incoming_address),CMD_LINE(REQUIRED_ARG), - IN_FS_CHARSET, DEFAULT(WSREP_NODE_INCOMING_AUTO)); + IN_SYSTEM_CHARSET, DEFAULT(WSREP_NODE_INCOMING_AUTO)); static Sys_var_ulong Sys_wsrep_slave_threads( "wsrep_slave_threads", "Number of slave appliers to launch", @@ -4505,7 +4505,7 @@ static Sys_var_ulong Sys_wsrep_slave_threads( static Sys_var_charptr Sys_wsrep_dbug_option( "wsrep_dbug_option", "DBUG options to provider library", GLOBAL_VAR(wsrep_dbug_option),CMD_LINE(REQUIRED_ARG), - IN_FS_CHARSET, DEFAULT("")); + IN_SYSTEM_CHARSET, DEFAULT("")); static Sys_var_mybool Sys_wsrep_debug( "wsrep_debug", "To enable debug level logging", @@ -4538,7 +4538,7 @@ static Sys_var_mybool Sys_wsrep_drupal_282555_workaround( static Sys_var_charptr sys_wsrep_sst_method( "wsrep_sst_method", "State snapshot transfer method", GLOBAL_VAR(wsrep_sst_method),CMD_LINE(REQUIRED_ARG), - IN_FS_CHARSET, DEFAULT(WSREP_SST_DEFAULT), NO_MUTEX_GUARD, NOT_IN_BINLOG, + IN_SYSTEM_CHARSET, DEFAULT(WSREP_SST_DEFAULT), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(wsrep_sst_method_check), ON_UPDATE(wsrep_sst_method_update)); @@ -4546,7 +4546,7 @@ static Sys_var_charptr Sys_wsrep_sst_receive_address( "wsrep_sst_receive_address", "Address where node is waiting for " "SST contact", GLOBAL_VAR(wsrep_sst_receive_address),CMD_LINE(REQUIRED_ARG), - IN_FS_CHARSET, DEFAULT(WSREP_SST_ADDRESS_AUTO), NO_MUTEX_GUARD, + IN_SYSTEM_CHARSET, DEFAULT(WSREP_SST_ADDRESS_AUTO), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(wsrep_sst_receive_address_check), ON_UPDATE(wsrep_sst_receive_address_update)); @@ -4554,7 +4554,7 @@ static Sys_var_charptr Sys_wsrep_sst_receive_address( static Sys_var_charptr Sys_wsrep_sst_auth( "wsrep_sst_auth", "Authentication for SST connection", PREALLOCATED GLOBAL_VAR(wsrep_sst_auth), CMD_LINE(REQUIRED_ARG, OPT_WSREP_SST_AUTH), - IN_FS_CHARSET, DEFAULT(NULL), NO_MUTEX_GUARD, + IN_SYSTEM_CHARSET, DEFAULT(NULL), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(wsrep_sst_auth_check), ON_UPDATE(wsrep_sst_auth_update)); @@ -4562,7 +4562,7 @@ static Sys_var_charptr Sys_wsrep_sst_auth( static Sys_var_charptr Sys_wsrep_sst_donor( "wsrep_sst_donor", "preferred donor node for the SST", GLOBAL_VAR(wsrep_sst_donor),CMD_LINE(REQUIRED_ARG), - IN_FS_CHARSET, DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG, + IN_SYSTEM_CHARSET, DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(wsrep_sst_donor_check), ON_UPDATE(wsrep_sst_donor_update)); @@ -4583,7 +4583,7 @@ static Sys_var_charptr Sys_wsrep_start_position ( "wsrep_start_position", "global transaction position to start from ", PREALLOCATED GLOBAL_VAR(wsrep_start_position), CMD_LINE(REQUIRED_ARG, OPT_WSREP_START_POSITION), - IN_FS_CHARSET, DEFAULT(WSREP_START_POSITION_ZERO), + IN_SYSTEM_CHARSET, DEFAULT(WSREP_START_POSITION_ZERO), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(wsrep_start_position_check), ON_UPDATE(wsrep_start_position_update)); @@ -4602,19 +4602,27 @@ static Sys_var_ulong Sys_wsrep_max_ws_rows ( static Sys_var_charptr Sys_wsrep_notify_cmd( "wsrep_notify_cmd", "", GLOBAL_VAR(wsrep_notify_cmd),CMD_LINE(REQUIRED_ARG), - IN_FS_CHARSET, DEFAULT("")); + IN_SYSTEM_CHARSET, DEFAULT("")); static Sys_var_mybool Sys_wsrep_certify_nonPK( "wsrep_certify_nonPK", "Certify tables with no primary key", GLOBAL_VAR(wsrep_certify_nonPK), CMD_LINE(OPT_ARG), DEFAULT(TRUE)); +static bool fix_wsrep_causal_reads(sys_var *self, THD* thd, enum_var_type var_type) +{ + if (var_type == OPT_GLOBAL) + wsrep_causal_reads_update(&global_system_variables); + else + wsrep_causal_reads_update(&thd->variables); + return false; +} static Sys_var_mybool Sys_wsrep_causal_reads( "wsrep_causal_reads", "(DEPRECATED) Setting this variable is equivalent " "to setting wsrep_sync_wait READ flag", SESSION_VAR(wsrep_causal_reads), CMD_LINE(OPT_ARG), DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), - ON_UPDATE(wsrep_causal_reads_update)); + ON_UPDATE(fix_wsrep_causal_reads)); static Sys_var_uint Sys_wsrep_sync_wait( "wsrep_sync_wait", "Ensure \"synchronous\" read view before executing " @@ -4642,16 +4650,17 @@ static Sys_var_mybool Sys_wsrep_desync ( ON_CHECK(wsrep_desync_check), ON_UPDATE(wsrep_desync_update)); +static const char *wsrep_binlog_format_names[]= + {"MIXED", "STATEMENT", "ROW", "NONE", NullS}; static Sys_var_enum Sys_wsrep_forced_binlog_format( "wsrep_forced_binlog_format", "binlog format to take effect over user's choice", - GLOBAL_VAR(wsrep_forced_binlog_format), - CMD_LINE(REQUIRED_ARG, OPT_BINLOG_FORMAT), + GLOBAL_VAR(wsrep_forced_binlog_format), CMD_LINE(REQUIRED_ARG), wsrep_binlog_format_names, DEFAULT(BINLOG_FORMAT_UNSPEC)); static Sys_var_mybool Sys_wsrep_recover_datadir( "wsrep_recover", "Recover database state after crash and exit", READ_ONLY GLOBAL_VAR(wsrep_recovery), - CMD_LINE(OPT_ARG, OPT_WSREP_RECOVER), DEFAULT(FALSE)); + CMD_LINE(OPT_ARG), DEFAULT(FALSE)); static Sys_var_mybool Sys_wsrep_replicate_myisam( "wsrep_replicate_myisam", "To enable myisam replication", diff --git a/sql/table.cc b/sql/table.cc index 735dbf6eedd..d720a16f6e5 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -40,7 +40,6 @@ #include "sql_statistics.h" #include "discover.h" #include "mdl.h" // MDL_wait_for_graph_visitor -#include "ha_partition.h" /* INFORMATION_SCHEMA name */ LEX_STRING INFORMATION_SCHEMA_NAME= {C_STRING_WITH_LEN("information_schema")}; diff --git a/sql/transaction.cc b/sql/transaction.cc index 9b3507de2eb..223d507a799 100644 --- a/sql/transaction.cc +++ b/sql/transaction.cc @@ -97,10 +97,8 @@ static bool xa_trans_force_rollback(THD *thd) by ha_rollback()/THD::transaction::cleanup(). */ thd->transaction.xid_state.rm_error= 0; -#ifdef WITH_WSREP if (WSREP_ON) wsrep_register_hton(thd, TRUE); -#endif /* WITH_WSREP */ if (ha_rollback_trans(thd, true)) { my_error(ER_XAER_RMERR, MYF(0)); @@ -139,18 +137,14 @@ bool trans_begin(THD *thd, uint flags) (thd->variables.option_bits & OPTION_TABLE_LOCK)) { thd->variables.option_bits&= ~OPTION_TABLE_LOCK; -#ifdef WITH_WSREP if (WSREP_ON) wsrep_register_hton(thd, TRUE); -#endif /* WITH_WSREP */ thd->server_status&= ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY); DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS")); res= MY_TEST(ha_commit_trans(thd, TRUE)); -#ifdef WITH_WSREP if (WSREP_ON) wsrep_post_commit(thd, TRUE); -#endif /* WITH_WSREP */ } thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG); @@ -230,18 +224,14 @@ bool trans_commit(THD *thd) if (trans_check(thd)) DBUG_RETURN(TRUE); -#ifdef WITH_WSREP if (WSREP_ON) wsrep_register_hton(thd, TRUE); -#endif /* WITH_WSREP */ thd->server_status&= ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY); DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS")); res= ha_commit_trans(thd, TRUE); -#ifdef WITH_WSREP if (WSREP_ON) wsrep_post_commit(thd, TRUE); -#endif /* WITH_WSREP */ /* if res is non-zero, then ha_commit_trans has rolled back the transaction, so the hooks for rollback will be called. @@ -287,18 +277,14 @@ bool trans_commit_implicit(THD *thd) /* Safety if one did "drop table" on locked tables */ if (!thd->locked_tables_mode) thd->variables.option_bits&= ~OPTION_TABLE_LOCK; -#ifdef WITH_WSREP if (WSREP_ON) wsrep_register_hton(thd, TRUE); -#endif /* WITH_WSREP */ thd->server_status&= ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY); DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS")); res= MY_TEST(ha_commit_trans(thd, TRUE)); -#ifdef WITH_WSREP if (WSREP_ON) wsrep_post_commit(thd, TRUE); -#endif /* WITH_WSREP */ } thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG); @@ -337,10 +323,8 @@ bool trans_rollback(THD *thd) if (trans_check(thd)) DBUG_RETURN(TRUE); -#ifdef WITH_WSREP if (WSREP_ON) wsrep_register_hton(thd, TRUE); -#endif /* WITH_WSREP */ thd->server_status&= ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY); DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS")); @@ -431,19 +415,15 @@ bool trans_commit_stmt(THD *thd) if (thd->transaction.stmt.ha_list) { -#ifdef WITH_WSREP if (WSREP_ON) wsrep_register_hton(thd, FALSE); -#endif /* WITH_WSREP */ res= ha_commit_trans(thd, FALSE); if (! thd->in_active_multi_stmt_transaction()) { thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation; thd->tx_read_only= thd->variables.tx_read_only; -#ifdef WITH_WSREP if (WSREP_ON) wsrep_post_commit(thd, FALSE); -#endif /* WITH_WSREP */ } } @@ -484,10 +464,8 @@ bool trans_rollback_stmt(THD *thd) if (thd->transaction.stmt.ha_list) { -#ifdef WITH_WSREP if (WSREP_ON) wsrep_register_hton(thd, FALSE); -#endif /* WITH_WSREP */ ha_rollback_trans(thd, FALSE); if (! thd->in_active_multi_stmt_transaction()) { @@ -865,17 +843,13 @@ bool trans_xa_commit(THD *thd) } else if (xa_state == XA_IDLE && thd->lex->xa_opt == XA_ONE_PHASE) { -#ifdef WITH_WSREP if (WSREP_ON) wsrep_register_hton(thd, TRUE); -#endif /* WITH_WSREP */ int r= ha_commit_trans(thd, TRUE); if ((res= MY_TEST(r))) my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0)); -#ifdef WITH_WSREP if (WSREP_ON) wsrep_post_commit(thd, TRUE); -#endif /* WITH_WSREP */ } else if (xa_state == XA_PREPARED && thd->lex->xa_opt == XA_NONE) { @@ -894,10 +868,8 @@ bool trans_xa_commit(THD *thd) if (thd->mdl_context.acquire_lock(&mdl_request, thd->variables.lock_wait_timeout)) { -#ifdef WITH_WSREP if (WSREP_ON) wsrep_register_hton(thd, TRUE); -#endif /* WITH_WSREP */ ha_rollback_trans(thd, TRUE); my_error(ER_XAER_RMERR, MYF(0)); } diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index c74bb528ebd..f47310ba49f 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -47,9 +47,6 @@ my_bool wsrep_preordered_opt= FALSE; * Begin configuration options and their default values */ -extern int wsrep_replaying; -extern ulong wsrep_running_threads; -extern ulong my_bind_addr; extern my_bool plugins_are_initialized; extern uint kill_cached_threads; extern mysql_cond_t COND_thread_cache; @@ -91,6 +88,63 @@ my_bool wsrep_slave_FK_checks = 0; // slave thread does FK checks /* * Other wsrep global variables. */ + +mysql_mutex_t LOCK_wsrep_ready; +mysql_cond_t COND_wsrep_ready; +mysql_mutex_t LOCK_wsrep_sst; +mysql_cond_t COND_wsrep_sst; +mysql_mutex_t LOCK_wsrep_sst_init; +mysql_cond_t COND_wsrep_sst_init; +mysql_mutex_t LOCK_wsrep_rollback; +mysql_cond_t COND_wsrep_rollback; +wsrep_aborting_thd_t wsrep_aborting_thd= NULL; +mysql_mutex_t LOCK_wsrep_replaying; +mysql_cond_t COND_wsrep_replaying; +mysql_mutex_t LOCK_wsrep_slave_threads; +mysql_mutex_t LOCK_wsrep_desync; +int wsrep_replaying= 0; +ulong wsrep_running_threads = 0; // # of currently running wsrep threads +ulong my_bind_addr; + +#ifdef HAVE_PSI_INTERFACE +PSI_mutex_key key_LOCK_wsrep_rollback, key_LOCK_wsrep_thd, + key_LOCK_wsrep_replaying, key_LOCK_wsrep_ready, key_LOCK_wsrep_sst, + key_LOCK_wsrep_sst_thread, key_LOCK_wsrep_sst_init, + key_LOCK_wsrep_slave_threads, key_LOCK_wsrep_desync; + +PSI_cond_key key_COND_wsrep_rollback, key_COND_wsrep_thd, + key_COND_wsrep_replaying, key_COND_wsrep_ready, key_COND_wsrep_sst, + key_COND_wsrep_sst_init, key_COND_wsrep_sst_thread; + +static PSI_mutex_info wsrep_mutexes[]= +{ + { &key_LOCK_wsrep_ready, "LOCK_wsrep_ready", PSI_FLAG_GLOBAL}, + { &key_LOCK_wsrep_sst, "LOCK_wsrep_sst", PSI_FLAG_GLOBAL}, + { &key_LOCK_wsrep_sst_thread, "wsrep_sst_thread", 0}, + { &key_LOCK_wsrep_sst_init, "LOCK_wsrep_sst_init", PSI_FLAG_GLOBAL}, + { &key_LOCK_wsrep_sst, "LOCK_wsrep_sst", PSI_FLAG_GLOBAL}, + { &key_LOCK_wsrep_rollback, "LOCK_wsrep_rollback", PSI_FLAG_GLOBAL}, + { &key_LOCK_wsrep_thd, "THD::LOCK_wsrep_thd", 0}, + { &key_LOCK_wsrep_replaying, "LOCK_wsrep_replaying", PSI_FLAG_GLOBAL}, + { &key_LOCK_wsrep_slave_threads, "LOCK_wsrep_slave_threads", PSI_FLAG_GLOBAL}, + { &key_LOCK_wsrep_desync, "LOCK_wsrep_desync", PSI_FLAG_GLOBAL} +}; + +static PSI_cond_info wsrep_conds[]= +{ + { &key_COND_wsrep_ready, "COND_wsrep_ready", PSI_FLAG_GLOBAL}, + { &key_COND_wsrep_sst, "COND_wsrep_sst", PSI_FLAG_GLOBAL}, + { &key_COND_wsrep_sst_init, "COND_wsrep_sst_init", PSI_FLAG_GLOBAL}, + { &key_COND_wsrep_sst_thread, "wsrep_sst_thread", 0}, + { &key_COND_wsrep_rollback, "COND_wsrep_rollback", PSI_FLAG_GLOBAL}, + { &key_COND_wsrep_thd, "THD::COND_wsrep_thd", 0}, + { &key_COND_wsrep_replaying, "COND_wsrep_replaying", PSI_FLAG_GLOBAL} +}; +#else +#define mysql_mutex_register(X,Y,Z) +#define mysql_cond_register(X,Y,Z) +#endif + my_bool wsrep_inited = 0; // initialized ? static const wsrep_uuid_t cluster_uuid = WSREP_UUID_UNDEFINED; @@ -517,6 +571,24 @@ int wsrep_init() int rcode= -1; DBUG_ASSERT(wsrep_inited == 0); + wsrep_causal_reads_update(&global_system_variables); + + mysql_mutex_register("sql", wsrep_mutexes, array_elements(wsrep_mutexes)); + mysql_cond_register("sql", wsrep_conds, array_elements(wsrep_conds)); + + mysql_mutex_init(key_LOCK_wsrep_ready, &LOCK_wsrep_ready, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_wsrep_ready, &COND_wsrep_ready, NULL); + mysql_mutex_init(key_LOCK_wsrep_sst, &LOCK_wsrep_sst, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_wsrep_sst, &COND_wsrep_sst, NULL); + mysql_mutex_init(key_LOCK_wsrep_sst_init, &LOCK_wsrep_sst_init, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_wsrep_sst_init, &COND_wsrep_sst_init, NULL); + mysql_mutex_init(key_LOCK_wsrep_rollback, &LOCK_wsrep_rollback, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_wsrep_rollback, &COND_wsrep_rollback, NULL); + mysql_mutex_init(key_LOCK_wsrep_replaying, &LOCK_wsrep_replaying, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_wsrep_replaying, &COND_wsrep_replaying, NULL); + mysql_mutex_init(key_LOCK_wsrep_slave_threads, &LOCK_wsrep_slave_threads, MY_MUTEX_INIT_FAST); + mysql_mutex_init(key_LOCK_wsrep_desync, &LOCK_wsrep_desync, MY_MUTEX_INIT_FAST); + wsrep_ready_set(FALSE); assert(wsrep_provider); @@ -747,6 +819,19 @@ void wsrep_deinit(bool free_options) { wsrep_sst_auth_free(); } + + mysql_mutex_destroy(&LOCK_wsrep_ready); + mysql_cond_destroy(&COND_wsrep_ready); + mysql_mutex_destroy(&LOCK_wsrep_sst); + mysql_cond_destroy(&COND_wsrep_sst); + mysql_mutex_destroy(&LOCK_wsrep_sst_init); + mysql_cond_destroy(&COND_wsrep_sst_init); + mysql_mutex_destroy(&LOCK_wsrep_rollback); + mysql_cond_destroy(&COND_wsrep_rollback); + mysql_mutex_destroy(&LOCK_wsrep_replaying); + mysql_cond_destroy(&COND_wsrep_replaying); + mysql_mutex_destroy(&LOCK_wsrep_slave_threads); + mysql_mutex_destroy(&LOCK_wsrep_desync); } void wsrep_recover() @@ -2007,7 +2092,7 @@ int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len) sp_returns_type(thd, retstr, sp); } - if (!create_string(thd, &log_query, + if (!show_create_sp(thd, &log_query, sp->m_type, (sp->m_explicit_name ? sp->m_db.str : NULL), (sp->m_explicit_name ? sp->m_db.length : 0), @@ -2238,23 +2323,6 @@ wsrep_trx_is_aborting(void *thd_ptr) } -my_bool wsrep_read_only_option(THD *thd, TABLE_LIST *all_tables) -{ - int opt_readonly_saved = opt_readonly; - ulong flag_saved = (ulong)(thd->security_ctx->master_access & SUPER_ACL); - - opt_readonly = 0; - thd->security_ctx->master_access &= ~SUPER_ACL; - - my_bool ret = !deny_updates_if_read_only_option(thd, all_tables); - - opt_readonly = opt_readonly_saved; - thd->security_ctx->master_access |= flag_saved; - - return ret; -} - - void wsrep_copy_query(THD *thd) { thd->wsrep_retry_command = thd->get_command(); diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index 2150ac85bf0..c81ed794659 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -15,9 +15,11 @@ #include -#if !defined(WSREP_MYSQLD_H) && defined(WITH_WSREP) +#ifndef WSREP_MYSQLD_H #define WSREP_MYSQLD_H +#ifdef WITH_WSREP + typedef struct st_mysql_show_var SHOW_VAR; #include //#include "rpl_gtid.h" @@ -138,7 +140,6 @@ extern const char* wsrep_provider_version; extern const char* wsrep_provider_vendor; int wsrep_show_status(THD *thd, SHOW_VAR *var, char *buff); -void wsrep_free_status(THD *thd); /* Filters out --wsrep-new-cluster oprtion from argv[] * should be called in the very beginning of main() */ @@ -219,11 +220,11 @@ extern wsrep_seqno_t wsrep_locked_seqno; // MySQL logging functions don't seem to understand long long length modifer. // This is a workaround. It also prefixes all messages with "WSREP" #define WSREP_LOG(fun, ...) \ - { \ + do { \ char msg[1024] = {'\0'}; \ snprintf(msg, sizeof(msg) - 1, ## __VA_ARGS__); \ fun("WSREP: %s", msg); \ - } + } while(0) #define WSREP_LOG_CONFLICT_THD(thd, role) \ WSREP_LOG(sql_print_information, \ @@ -298,6 +299,8 @@ extern my_bool wsrep_preordered_opt; extern handlerton *wsrep_hton; #ifdef HAVE_PSI_INTERFACE +extern PSI_mutex_key key_LOCK_wsrep_thd; +extern PSI_cond_key key_COND_wsrep_thd; extern PSI_mutex_key key_LOCK_wsrep_ready; extern PSI_mutex_key key_COND_wsrep_ready; extern PSI_mutex_key key_LOCK_wsrep_sst; @@ -356,7 +359,6 @@ void wsrep_wait_appliers_close(THD *thd); void wsrep_kill_mysql(THD *thd); void wsrep_close_threads(THD *thd); int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len); -my_bool wsrep_read_only_option(THD *thd, TABLE_LIST *all_tables); void wsrep_copy_query(THD *thd); bool wsrep_is_show_query(enum enum_sql_command command); void wsrep_replay_transaction(THD *thd); @@ -365,6 +367,32 @@ bool wsrep_create_like_table(THD* thd, TABLE_LIST* table, HA_CREATE_INFO *create_info); int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len); -extern my_bool deny_updates_if_read_only_option(THD *thd, - TABLE_LIST *all_tables); +#else /* WITH_WSREP */ + +#define WSREP(T) (0) +#define WSREP_ON (0) +#define WSREP_EMULATE_BINLOG(thd) (0) +#define WSREP_CLIENT(thd) (0) +#define wsrep_emulate_bin_log (0) +#define wsrep_xid_seqno(X) (0) +#define wsrep_is_wsrep_xid(X) (0) +#define wsrep_to_isolation (0) +#define wsrep_recovery (0) +#define wsrep_init() (1) +#define wsrep_prepend_PATH(X) +#define wsrep_before_SE() (0) +#define wsrep_init_startup(X) +#define wsrep_sync_wait(...) (0) +#define wsrep_to_isolation_begin(...) (0) +#define wsrep_register_hton(...) do { } while(0) +#define wsrep_post_commit(...) do { } while(0) +#define wsrep_check_opts() (0) +#define wsrep_stop_replication(X) do { } while(0) +#define wsrep_inited (0) +#define wsrep_deinit(X) do { } while(0) +#define wsrep_filter_new_cluster(X,Y) do { } while(0) +#define wsrep_recover() do { } while(0) +#define wsrep_slave_threads (1) + +#endif /* WITH_WSREP */ #endif /* WSREP_MYSQLD_H */ diff --git a/sql/wsrep_sst.h b/sql/wsrep_sst.h index d85fed97fca..be1dfcfa582 100644 --- a/sql/wsrep_sst.h +++ b/sql/wsrep_sst.h @@ -13,9 +13,13 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#if !defined(WSREP_SST_H) && defined(WITH_WSREP) +#include + +#ifndef WSREP_SST_H #define WSREP_SST_H +#ifdef WITH_WSREP + #include // my_bool #define WSREP_SST_OPT_ROLE "--role" @@ -65,4 +69,11 @@ extern void wsrep_SE_init_wait(); /*! wait for SE init to complete */ extern void wsrep_SE_init_done(); /*! signal that SE init is complte */ extern void wsrep_SE_initialized(); /*! mark SE initialization complete */ +#else +#define wsrep_SE_initialized() do { } while(0) +#define wsrep_SE_init_grab() do { } while(0) +#define wsrep_SE_init_done() do { } while(0) +#define wsrep_sst_continue() do { } while(0) + +#endif /* WITH_WSREP */ #endif /* WSREP_SST_H */ diff --git a/sql/wsrep_thd.h b/sql/wsrep_thd.h index c5a497bb428..cc3a7c7b9d1 100644 --- a/sql/wsrep_thd.h +++ b/sql/wsrep_thd.h @@ -13,9 +13,13 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#if !defined(WSREP_THD_H) && defined(WITH_WSREP) +#include + +#ifndef WSREP_THD_H #define WSREP_THD_H +#ifdef WITH_WSREP + #include "sql_class.h" int wsrep_show_bf_aborts (THD *thd, SHOW_VAR *var, char *buff); @@ -37,4 +41,11 @@ extern "C" my_bool wsrep_thd_is_BF_or_commit(void *thd_ptr, my_bool sync); extern "C" my_bool wsrep_thd_is_local(void *thd_ptr, my_bool sync); extern "C" int wsrep_thd_in_locking_session(void *thd_ptr); +#else /* WITH_WSREP */ + +#define wsrep_thd_is_BF(T, S) (0) +#define wsrep_abort_thd(X,Y,Z) do { } while(0) +#define wsrep_create_appliers(T) (0) + +#endif #endif /* WSREP_THD_H */ diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc index 2272945535d..3f4b163281b 100644 --- a/sql/wsrep_var.cc +++ b/sql/wsrep_var.cc @@ -60,28 +60,24 @@ bool wsrep_on_update (sys_var *self, THD* thd, enum_var_type var_type) return false; } -bool wsrep_causal_reads_update (sys_var *self, THD* thd, enum_var_type var_type) +bool wsrep_causal_reads_update (SV *sv) { - // global setting should not affect session setting. - // if (var_type == OPT_GLOBAL) { - // thd->variables.wsrep_causal_reads = global_system_variables.wsrep_causal_reads; - // } - if (thd->variables.wsrep_causal_reads) { - thd->variables.wsrep_sync_wait |= WSREP_SYNC_WAIT_BEFORE_READ; + if (sv->wsrep_causal_reads) { + sv->wsrep_sync_wait |= WSREP_SYNC_WAIT_BEFORE_READ; } else { - thd->variables.wsrep_sync_wait &= ~WSREP_SYNC_WAIT_BEFORE_READ; + sv->wsrep_sync_wait &= ~WSREP_SYNC_WAIT_BEFORE_READ; } return false; } bool wsrep_sync_wait_update (sys_var* self, THD* thd, enum_var_type var_type) { - // global setting should not affect session setting. - // if (var_type == OPT_GLOBAL) { - // thd->variables.wsrep_sync_wait = global_system_variables.wsrep_sync_wait; - // } - thd->variables.wsrep_causal_reads = thd->variables.wsrep_sync_wait & - WSREP_SYNC_WAIT_BEFORE_READ; + if (var_type == OPT_GLOBAL) + global_system_variables.wsrep_causal_reads = + MY_TEST(global_system_variables.wsrep_sync_wait & WSREP_SYNC_WAIT_BEFORE_READ); + else + thd->variables.wsrep_causal_reads = + MY_TEST(thd->variables.wsrep_sync_wait & WSREP_SYNC_WAIT_BEFORE_READ); return false; } @@ -589,14 +585,21 @@ int wsrep_show_status (THD *thd, SHOW_VAR *var, char *buff) export_wsrep_status_to_mysql(thd); var->type= SHOW_ARRAY; var->value= (char *) &mysql_status_vars; +#if 0 + {"wsrep_connected", (char*) &wsrep_connected, SHOW_BOOL}, + {"wsrep_ready", (char*) &wsrep_ready, SHOW_BOOL}, + {"wsrep_cluster_state_uuid", (char*) &wsrep_cluster_state_uuid,SHOW_CHAR_PTR}, + {"wsrep_cluster_conf_id", (char*) &wsrep_cluster_conf_id, SHOW_LONGLONG}, + {"wsrep_cluster_status", (char*) &wsrep_cluster_status, SHOW_CHAR_PTR}, + {"wsrep_cluster_size", (char*) &wsrep_cluster_size, SHOW_LONG_NOFLUSH}, + {"wsrep_local_index", (char*) &wsrep_local_index, SHOW_LONG_NOFLUSH}, + {"wsrep_local_bf_aborts", (char*) &wsrep_show_bf_aborts, SHOW_SIMPLE_FUNC}, + {"wsrep_provider_name", (char*) &wsrep_provider_name, SHOW_CHAR_PTR}, + {"wsrep_provider_version", (char*) &wsrep_provider_version, SHOW_CHAR_PTR}, + {"wsrep_provider_vendor", (char*) &wsrep_provider_vendor, SHOW_CHAR_PTR}, + {"wsrep_thread_count", (char*) &wsrep_running_threads, SHOW_LONG_NOFLUSH}, + {"wsrep", (char*) &wsrep_show_status, SHOW_FUNC}, +#endif return 0; } -void wsrep_free_status (THD* thd) -{ - if (thd->wsrep_status_vars) - { - wsrep->stats_free (wsrep, thd->wsrep_status_vars); - thd->wsrep_status_vars = 0; - } -} diff --git a/sql/wsrep_var.h b/sql/wsrep_var.h index 58d0374baa5..654b76be617 100644 --- a/sql/wsrep_var.h +++ b/sql/wsrep_var.h @@ -13,9 +13,13 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#if !defined (WSREP_VAR_H) && defined(WITH_WSREP) +#include + +#ifndef WSREP_VAR_H #define WSREP_VAR_H +#ifdef WITH_WSREP + #define WSREP_CLUSTER_NAME "my_wsrep_cluster" #define WSREP_NODE_INCOMING_AUTO "AUTO" #define WSREP_START_POSITION_ZERO "00000000-0000-0000-0000-000000000000:-1" @@ -34,8 +38,10 @@ int wsrep_init_vars(); #define DEFAULT_ARGS (THD* thd, enum_var_type var_type) #define INIT_ARGS (const char* opt) +struct system_variables; +bool wsrep_causal_reads_update(struct system_variables *sv); + extern bool wsrep_on_update UPDATE_ARGS; -extern bool wsrep_causal_reads_update UPDATE_ARGS; extern bool wsrep_sync_wait_update UPDATE_ARGS; extern bool wsrep_start_position_check CHECK_ARGS; extern bool wsrep_start_position_update UPDATE_ARGS; @@ -83,4 +89,13 @@ extern bool wsrep_slave_threads_update UPDATE_ARGS; extern bool wsrep_desync_check CHECK_ARGS; extern bool wsrep_desync_update UPDATE_ARGS; +#else /* WITH_WSREP */ + +#define WSREP_NONE +#define wsrep_provider_init(X) +#define wsrep_init_vars() (1) +#define wsrep_start_position_init(X) +#define wsrep_sst_auth_init(X) + +#endif /* WITH_WSREP */ #endif /* WSREP_VAR_H */ diff --git a/storage/innobase/wsrep/md5.cc b/storage/innobase/wsrep/md5.cc index 30be6ab7dd3..d3d83c65301 100644 --- a/storage/innobase/wsrep/md5.cc +++ b/storage/innobase/wsrep/md5.cc @@ -15,15 +15,16 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifdef WITH_WSREP +#include "my_config.h" #if defined(HAVE_YASSL) -#include "my_config.h" #include "md5.hpp" #elif defined(HAVE_OPENSSL) #include #endif /* HAVE_YASSL */ +#ifdef WITH_WSREP + /* Initialize md5 object. */ void *wsrep_md5_init() { diff --git a/storage/perfschema/CMakeLists.txt b/storage/perfschema/CMakeLists.txt index 870702afb48..b77cae6d018 100644 --- a/storage/perfschema/CMakeLists.txt +++ b/storage/perfschema/CMakeLists.txt @@ -13,10 +13,6 @@ # along with this program; if not, write to the Free Software Foundation, # 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA -IF (WITH_WSREP) - BUILD_WITH_WSREP() -ENDIF() - INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/sql diff --git a/storage/xtradb/wsrep/md5.cc b/storage/xtradb/wsrep/md5.cc index 30be6ab7dd3..d3d83c65301 100644 --- a/storage/xtradb/wsrep/md5.cc +++ b/storage/xtradb/wsrep/md5.cc @@ -15,15 +15,16 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifdef WITH_WSREP +#include "my_config.h" #if defined(HAVE_YASSL) -#include "my_config.h" #include "md5.hpp" #elif defined(HAVE_OPENSSL) #include #endif /* HAVE_YASSL */ +#ifdef WITH_WSREP + /* Initialize md5 object. */ void *wsrep_md5_init() { diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh index bdc481d39c2..caeec3f610f 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -52,7 +52,6 @@ datadir= # 0 means don't wait at all # Negative numbers mean to wait indefinitely service_startup_timeout=900 -startup_sleep=1 # Lock directory for RedHat / SuSE. lockdir='/var/lock/subsys' @@ -254,8 +253,6 @@ wait_for_gone () { wait_for_ready () { - sst_progress_file=$datadir/sst_in_progress - i=0 while test $i -ne $service_startup_timeout ; do @@ -264,14 +261,9 @@ wait_for_ready () { return 0 fi - if test -e $sst_progress_file && [ $startup_sleep -ne 10 ];then - echo $echo_n "SST in progress, setting sleep intervals to 10 seconds" - startup_sleep=10 - fi - echo $echo_n ".$echo_c" i=`expr $i + 1` - sleep $startup_sleep + sleep 1 done diff --git a/wsrep/CMakeLists.txt b/wsrep/CMakeLists.txt index d9e66739fcc..53c8e853078 100644 --- a/wsrep/CMakeLists.txt +++ b/wsrep/CMakeLists.txt @@ -13,9 +13,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -INCLUDE_DIRECTORIES( "." ) -BUILD_WITH_WSREP() - SET(WSREP_SOURCES wsrep_gtid.c wsrep_uuid.c wsrep_loader.c wsrep_dummy.c) ADD_CONVENIENCE_LIBRARY(wsrep ${WSREP_SOURCES}) From 4b9bf9d3b87005d6570d76f9de074615d7f8ca36 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 26 Sep 2014 07:04:33 +0200 Subject: [PATCH 064/153] bugfix: remove the code that broke XA recovery --- sql/log.h | 6 +----- sql/mysqld.cc | 3 --- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/sql/log.h b/sql/log.h index 619d7ed19cd..ac1e9f4a70f 100644 --- a/sql/log.h +++ b/sql/log.h @@ -108,11 +108,7 @@ public: int log_and_order(THD *thd, my_xid xid, bool all, bool need_prepare_ordered, bool need_commit_ordered) { - /* - If we are not using WSREP this is an Internal error - - TC_LOG_DUMMY::log_and_order() called - */ - DBUG_ASSERT(IF_WSREP(1,0)); + DBUG_ASSERT(0); return 1; } int unlog(ulong cookie, my_xid xid) { return 0; } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index f842c835f24..e329e2e3ce8 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5101,9 +5101,6 @@ a file name for --log-bin-index option", opt_binlog_index_name); tc_log= get_tc_log_implementation(); - if (WSREP_ON && tc_log == &tc_log_mmap) - tc_log= &tc_log_dummy; - WSREP_DEBUG("Initial TC log open: %s", (tc_log == &mysql_bin_log) ? "binlog" : (tc_log == &tc_log_mmap) ? "mmap" : From d06b5b6a2d37323157bd50060c6ed2bf7f8fe4d8 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 26 Sep 2014 10:22:18 +0200 Subject: [PATCH 065/153] disable wsrep by default. fix wsrep not to crash when started disabled --- sql/mysqld.cc | 4 +++- sql/sys_vars.cc | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index e329e2e3ce8..7fe1adc346e 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5664,6 +5664,8 @@ int mysqld_main(int argc, char **argv) wsrep_create_appliers(wsrep_slave_threads - 1); } } + else + wsrep_init_startup (false); if (opt_bootstrap) { @@ -8523,7 +8525,7 @@ static int mysql_init_variables(void) strmake_buf(mysql_home, tmpenv); #endif - if (WSREP_ON && wsrep_init_vars()) + if (wsrep_init_vars()) return 1; return 0; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 046f68e574e..5722cd38de5 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -4575,7 +4575,7 @@ static Sys_var_mybool Sys_wsrep_sst_donor_rejects_queries( static Sys_var_mybool Sys_wsrep_on ( "wsrep_on", "To enable wsrep replication ", SESSION_VAR(wsrep_on), - CMD_LINE(OPT_ARG), DEFAULT(TRUE), + CMD_LINE(OPT_ARG), DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(wsrep_on_update)); From dc113e2765c19cc3b1dff7c6141701411c93ce42 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 26 Sep 2014 12:55:56 +0200 Subject: [PATCH 066/153] fix cmake detection of bfd.h --- configure.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/configure.cmake b/configure.cmake index 4adc977b192..c562b583830 100644 --- a/configure.cmake +++ b/configure.cmake @@ -186,7 +186,6 @@ CHECK_INCLUDE_FILES (aio.h HAVE_AIO_H) CHECK_INCLUDE_FILES (arpa/inet.h HAVE_ARPA_INET_H) CHECK_INCLUDE_FILES (crypt.h HAVE_CRYPT_H) CHECK_INCLUDE_FILE_CXX (cxxabi.h HAVE_CXXABI_H) -CHECK_INCLUDE_FILES (bfd.h BFD_H_EXISTS) CHECK_INCLUDE_FILES (dirent.h HAVE_DIRENT_H) CHECK_INCLUDE_FILES (dlfcn.h HAVE_DLFCN_H) CHECK_INCLUDE_FILES (execinfo.h HAVE_EXECINFO_H) @@ -262,6 +261,8 @@ CHECK_INCLUDE_FILES (wctype.h HAVE_WCTYPE_H) CHECK_INCLUDE_FILES (sys/sockio.h HAVE_SYS_SOCKIO_H) CHECK_INCLUDE_FILES (sys/utsname.h HAVE_SYS_UTSNAME_H) +SET(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -DPACKAGE=test) # bfd.h is picky +CHECK_INCLUDE_FILES (bfd.h BFD_H_EXISTS) IF(BFD_H_EXISTS) IF(NOT_FOR_DISTRIBUTION) SET(NON_DISTRIBUTABLE_WARNING 1) From 4bb49d84a9df8c3f29683bfe8503a575bc0ab84b Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 26 Sep 2014 15:54:42 +0200 Subject: [PATCH 067/153] correct handling on defaults[-extra]-file is SST scripts pass --defaults-file and --defaults-extra-file (whatever was specified, or none) from mysqld down to SST scripts. parse these options in SST scripts and pass them down to mysqldump, my_print_defaults, and xtrabackup --- mysys/my_default.c | 12 ----------- scripts/wsrep_sst_common.sh | 16 ++++++++++++--- scripts/wsrep_sst_mysqldump.sh | 4 ---- scripts/wsrep_sst_rsync.sh | 4 +--- scripts/wsrep_sst_xtrabackup-v2.sh | 16 +++++++-------- scripts/wsrep_sst_xtrabackup.sh | 18 ++++++++-------- sql/wsrep_sst.cc | 33 ++++++++++++++++++++++++++---- sql/wsrep_sst.h | 1 + 8 files changed, 61 insertions(+), 43 deletions(-) diff --git a/mysys/my_default.c b/mysys/my_default.c index 1a29fd87a34..1e4038d17fb 100644 --- a/mysys/my_default.c +++ b/mysys/my_default.c @@ -88,12 +88,6 @@ static char my_defaults_extra_file_buffer[FN_REFLEN]; static my_bool defaults_already_read= FALSE; -#ifdef WITH_WSREP -/* The only purpose of this global array is to hold full name of my.cnf - * which seems to be otherwise unavailable */ -char wsrep_defaults_file[FN_REFLEN + 10]={0,}; -#endif /* WITH_WREP */ - /* Which directories are searched for options (and in which order) */ #define MAX_DEFAULT_DIRS 6 @@ -810,12 +804,6 @@ static int search_default_file_with_ext(Process_option_func opt_handler, if (!(fp= mysql_file_fopen(key_file_cnf, name, O_RDONLY, MYF(0)))) return 1; /* Ignore wrong files */ -#ifdef WITH_WSREP - /* make sure we do this only once - for top-level file */ - if ('\0' == wsrep_defaults_file[0]) - strmake(wsrep_defaults_file, name, sizeof(wsrep_defaults_file) - 1); -#endif /* WITH_WSREP */ - while (mysql_file_fgets(buff, sizeof(buff) - 1, fp)) { line++; diff --git a/scripts/wsrep_sst_common.sh b/scripts/wsrep_sst_common.sh index 88f5d80f53a..574657f1a76 100644 --- a/scripts/wsrep_sst_common.sh +++ b/scripts/wsrep_sst_common.sh @@ -22,6 +22,9 @@ WSREP_SST_OPT_BYPASS=0 WSREP_SST_OPT_BINLOG="" WSREP_SST_OPT_DATA="" WSREP_SST_OPT_AUTH="" +WSREP_SST_OPT_DEFAULT="" +WSREP_SST_OPT_EXTRA_DEFAULT="" + while [ $# -gt 0 ]; do case "$1" in @@ -41,7 +44,11 @@ case "$1" in shift ;; '--defaults-file') - readonly WSREP_SST_OPT_CONF="$2" + readonly WSREP_SST_OPT_DEFAULT="$1=$2" + shift + ;; + '--defaults-extra-file') + readonly WSREP_SST_OPT_EXTRA_DEFAULT="$1=$2" shift ;; '--host') @@ -94,10 +101,13 @@ done readonly WSREP_SST_OPT_BYPASS readonly WSREP_SST_OPT_BINLOG +readonly WSREP_SST_OPT_CONF="$WSREP_SST_OPT_DEFAULT $WSREP_SST_OPT_EXTRA_DEFAULT" +readonly my_print_defaults="my_print_defaults $WSREP_SST_OPT_CONF" + # State Snapshot Transfer authentication password was displayed in the ps output. Bug fixed #1200727. -if my_print_defaults -c $WSREP_SST_OPT_CONF sst | grep -q "wsrep_sst_auth";then +if $my_print_defaults sst | grep -q "wsrep_sst_auth";then if [ -z "$WSREP_SST_OPT_AUTH" -o "$WSREP_SST_OPT_AUTH" = "(null)" ];then - WSREP_SST_OPT_AUTH=$(my_print_defaults -c $WSREP_SST_OPT_CONF sst | grep -- "--wsrep_sst_auth" | cut -d= -f2) + WSREP_SST_OPT_AUTH=$($my_print_defaults sst | grep -- "--wsrep_sst_auth" | cut -d= -f2) fi fi diff --git a/scripts/wsrep_sst_mysqldump.sh b/scripts/wsrep_sst_mysqldump.sh index d4093dbcaef..6a863d7714d 100644 --- a/scripts/wsrep_sst_mysqldump.sh +++ b/scripts/wsrep_sst_mysqldump.sh @@ -17,10 +17,6 @@ # This is a reference script for mysqldump-based state snapshot tansfer -# This variable is not used in mysqldump sst, so better initialize it -# to avoid shell's "parameter not set" message. -WSREP_SST_OPT_CONF="" - . $(dirname $0)/wsrep_sst_common EINVAL=22 diff --git a/scripts/wsrep_sst_rsync.sh b/scripts/wsrep_sst_rsync.sh index 86bf557662d..7bcc398c727 100644 --- a/scripts/wsrep_sst_rsync.sh +++ b/scripts/wsrep_sst_rsync.sh @@ -92,9 +92,7 @@ fi WSREP_LOG_DIR=${WSREP_LOG_DIR:-""} # if WSREP_LOG_DIR env. variable is not set, try to get it from my.cnf if [ -z "$WSREP_LOG_DIR" ]; then - SCRIPT_DIR="$(cd $(dirname "$0"); pwd -P)" - WSREP_LOG_DIR=$($SCRIPT_DIR/my_print_defaults --defaults-file \ - "$WSREP_SST_OPT_CONF" mysqld server mysqld-10.0 mariadb mariadb-10.0 \ + WSREP_LOG_DIR=$($my_print_defaults --mysqld \ | grep -- '--innodb[-_]log[-_]group[-_]home[-_]dir=' \ | cut -b 29- ) fi diff --git a/scripts/wsrep_sst_xtrabackup-v2.sh b/scripts/wsrep_sst_xtrabackup-v2.sh index f4d133d4f8e..dab0201f067 100644 --- a/scripts/wsrep_sst_xtrabackup-v2.sh +++ b/scripts/wsrep_sst_xtrabackup-v2.sh @@ -117,7 +117,7 @@ get_keys() fi if [[ $encrypt -eq 0 ]];then - if my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -q encrypt;then + if $my_print_defaults xtrabackup | grep -q encrypt;then wsrep_log_error "Unexpected option combination. SST may fail. Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html " fi return @@ -230,7 +230,7 @@ parse_cnf() { local group=$1 local var=$2 - reval=$(my_print_defaults -c $WSREP_SST_OPT_CONF $group | awk -F= '{if ($1 ~ /_/) { gsub(/_/,"-",$1); print $1"="$2 } else { print $0 }}' | grep -- "--$var=" | cut -d= -f2-) + reval=$($my_print_defaults $group | awk -F= '{if ($1 ~ /_/) { gsub(/_/,"-",$1); print $1"="$2 } else { print $0 }}' | grep -- "--$var=" | cut -d= -f2-) if [[ -z $reval ]];then [[ -n $3 ]] && reval=$3 fi @@ -241,7 +241,7 @@ get_footprint() { pushd $WSREP_SST_OPT_DATA 1>/dev/null payload=$(find . -regex '.*\.ibd$\|.*\.MYI$\|.*\.MYD$\|.*ibdata1$' -type f -print0 | xargs -0 du --block-size=1 -c | awk 'END { print $1 }') - if my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -q -- "--compress";then + if $my_print_defaults xtrabackup | grep -q -- "--compress";then # QuickLZ has around 50% compression ratio # When compression/compaction used, the progress is only an approximate. payload=$(( payload*1/2 )) @@ -443,8 +443,8 @@ check_extra() { local use_socket=1 if [[ $uextra -eq 1 ]];then - if my_print_defaults -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--thread-handling=" | grep -q 'pool-of-threads';then - local eport=$(my_print_defaults -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--extra-port=" | cut -d= -f2) + if $my_print_defaults --mysqld | tr '_' '-' | grep -- "--thread-handling=" | grep -q 'pool-of-threads';then + local eport=$($my_print_defaults --mysqld | tr '_' '-' | grep -- "--extra-port=" | cut -d= -f2) if [[ -n $eport ]];then # Xtrabackup works only locally. # Hence, setting host to 127.0.0.1 unconditionally. @@ -557,8 +557,8 @@ fi INNOEXTRA="" INNOAPPLY="${INNOBACKUPEX_BIN} $disver $iapts --apply-log \$rebuildcmd \${DATA} &>\${DATA}/innobackup.prepare.log" -INNOMOVE="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} $disver $impts --move-back --force-non-empty-directories \${DATA} &>\${DATA}/innobackup.move.log" -INNOBACKUP="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} $disver $iopts \$tmpopts \$INNOEXTRA --galera-info --stream=\$sfmt \$itmpdir 2>\${DATA}/innobackup.backup.log" +INNOMOVE="${INNOBACKUPEX_BIN} ${WSREP_SST_OPT_CONF} $disver $impts --move-back --force-non-empty-directories \${DATA} &>\${DATA}/innobackup.move.log" +INNOBACKUP="${INNOBACKUPEX_BIN} ${WSREP_SST_OPT_CONF} $disver $iopts \$tmpopts \$INNOEXTRA --galera-info --stream=\$sfmt \$itmpdir 2>\${DATA}/innobackup.backup.log" if [ "$WSREP_SST_OPT_ROLE" = "donor" ] then @@ -879,7 +879,7 @@ then if [[ $incremental -eq 1 ]];then # Added --ibbackup=xtrabackup_55 because it fails otherwise citing connection issues. - INNOAPPLY="${INNOBACKUPEX_BIN} $disver --defaults-file=${WSREP_SST_OPT_CONF} \ + INNOAPPLY="${INNOBACKUPEX_BIN} $disver ${WSREP_SST_OPT_CONF} \ --ibbackup=xtrabackup_56 --apply-log $rebuildcmd --redo-only $BDATA --incremental-dir=${DATA} &>>${BDATA}/innobackup.prepare.log" fi diff --git a/scripts/wsrep_sst_xtrabackup.sh b/scripts/wsrep_sst_xtrabackup.sh index 6b33eabee23..0aac7dc50d2 100644 --- a/scripts/wsrep_sst_xtrabackup.sh +++ b/scripts/wsrep_sst_xtrabackup.sh @@ -100,7 +100,7 @@ get_keys() fi if [[ $encrypt -eq 0 ]];then - if my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -q encrypt;then + if $my_print_defaults xtrabackup | grep -q encrypt;then wsrep_log_error "Unexpected option combination. SST may fail. Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html " fi return @@ -195,7 +195,7 @@ parse_cnf() { local group=$1 local var=$2 - reval=$(my_print_defaults -c $WSREP_SST_OPT_CONF $group | awk -F= '{if ($1 ~ /_/) { gsub(/_/,"-",$1); print $1"="$2 } else { print $0 }}' | grep -- "--$var=" | cut -d= -f2-) + reval=$($my_print_defaults $group | awk -F= '{if ($1 ~ /_/) { gsub(/_/,"-",$1); print $1"="$2 } else { print $0 }}' | grep -- "--$var=" | cut -d= -f2-) if [[ -z $reval ]];then [[ -n $3 ]] && reval=$3 fi @@ -206,7 +206,7 @@ get_footprint() { pushd $WSREP_SST_OPT_DATA 1>/dev/null payload=$(find . -regex '.*\.ibd$\|.*\.MYI$\|.*\.MYD$\|.*ibdata1$' -type f -print0 | xargs -0 du --block-size=1 -c | awk 'END { print $1 }') - if my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -q -- "--compress";then + if $my_print_defaults xtrabackup | grep -q -- "--compress";then # QuickLZ has around 50% compression ratio # When compression/compaction used, the progress is only an approximate. payload=$(( payload*1/2 )) @@ -385,8 +385,8 @@ check_extra() { local use_socket=1 if [[ $uextra -eq 1 ]];then - if my_print_defaults -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--thread-handling=" | grep -q 'pool-of-threads';then - local eport=$(my_print_defaults -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--extra-port=" | cut -d= -f2) + if $my_print_defaults --mysqld | tr '_' '-' | grep -- "--thread-handling=" | grep -q 'pool-of-threads';then + local eport=$($my_print_defaults --mysqld | tr '_' '-' | grep -- "--extra-port=" | cut -d= -f2) if [[ -n $eport ]];then # Xtrabackup works only locally. # Hence, setting host to 127.0.0.1 unconditionally. @@ -424,8 +424,8 @@ get_stream get_transfer INNOEXTRA="" -INNOAPPLY="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} --apply-log \$rebuildcmd \${DATA} &>\${DATA}/innobackup.prepare.log" -INNOBACKUP="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} \$INNOEXTRA --galera-info --stream=\$sfmt \${TMPDIR} 2>\${DATA}/innobackup.backup.log" +INNOAPPLY="${INNOBACKUPEX_BIN} ${WSREP_SST_OPT_CONF} --apply-log \$rebuildcmd \${DATA} &>\${DATA}/innobackup.prepare.log" +INNOBACKUP="${INNOBACKUPEX_BIN} ${WSREP_SST_OPT_CONF} \$INNOEXTRA --galera-info --stream=\$sfmt \${TMPDIR} 2>\${DATA}/innobackup.backup.log" if [ "$WSREP_SST_OPT_ROLE" = "donor" ] then @@ -528,7 +528,7 @@ then if [[ $incremental -eq 1 ]];then wsrep_log_info "Incremental SST enabled" - #lsn=$(/pxc/bin/mysqld --defaults-file=$WSREP_SST_OPT_CONF --basedir=/pxc --wsrep-recover 2>&1 | grep -o 'log sequence number .*' | cut -d " " -f 4 | head -1) + #lsn=$(/pxc/bin/mysqld $WSREP_SST_OPT_CONF --basedir=/pxc --wsrep-recover 2>&1 | grep -o 'log sequence number .*' | cut -d " " -f 4 | head -1) lsn=$(grep to_lsn xtrabackup_checkpoints | cut -d= -f2 | tr -d ' ') wsrep_log_info "Recovered LSN: $lsn" fi @@ -681,7 +681,7 @@ then if [[ $incremental -eq 1 ]];then # Added --ibbackup=xtrabackup_55 because it fails otherwise citing connection issues. - INNOAPPLY="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} \ + INNOAPPLY="${INNOBACKUPEX_BIN} ${WSREP_SST_OPT_CONF} \ --ibbackup=xtrabackup_55 --apply-log $rebuildcmd --redo-only $BDATA --incremental-dir=${DATA} &>>${BDATA}/innobackup.prepare.log" fi diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc index c122d88f7cc..17943308c37 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -29,7 +29,9 @@ #include #include -extern const char wsrep_defaults_file[]; +char wsrep_defaults_file[FN_REFLEN * 2 + 10 + + sizeof(WSREP_SST_OPT_CONF) + + sizeof(WSREP_SST_OPT_EXTRA_CONF)] = {0}; const char* wsrep_sst_method = WSREP_SST_DEFAULT; const char* wsrep_sst_receive_address = WSREP_SST_ADDRESS_AUTO; @@ -59,6 +61,24 @@ bool wsrep_sst_method_update (sys_var *self, THD* thd, enum_var_type type) return 0; } + +static void make_wsrep_defaults_file() +{ + if (!wsrep_defaults_file[0]) + { + char *ptr= wsrep_defaults_file; + char *end= ptr + sizeof(wsrep_defaults_file); + if (my_defaults_file) + ptr= strxnmov(ptr, end - ptr, + WSREP_SST_OPT_CONF, " '", my_defaults_file, "' ", NULL); + + if (my_defaults_extra_file) + ptr= strxnmov(ptr, end - ptr, + WSREP_SST_OPT_EXTRA_CONF, " '", my_defaults_extra_file, "' ", NULL); + } +} + + // TODO: Improve address verification. static bool sst_receive_address_check (const char* str) { @@ -455,6 +475,7 @@ static ssize_t sst_prepare_other (const char* method, } if (strlen(binlog_opt_val)) binlog_opt= WSREP_SST_OPT_BINLOG; + make_wsrep_defaults_file(); ret= snprintf (cmd_str, cmd_len, "wsrep_sst_%s " @@ -462,7 +483,7 @@ static ssize_t sst_prepare_other (const char* method, WSREP_SST_OPT_ADDR" '%s' " WSREP_SST_OPT_AUTH" '%s' " WSREP_SST_OPT_DATA" '%s' " - WSREP_SST_OPT_CONF" '%s' " + " %s " WSREP_SST_OPT_PARENT" '%d'" " %s '%s' ", method, addr_in, (sst_auth_real) ? sst_auth_real : "", @@ -754,6 +775,8 @@ static int sst_donate_mysqldump (const char* addr, if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(TRUE); + make_wsrep_defaults_file(); + snprintf (cmd_str, cmd_len, "wsrep_sst_mysqldump " WSREP_SST_OPT_USER" '%s' " @@ -762,7 +785,7 @@ static int sst_donate_mysqldump (const char* addr, WSREP_SST_OPT_PORT" '%s' " WSREP_SST_OPT_LPORT" '%u' " WSREP_SST_OPT_SOCKET" '%s' " - WSREP_SST_OPT_CONF" '%s' " + " %s " WSREP_SST_OPT_GTID" '%s:%lld'" "%s", user, pswd, host, port, mysqld_port, mysqld_unix_port, @@ -1027,6 +1050,8 @@ static int sst_donate_other (const char* method, } if (strlen(binlog_opt_val)) binlog_opt= WSREP_SST_OPT_BINLOG; + make_wsrep_defaults_file(); + ret= snprintf (cmd_str, cmd_len, "wsrep_sst_%s " WSREP_SST_OPT_ROLE" 'donor' " @@ -1034,7 +1059,7 @@ static int sst_donate_other (const char* method, WSREP_SST_OPT_AUTH" '%s' " WSREP_SST_OPT_SOCKET" '%s' " WSREP_SST_OPT_DATA" '%s' " - WSREP_SST_OPT_CONF" '%s' " + " %s " " %s '%s' " WSREP_SST_OPT_GTID" '%s:%lld'" "%s", diff --git a/sql/wsrep_sst.h b/sql/wsrep_sst.h index be1dfcfa582..2a6ab406297 100644 --- a/sql/wsrep_sst.h +++ b/sql/wsrep_sst.h @@ -27,6 +27,7 @@ #define WSREP_SST_OPT_AUTH "--auth" #define WSREP_SST_OPT_DATA "--datadir" #define WSREP_SST_OPT_CONF "--defaults-file" +#define WSREP_SST_OPT_EXTRA_CONF "--defaults-extra-file" #define WSREP_SST_OPT_PARENT "--parent" #define WSREP_SST_OPT_BINLOG "--binlog" From 93b50e64a04efd54ab1ef64f593da0d4a7de6fb6 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 26 Sep 2014 10:22:44 +0200 Subject: [PATCH 068/153] cleanup: remove galera/wsrep magic from mtr --- mysql-test/include/mtr_check.sql | 1 - mysql-test/include/mtr_warnings.sql | 8 -- mysql-test/include/not_wsrep.inc | 7 - mysql-test/lib/mtr_cases.pm | 3 - mysql-test/mysql-test-run.pl | 62 +-------- mysql-test/r/mysqld--help.result | 125 ------------------ mysql-test/r/not_wsrep.require | 2 - mysql-test/suite/galera/my.cnf | 1 - .../wsrep}/include/galera_cluster.inc | 0 .../wsrep}/include/galera_connect.inc | 0 .../{ => suite/wsrep}/include/galera_diff.inc | 0 .../{ => suite/wsrep}/include/galera_end.inc | 0 .../{ => suite/wsrep}/include/galera_init.inc | 0 .../wsrep}/include/have_wsrep_enabled.inc | 2 + .../galera_2nodes.cnf => wsrep/my.cnf} | 25 ++-- .../suite/{galera => wsrep}/r/basic.result | 0 .../suite/{galera => wsrep}/r/grant.result | 0 .../{galera => wsrep}/r/partition.result | 0 .../{galera => wsrep}/r/unique_key.result | 0 mysql-test/suite/wsrep/suite.pm | 38 ++++++ .../suite/{galera => wsrep}/t/basic.test | 0 mysql-test/suite/wsrep/t/binlog_format.opt | 2 +- .../suite/{galera => wsrep}/t/grant.test | 0 .../suite/{galera => wsrep}/t/partition.test | 0 mysql-test/suite/wsrep/t/pool_of_threads.opt | 2 +- mysql-test/suite/wsrep/t/pool_of_threads.test | 2 +- .../suite/{galera => wsrep}/t/unique_key.test | 3 - mysql-test/t/mysqld--help.test | 5 +- 28 files changed, 62 insertions(+), 226 deletions(-) delete mode 100644 mysql-test/include/not_wsrep.inc delete mode 100644 mysql-test/r/not_wsrep.require delete mode 100644 mysql-test/suite/galera/my.cnf rename mysql-test/{ => suite/wsrep}/include/galera_cluster.inc (100%) rename mysql-test/{ => suite/wsrep}/include/galera_connect.inc (100%) rename mysql-test/{ => suite/wsrep}/include/galera_diff.inc (100%) rename mysql-test/{ => suite/wsrep}/include/galera_end.inc (100%) rename mysql-test/{ => suite/wsrep}/include/galera_init.inc (100%) rename mysql-test/{ => suite/wsrep}/include/have_wsrep_enabled.inc (90%) rename mysql-test/suite/{galera/galera_2nodes.cnf => wsrep/my.cnf} (72%) rename mysql-test/suite/{galera => wsrep}/r/basic.result (100%) rename mysql-test/suite/{galera => wsrep}/r/grant.result (100%) rename mysql-test/suite/{galera => wsrep}/r/partition.result (100%) rename mysql-test/suite/{galera => wsrep}/r/unique_key.result (100%) create mode 100644 mysql-test/suite/wsrep/suite.pm rename mysql-test/suite/{galera => wsrep}/t/basic.test (100%) rename mysql-test/suite/{galera => wsrep}/t/grant.test (100%) rename mysql-test/suite/{galera => wsrep}/t/partition.test (100%) rename mysql-test/suite/{galera => wsrep}/t/unique_key.test (96%) diff --git a/mysql-test/include/mtr_check.sql b/mysql-test/include/mtr_check.sql index edc15850d97..e34e32ad1a6 100644 --- a/mysql-test/include/mtr_check.sql +++ b/mysql-test/include/mtr_check.sql @@ -34,7 +34,6 @@ BEGIN AND variable_name != 'INNODB_USE_NATIVE_AIO' AND variable_name not like 'GTID%POS' AND variable_name != 'GTID_BINLOG_STATE' - AND variable_name != 'WSREP_DATA_HOME_DIR' ORDER BY variable_name; -- Dump all databases, there should be none diff --git a/mysql-test/include/mtr_warnings.sql b/mysql-test/include/mtr_warnings.sql index 06a7b49e979..0ad1079cd92 100644 --- a/mysql-test/include/mtr_warnings.sql +++ b/mysql-test/include/mtr_warnings.sql @@ -226,14 +226,6 @@ INSERT INTO global_suppressions VALUES ("Slave I/O: Notifying master by SET @master_binlog_checksum= @@global.binlog_checksum failed with error.*"), ("Slave I/O: Setting master-side filtering of @@skip_replication failed with error:.*"), ("Slave I/O: Setting @mariadb_slave_capability failed with error:.*"), - - /* - Galera-related warnings. - */ - ("WSREP: Could not open saved state file for reading: .*"), - ("WSREP: last inactive check more than .* skipping check"), - ("WSREP: Gap in state sequence. Need state transfer."), - ("WSREP: Failed to prepare for incremental state transfer: .*"), ("THE_LAST_SUPPRESSION")|| diff --git a/mysql-test/include/not_wsrep.inc b/mysql-test/include/not_wsrep.inc deleted file mode 100644 index 3314b5c8717..00000000000 --- a/mysql-test/include/not_wsrep.inc +++ /dev/null @@ -1,7 +0,0 @@ -# To be used in a test which should be skipped if server is compiled with wsrep -# support (-DWITH_WSREP=ON) and wsrep plugin is ACTIVE. - --- require r/not_wsrep.require -disable_query_log; -SELECT VERSION() LIKE '%wsrep%' AS 'HAVE_WSREP'; -enable_query_log; diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm index 7415b229862..441fd6e6559 100644 --- a/mysql-test/lib/mtr_cases.pm +++ b/mysql-test/lib/mtr_cases.pm @@ -861,8 +861,6 @@ sub collect_one_test_case { # Suite has no config, autodetect which one to use if ($tinfo->{rpl_test}) { $config= "suite/rpl/my.cnf"; - } elsif ($tinfo->{galera_test}) { - $config= "suite/galera/my.cnf"; } else { $config= "include/default_my.cnf"; } @@ -983,7 +981,6 @@ my $tags_map= {'big_test' => ['big_test', 1], 'master-slave' => ['rpl_test', 1], 'ndb_master-slave' => ['rpl_test', 1, 'ndb_test', 1], 'long_test' => ['long_test', 1], - 'galera_init' => ['galera_test', 1], }; my $tags_regex_string= join('|', keys %$tags_map); my $tags_regex= qr:include/($tags_regex_string)\.inc:o; diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 61f9538c1b4..861bc875896 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -137,6 +137,8 @@ my $opt_start_exit; my $start_only; my $file_wsrep_provider; +our @global_suppressions; + END { if ( defined $opt_tmpdir_pid and $opt_tmpdir_pid == $$ ) { @@ -188,6 +190,7 @@ my @DEFAULT_SUITES= qw( sys_vars- unit- vcol- + wsrep- ); my $opt_suites; @@ -413,7 +416,6 @@ sub main { check_ndbcluster_support(); check_ssl_support(); check_debug_support(); - check_wsrep_support(); if (!$opt_suites) { $opt_suites= join ',', collect_default_suites(@DEFAULT_SUITES); @@ -2399,24 +2401,6 @@ sub environment_setup { $ENV{'NDB_EXAMPLES_OUTPUT'}= $path_ndb_testrun_log; } - # ---------------------------------------------------- - # Setup env for wsrep - # ---------------------------------------------------- - if (have_wsrep()) { - if (defined $ENV{'WSREP_PROVIDER'} ) { - # Nothing needs to be done! WSREP_PROVIDER env is already set & checked; - # will be used. - } else { - $ENV{'WSREP_PROVIDER'}= $file_wsrep_provider; - } - - if ($ENV{'WSREP_PROVIDER'} ne "") { - mtr_verbose("WSREP_PROVIDER set to $ENV{'WSREP_PROVIDER'}"); - } else { - mtr_verbose("WSREP_PROVIDER isn't available"); - } - } - # ---------------------------------------------------- # mysql clients # ---------------------------------------------------- @@ -3194,41 +3178,6 @@ sub ndbcluster_start ($) { return 0; } -sub have_wsrep() { - my $wsrep_on= $mysqld_variables{'wsrep-on'}; - return defined $wsrep_on -} - -sub check_wsrep_provider_env { - if (defined $ENV{'WSREP_PROVIDER'}) { - if (mtr_file_exists($ENV{'WSREP_PROVIDER'}) eq "") { - mtr_error("WSREP_PROVIDER env set to an invalid path"); - return 0; # error - } - # Ok, WSREP_PROVIDER set to a valid path. - return 1; - } - # Ok, WSREP_PROVIDER not defined. - return 2; -} - -sub check_wsrep_support() { - if (have_wsrep()) - { - mtr_report(" - binaries built with wsrep patch"); - - $file_wsrep_provider= - mtr_file_exists("/usr/lib/galera/libgalera_smm.so", - "/usr/lib64/galera/libgalera_smm.so"); - - if ((check_wsrep_provider_env() == 1) || ($file_wsrep_provider ne "")) { - # Add galera test suites - mtr_report(" - adding wsrep, galera to default test suites"); - push @DEFAULT_SUITES, qw(wsrep galera); - } - } -} - sub mysql_server_start($) { my ($mysqld, $tinfo) = @_; @@ -4837,6 +4786,7 @@ sub extract_warning_lines ($$) { # Perl code. my @antipatterns = ( + @global_suppressions, qr/error .*connecting to master/, qr/Plugin 'ndbcluster' will be forced to shutdown/, qr/InnoDB: Error: in ALTER TABLE `test`.`t[12]`/, @@ -4891,10 +4841,6 @@ sub extract_warning_lines ($$) { qr|Plugin 'FEEDBACK' registration as a INFORMATION SCHEMA failed|, qr|'log-bin-use-v1-row-events' is MySQL 5.6 compatible option|, qr|InnoDB: Setting thread \d+ nice to \d+ failed, current nice \d+, errno 13|, # setpriority() fails under valgrind - # Galera-related warnings. - qr|WSREP:.*down context.*|, - qr|WSREP: Failed to send state UUID:.*|, - qr|WSREP: wsrep_sst_receive_address.*|, ); my $matched_lines= []; diff --git a/mysql-test/r/mysqld--help.result b/mysql-test/r/mysqld--help.result index 6953a05fd5c..5a2142c402c 100644 --- a/mysql-test/r/mysqld--help.result +++ b/mysql-test/r/mysqld--help.result @@ -1065,93 +1065,6 @@ The following options may be given as the first argument: -V, --version Output version information and exit. --wait-timeout=# The number of seconds the server waits for activity on a connection before closing it - --wsrep-OSU-method[=name] - Method for Online Schema Upgrade - --wsrep-auto-increment-control - To automatically control the assignment of autoincrement - variables - (Defaults to on; use --skip-wsrep-auto-increment-control to disable.) - --wsrep-causal-reads - (DEPRECATED) Setting this variable is equivalent to - setting wsrep_sync_wait READ flag - --wsrep-certify-nonPK - Certify tables with no primary key - (Defaults to on; use --skip-wsrep-certify-nonPK to disable.) - --wsrep-cluster-address=name - Address to initially connect to cluster - --wsrep-cluster-name=name - Name for the cluster - --wsrep-convert-LOCK-to-trx - To convert locking sessions into transactions - --wsrep-data-home-dir=name - home directory for wsrep provider - --wsrep-dbug-option=name - DBUG options to provider library - --wsrep-debug To enable debug level logging - --wsrep-desync To desynchronize the node from the cluster - --wsrep-drupal-282555-workaround - To use a workaround forbad autoincrement value - --wsrep-forced-binlog-format=name - binlog format to take effect over user's choice - --wsrep-load-data-splitting - To commit LOAD DATA transaction after every 10K rows - inserted - (Defaults to on; use --skip-wsrep-load-data-splitting to disable.) - --wsrep-log-conflicts - To log multi-master conflicts - --wsrep-max-ws-rows=# - Max number of rows in write set - --wsrep-max-ws-size=# - Max write set size (bytes) - --wsrep-mysql-replication-bundle=# - mysql replication group commit - --wsrep-node-address=name - Node address - --wsrep-node-incoming-address=name - Client connection address - --wsrep-node-name=name - Node name - --wsrep-notify-cmd=name - --wsrep-on To enable wsrep replication - (Defaults to on; use --skip-wsrep-on to disable.) - --wsrep-provider=name - Path to replication provider library - --wsrep-provider-options=name - provider specific options - --wsrep-recover Recover database state after crash and exit - --wsrep-replicate-myisam - To enable myisam replication - --wsrep-restart-slave - Should MySQL slave be restarted automatically, when node - joins back to cluster - --wsrep-retry-autocommit=# - Max number of times to retry a failed autocommit - statement - --wsrep-slave-FK-checks - Should slave thread do foreign key constraint checks - (Defaults to on; use --skip-wsrep-slave-FK-checks to disable.) - --wsrep-slave-UK-checks - Should slave thread do secondary index uniqueness checks - --wsrep-slave-threads=# - Number of slave appliers to launch - --wsrep-sst-auth=name - Authentication for SST connection - --wsrep-sst-donor=name - preferred donor node for the SST - --wsrep-sst-donor-rejects-queries - Reject client queries when donating state snapshot - transfer - --wsrep-sst-method=name - State snapshot transfer method - --wsrep-sst-receive-address=name - Address where node is waiting for SST contact - --wsrep-start-position=name - global transaction position to start from - --wsrep-sync-wait[=#] - Ensure "synchronous" read view before executing an - operation of the type specified by bitmask: 1 - - READ(includes SELECT, SHOW and BEGIN/START TRANSACTION); - 2 - UPDATE and DELETE; 4 - INSERT and REPLACE Variables (--variable-name=value) allow-suspicious-udfs FALSE @@ -1451,44 +1364,6 @@ use-stat-tables NEVER userstat FALSE verbose TRUE wait-timeout 28800 -wsrep-OSU-method TOI -wsrep-auto-increment-control TRUE -wsrep-causal-reads FALSE -wsrep-certify-nonPK TRUE -wsrep-cluster-address -wsrep-cluster-name my_wsrep_cluster -wsrep-convert-LOCK-to-trx FALSE -wsrep-data-home-dir -wsrep-dbug-option -wsrep-debug FALSE -wsrep-desync FALSE -wsrep-drupal-282555-workaround FALSE -wsrep-forced-binlog-format NONE -wsrep-load-data-splitting TRUE -wsrep-log-conflicts FALSE -wsrep-max-ws-rows 131072 -wsrep-max-ws-size 1073741824 -wsrep-mysql-replication-bundle 0 -wsrep-node-address -wsrep-node-incoming-address AUTO -wsrep-notify-cmd -wsrep-on FALSE -wsrep-provider none -wsrep-provider-options -wsrep-recover FALSE -wsrep-replicate-myisam FALSE -wsrep-restart-slave FALSE -wsrep-retry-autocommit 1 -wsrep-slave-FK-checks TRUE -wsrep-slave-UK-checks FALSE -wsrep-slave-threads 1 -wsrep-sst-auth (No default value) -wsrep-sst-donor -wsrep-sst-donor-rejects-queries FALSE -wsrep-sst-method rsync -wsrep-sst-receive-address AUTO -wsrep-start-position 00000000-0000-0000-0000-000000000000:-1 -wsrep-sync-wait 0 To see what values a running MySQL server is using, type 'mysqladmin variables' instead of 'mysqld --verbose --help'. diff --git a/mysql-test/r/not_wsrep.require b/mysql-test/r/not_wsrep.require deleted file mode 100644 index 7c8e74af144..00000000000 --- a/mysql-test/r/not_wsrep.require +++ /dev/null @@ -1,2 +0,0 @@ -HAVE_WSREP -0 diff --git a/mysql-test/suite/galera/my.cnf b/mysql-test/suite/galera/my.cnf deleted file mode 100644 index ca163a540d9..00000000000 --- a/mysql-test/suite/galera/my.cnf +++ /dev/null @@ -1 +0,0 @@ -!include galera_2nodes.cnf diff --git a/mysql-test/include/galera_cluster.inc b/mysql-test/suite/wsrep/include/galera_cluster.inc similarity index 100% rename from mysql-test/include/galera_cluster.inc rename to mysql-test/suite/wsrep/include/galera_cluster.inc diff --git a/mysql-test/include/galera_connect.inc b/mysql-test/suite/wsrep/include/galera_connect.inc similarity index 100% rename from mysql-test/include/galera_connect.inc rename to mysql-test/suite/wsrep/include/galera_connect.inc diff --git a/mysql-test/include/galera_diff.inc b/mysql-test/suite/wsrep/include/galera_diff.inc similarity index 100% rename from mysql-test/include/galera_diff.inc rename to mysql-test/suite/wsrep/include/galera_diff.inc diff --git a/mysql-test/include/galera_end.inc b/mysql-test/suite/wsrep/include/galera_end.inc similarity index 100% rename from mysql-test/include/galera_end.inc rename to mysql-test/suite/wsrep/include/galera_end.inc diff --git a/mysql-test/include/galera_init.inc b/mysql-test/suite/wsrep/include/galera_init.inc similarity index 100% rename from mysql-test/include/galera_init.inc rename to mysql-test/suite/wsrep/include/galera_init.inc diff --git a/mysql-test/include/have_wsrep_enabled.inc b/mysql-test/suite/wsrep/include/have_wsrep_enabled.inc similarity index 90% rename from mysql-test/include/have_wsrep_enabled.inc rename to mysql-test/suite/wsrep/include/have_wsrep_enabled.inc index 439e13e1eb9..94eccadec3b 100644 --- a/mysql-test/include/have_wsrep_enabled.inc +++ b/mysql-test/suite/wsrep/include/have_wsrep_enabled.inc @@ -2,8 +2,10 @@ # (i.e. wsrep_on=ON). It includes have_wsrep.inc. --source include/have_wsrep.inc +--source include/have_innodb.inc if (`SELECT COUNT(*)=0 FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME = 'wsrep_on' AND VARIABLE_VALUE='ON'`) { --skip Test requires wsrep_on=ON } + diff --git a/mysql-test/suite/galera/galera_2nodes.cnf b/mysql-test/suite/wsrep/my.cnf similarity index 72% rename from mysql-test/suite/galera/galera_2nodes.cnf rename to mysql-test/suite/wsrep/my.cnf index 024ced1d20b..ea04d948b61 100644 --- a/mysql-test/suite/galera/galera_2nodes.cnf +++ b/mysql-test/suite/wsrep/my.cnf @@ -1,27 +1,28 @@ # Use default setting for mysqld processes !include include/default_mysqld.cnf -[mysqld.1] +[mysqld] +wsrep-on=1 binlog-format=row -#galera_port=OPT.port -#sst_port=OPT.port +innodb-autoinc-lock-mode=2 +innodb-locks-unsafe-for-binlog=1 +wsrep-cluster-address=gcomm:// wsrep_provider=@ENV.WSREP_PROVIDER -wsrep_cluster_address='gcomm://' -wsrep_provider_options='base_port=@mysqld.1.#galera_port' -wsrep_sst_receive_address='127.0.0.1:@mysqld.1.#sst_port' # enforce read-committed characteristics across the cluster wsrep_causal_reads=ON +[mysqld.1] +#galera_port=@OPT.port +#sst_port=@OPT.port +wsrep_provider_options='base_port=@mysqld.1.#galera_port' +wsrep_sst_receive_address='127.0.0.1:@mysqld.1.#sst_port' + [mysqld.2] -binlog-format=row -#galera_port=OPT.port -#sst_port=OPT.port -wsrep_provider=@ENV.WSREP_PROVIDER +#galera_port=@OPT.port +#sst_port=@OPT.port wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port' wsrep_provider_options='base_port=@mysqld.2.#galera_port' wsrep_sst_receive_address='127.0.0.1:@mysqld.2.#sst_port' -# enforce read-committed characteristics across the cluster -wsrep_causal_reads=ON [ENV] NODE_MYPORT_1= @mysqld.1.port diff --git a/mysql-test/suite/galera/r/basic.result b/mysql-test/suite/wsrep/r/basic.result similarity index 100% rename from mysql-test/suite/galera/r/basic.result rename to mysql-test/suite/wsrep/r/basic.result diff --git a/mysql-test/suite/galera/r/grant.result b/mysql-test/suite/wsrep/r/grant.result similarity index 100% rename from mysql-test/suite/galera/r/grant.result rename to mysql-test/suite/wsrep/r/grant.result diff --git a/mysql-test/suite/galera/r/partition.result b/mysql-test/suite/wsrep/r/partition.result similarity index 100% rename from mysql-test/suite/galera/r/partition.result rename to mysql-test/suite/wsrep/r/partition.result diff --git a/mysql-test/suite/galera/r/unique_key.result b/mysql-test/suite/wsrep/r/unique_key.result similarity index 100% rename from mysql-test/suite/galera/r/unique_key.result rename to mysql-test/suite/wsrep/r/unique_key.result diff --git a/mysql-test/suite/wsrep/suite.pm b/mysql-test/suite/wsrep/suite.pm new file mode 100644 index 00000000000..bcd7e6f3813 --- /dev/null +++ b/mysql-test/suite/wsrep/suite.pm @@ -0,0 +1,38 @@ +package My::Suite::WSREP; +use File::Basename; +use My::Find; + +@ISA = qw(My::Suite); + +return "Not run for embedded server" if $::opt_embedded_server; + +return "WSREP is not compiled in" unless defined $::mysqld_variables{'wsrep-on'}; + +my ($provider) = grep { -f $_ } $ENV{WSREP_PROVIDER}, + "/usr/lib/galera/libgalera_smm.so", + "/usr/lib64/galera/libgalera_smm.so"; + +return "No wsrep provider library" unless -f $provider; + +$ENV{WSREP_PROVIDER} = $provider; + +my ($path) = grep { -f "$_/wsrep_sst_rsync"; } "$::bindir/scripts", $::path_client_bindir; + +return "No SST scripts" unless $path; + +push @::global_suppressions, + ( + qr(WSREP:.*down context.*), + qr(WSREP: Failed to send state UUID:.*), + qr(WSREP: wsrep_sst_receive_address.*), + qr(WSREP: Could not open saved state file for reading: .*), + qr(WSREP: last inactive check more than .* skipping check), + qr(WSREP: Gap in state sequence. Need state transfer.), + qr(WSREP: Failed to prepare for incremental state transfer: .*), + ); + + +$ENV{PATH}="$path:$ENV{PATH}"; + +bless { }; + diff --git a/mysql-test/suite/galera/t/basic.test b/mysql-test/suite/wsrep/t/basic.test similarity index 100% rename from mysql-test/suite/galera/t/basic.test rename to mysql-test/suite/wsrep/t/basic.test diff --git a/mysql-test/suite/wsrep/t/binlog_format.opt b/mysql-test/suite/wsrep/t/binlog_format.opt index 1b8937b91f3..beae84b3862 100644 --- a/mysql-test/suite/wsrep/t/binlog_format.opt +++ b/mysql-test/suite/wsrep/t/binlog_format.opt @@ -1 +1 @@ ---binlog-format=row --innodb_autoinc_lock_mode=2 --innodb_locks_unsafe_for_binlog=1 --wsrep-provider=$WSREP_PROVIDER --wsrep-cluster-address=gcomm:// --wsrep_provider_options='base_port=$GALERA_BASE_PORT' --wsrep-on=1 --log-bin +--log-bin diff --git a/mysql-test/suite/galera/t/grant.test b/mysql-test/suite/wsrep/t/grant.test similarity index 100% rename from mysql-test/suite/galera/t/grant.test rename to mysql-test/suite/wsrep/t/grant.test diff --git a/mysql-test/suite/galera/t/partition.test b/mysql-test/suite/wsrep/t/partition.test similarity index 100% rename from mysql-test/suite/galera/t/partition.test rename to mysql-test/suite/wsrep/t/partition.test diff --git a/mysql-test/suite/wsrep/t/pool_of_threads.opt b/mysql-test/suite/wsrep/t/pool_of_threads.opt index 5ee38531a4a..76b95d050d1 100644 --- a/mysql-test/suite/wsrep/t/pool_of_threads.opt +++ b/mysql-test/suite/wsrep/t/pool_of_threads.opt @@ -1 +1 @@ ---binlog-format=row --innodb_autoinc_lock_mode=2 --innodb_locks_unsafe_for_binlog=1 --wsrep-provider=$WSREP_PROVIDER --wsrep-cluster-address=gcomm:// --wsrep_provider_options='base_port=$GALERA_BASE_PORT' --thread_handling=pool-of-threads +--thread_handling=pool-of-threads diff --git a/mysql-test/suite/wsrep/t/pool_of_threads.test b/mysql-test/suite/wsrep/t/pool_of_threads.test index f4fffaf4f9a..e133ddf35dd 100644 --- a/mysql-test/suite/wsrep/t/pool_of_threads.test +++ b/mysql-test/suite/wsrep/t/pool_of_threads.test @@ -1,4 +1,4 @@ ---source include/have_wsrep.inc +--source include/have_wsrep_enabled.inc --echo --echo # diff --git a/mysql-test/suite/galera/t/unique_key.test b/mysql-test/suite/wsrep/t/unique_key.test similarity index 96% rename from mysql-test/suite/galera/t/unique_key.test rename to mysql-test/suite/wsrep/t/unique_key.test index 00b85d57165..aac3c541355 100644 --- a/mysql-test/suite/galera/t/unique_key.test +++ b/mysql-test/suite/wsrep/t/unique_key.test @@ -1,5 +1,4 @@ --source include/galera_cluster.inc ---source include/have_innodb.inc --echo # --echo # MDEV#5552 Deadlock when inserting NULL column value in column with @@ -20,14 +19,12 @@ SELECT * FROM test.t1; --connection node_2 SELECT * FROM test.t1; - --echo --echo # On node_1 --connection node_1 INSERT INTO t1 VALUES (1); UPDATE t1 SET c1=NULL WHERE c1=1; SELECT * FROM test.t1; - --echo --echo # On node_2 --connection node_2 diff --git a/mysql-test/t/mysqld--help.test b/mysql-test/t/mysqld--help.test index a8cafed9efb..f6a832a34fd 100644 --- a/mysql-test/t/mysqld--help.test +++ b/mysql-test/t/mysqld--help.test @@ -4,7 +4,6 @@ --source include/not_embedded.inc --source include/have_perfschema.inc --source include/platform.inc ---source include/not_wsrep.inc # # force lower-case-table-names=1 (linux/macosx have different defaults) @@ -23,7 +22,7 @@ perl; log-slow-queries pid-file slow-query-log-file log-basename datadir slave-load-tmpdir tmpdir socket thread-pool-size large-files-support lower-case-file-system system-time-zone - wsrep-node-name version.*/; + version.*/; # Plugins which may or may not be there: @plugins=qw/innodb ndb archive blackhole federated partition ndbcluster @@ -31,7 +30,7 @@ perl; thread-concurrency super-large-pages mutex-deadlock-detector connect null-audit aria oqgraph sphinx thread-handling test-sql-discovery rpl-semi-sync query-cache-info - query-response-time metadata-lock-info locales/; + query-response-time metadata-lock-info locales wsrep/; # And substitute the content some environment variables with their # names: From 11b6452a0f2f0f99bbd7c2767ebca7d043a2f43c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 26 Sep 2014 18:49:47 +0200 Subject: [PATCH 069/153] extend SHA1 service. cleanup of sha1 wrappers --- include/mysql/plugin_audit.h.pp | 8 ++ include/mysql/plugin_auth.h.pp | 8 ++ include/mysql/plugin_ftparser.h.pp | 8 ++ include/mysql/service_sha1.h | 14 +++- include/service_versions.h | 2 +- mysys_ssl/my_sha1.cc | 121 ++++++++++++++--------------- sql/sql_plugin_services.h | 8 +- 7 files changed, 103 insertions(+), 66 deletions(-) diff --git a/include/mysql/plugin_audit.h.pp b/include/mysql/plugin_audit.h.pp index 98fd089570d..48bb552857d 100644 --- a/include/mysql/plugin_audit.h.pp +++ b/include/mysql/plugin_audit.h.pp @@ -112,9 +112,17 @@ void thd_gmt_sec_to_TIME(void* thd, MYSQL_TIME *ltime, my_time_t t); extern struct my_sha1_service_st { void (*my_sha1_type)(unsigned char*, const char*, size_t); void (*my_sha1_multi_type)(unsigned char*, ...); + size_t (*my_sha1_context_size_type)(); + void (*my_sha1_init_type)(void *); + void (*my_sha1_input_type)(void *, const unsigned char *, size_t); + void (*my_sha1_result_type)(void *, unsigned char *); } *my_sha1_service; void my_sha1(unsigned char*, const char*, size_t); void my_sha1_multi(unsigned char*, ...); +size_t my_sha1_context_size(); +void my_sha1_init(void *context); +void my_sha1_input(void *context, const unsigned char *buf, size_t len); +void my_sha1_result(void *context, unsigned char *digest); #include typedef struct logger_handle_st LOGGER_HANDLE; extern struct logger_service_st { diff --git a/include/mysql/plugin_auth.h.pp b/include/mysql/plugin_auth.h.pp index 6d52c5be7f0..4b45a1f44fd 100644 --- a/include/mysql/plugin_auth.h.pp +++ b/include/mysql/plugin_auth.h.pp @@ -112,9 +112,17 @@ void thd_gmt_sec_to_TIME(void* thd, MYSQL_TIME *ltime, my_time_t t); extern struct my_sha1_service_st { void (*my_sha1_type)(unsigned char*, const char*, size_t); void (*my_sha1_multi_type)(unsigned char*, ...); + size_t (*my_sha1_context_size_type)(); + void (*my_sha1_init_type)(void *); + void (*my_sha1_input_type)(void *, const unsigned char *, size_t); + void (*my_sha1_result_type)(void *, unsigned char *); } *my_sha1_service; void my_sha1(unsigned char*, const char*, size_t); void my_sha1_multi(unsigned char*, ...); +size_t my_sha1_context_size(); +void my_sha1_init(void *context); +void my_sha1_input(void *context, const unsigned char *buf, size_t len); +void my_sha1_result(void *context, unsigned char *digest); #include typedef struct logger_handle_st LOGGER_HANDLE; extern struct logger_service_st { diff --git a/include/mysql/plugin_ftparser.h.pp b/include/mysql/plugin_ftparser.h.pp index cb3e7cafc97..e1e3704e506 100644 --- a/include/mysql/plugin_ftparser.h.pp +++ b/include/mysql/plugin_ftparser.h.pp @@ -112,9 +112,17 @@ void thd_gmt_sec_to_TIME(void* thd, MYSQL_TIME *ltime, my_time_t t); extern struct my_sha1_service_st { void (*my_sha1_type)(unsigned char*, const char*, size_t); void (*my_sha1_multi_type)(unsigned char*, ...); + size_t (*my_sha1_context_size_type)(); + void (*my_sha1_init_type)(void *); + void (*my_sha1_input_type)(void *, const unsigned char *, size_t); + void (*my_sha1_result_type)(void *, unsigned char *); } *my_sha1_service; void my_sha1(unsigned char*, const char*, size_t); void my_sha1_multi(unsigned char*, ...); +size_t my_sha1_context_size(); +void my_sha1_init(void *context); +void my_sha1_input(void *context, const unsigned char *buf, size_t len); +void my_sha1_result(void *context, unsigned char *digest); #include typedef struct logger_handle_st LOGGER_HANDLE; extern struct logger_service_st { diff --git a/include/mysql/service_sha1.h b/include/mysql/service_sha1.h index 01f5ba81566..609e173e8ce 100644 --- a/include/mysql/service_sha1.h +++ b/include/mysql/service_sha1.h @@ -1,5 +1,5 @@ #ifndef MYSQL_SERVICE_SHA1_INCLUDED -/* Copyright (c) 2013, Monty Program Ab +/* Copyright (c) 2013, 2014, Monty Program Ab 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 @@ -34,17 +34,29 @@ extern "C" { extern struct my_sha1_service_st { void (*my_sha1_type)(unsigned char*, const char*, size_t); void (*my_sha1_multi_type)(unsigned char*, ...); + size_t (*my_sha1_context_size_type)(); + void (*my_sha1_init_type)(void *); + void (*my_sha1_input_type)(void *, const unsigned char *, size_t); + void (*my_sha1_result_type)(void *, unsigned char *); } *my_sha1_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define my_sha1(A,B,C) my_sha1_service->my_sha1_type(A,B,C) #define my_sha1_multi my_sha1_service->my_sha1_multi_type +#define my_sha1_context_size_type() my_sha1_service->my_sha1_context_size_type() +#define my_sha1_init_type(A) my_sha1_service->my_sha1_init_type(A) +#define my_sha1_input_type(A,B,C) my_sha1_service->my_sha1_input_type(A,B,C) +#define my_sha1_result_type(A,B) my_sha1_service->my_sha1_result_type(A,B) #else void my_sha1(unsigned char*, const char*, size_t); void my_sha1_multi(unsigned char*, ...); +size_t my_sha1_context_size(); +void my_sha1_init(void *context); +void my_sha1_input(void *context, const unsigned char *buf, size_t len); +void my_sha1_result(void *context, unsigned char *digest); #endif diff --git a/include/service_versions.h b/include/service_versions.h index cca190b811c..765a15f12e5 100644 --- a/include/service_versions.h +++ b/include/service_versions.h @@ -28,7 +28,7 @@ #define VERSION_thd_wait 0x0100 #define VERSION_progress_report 0x0100 #define VERSION_thd_timezone 0x0100 -#define VERSION_my_sha1 0x0100 +#define VERSION_my_sha1 0x0101 #define VERSION_logger 0x0100 #define VERSION_thd_autoinc 0x0100 #define VERSION_thd_error_context 0x0100 diff --git a/mysys_ssl/my_sha1.cc b/mysys_ssl/my_sha1.cc index fc8f88856bb..9b12d1f1ae8 100644 --- a/mysys_ssl/my_sha1.cc +++ b/mysys_ssl/my_sha1.cc @@ -1,4 +1,5 @@ -/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2012, Oracle and/or its affiliates. + Copyright (c) 2014, SkySQL Ab. 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 @@ -29,66 +30,52 @@ #if defined(HAVE_YASSL) #include "sha.hpp" -/** - Compute SHA1 message digest using YaSSL. +typedef TaoCrypt::SHA SHA_CTX; - @param digest [out] Computed SHA1 digest - @param buf [in] Message to be computed - @param len [in] Length of the message - - @return void -*/ -void mysql_sha1_yassl(uint8 *digest, const char *buf, int len) +static void sha1_init(SHA_CTX *context) { - TaoCrypt::SHA hasher; - hasher.Update((const TaoCrypt::byte *) buf, len); - hasher.Final ((TaoCrypt::byte *) digest); + context->Init(); } -/** - Compute SHA1 message digest for two messages in order to - emulate sha1(msg1, msg2) using YaSSL. - - @param digest [out] Computed SHA1 digest - @param buf1 [in] First message - @param len1 [in] Length of first message - @param buf2 [in] Second message - @param len2 [in] Length of second message - - @return void +/* + this is a variant of sha1_init to be used in this file only. + does nothing for yassl, because the context's constructor was called automatically. */ -void mysql_sha1_multi_yassl(uint8 *digest, va_list args) +static void sha1_init_fast(SHA_CTX *context) { - const char *str; - TaoCrypt::SHA hasher; +} - for (str= va_arg(args, const char*); str; str= va_arg(args, const char*)) - { - hasher.Update((const TaoCrypt::byte *) str, va_arg(args, size_t)); - } - hasher.Final((TaoCrypt::byte *) digest); +static void sha1_input(SHA_CTX *context, const uchar *buf, unsigned len) +{ + context->Update((const TaoCrypt::byte *) buf, len); +} + +static void sha1_result(SHA_CTX *context, uchar digest[SHA1_HASH_SIZE]) +{ + context->Final((TaoCrypt::byte *) digest); } #elif defined(HAVE_OPENSSL) #include -int mysql_sha1_reset(SHA_CTX *context) +static void sha1_init(SHA_CTX *context) { - return SHA1_Init(context); + SHA1_Init(context); } - -int mysql_sha1_input(SHA_CTX *context, const uint8 *message_array, - unsigned length) +static void sha1_init_fast(SHA_CTX *context) { - return SHA1_Update(context, message_array, length); + sha1_init(context); } - -int mysql_sha1_result(SHA_CTX *context, - uint8 Message_Digest[SHA1_HASH_SIZE]) +static void sha1_input(SHA_CTX *context, const uchar *buf, unsigned len) { - return SHA1_Final(Message_Digest, context); + SHA1_Update(context, buf, len); +} + +static void sha1_result(SHA_CTX *context, uchar digest[SHA1_HASH_SIZE]) +{ + SHA1_Final(digest, context); } #endif /* HAVE_YASSL */ @@ -102,17 +89,13 @@ int mysql_sha1_result(SHA_CTX *context, @return void */ -void my_sha1(uint8 *digest, const char *buf, size_t len) +void my_sha1(uchar *digest, const char *buf, size_t len) { -#if defined(HAVE_YASSL) - mysql_sha1_yassl(digest, buf, len); -#elif defined(HAVE_OPENSSL) SHA_CTX sha1_context; - mysql_sha1_reset(&sha1_context); - mysql_sha1_input(&sha1_context, (const uint8 *) buf, len); - mysql_sha1_result(&sha1_context, digest); -#endif /* HAVE_YASSL */ + sha1_init_fast(&sha1_context); + sha1_input(&sha1_context, (const uchar *)buf, len); + sha1_result(&sha1_context, digest); } @@ -128,24 +111,38 @@ void my_sha1(uint8 *digest, const char *buf, size_t len) @return void */ -void my_sha1_multi(uint8 *digest, ...) +void my_sha1_multi(uchar *digest, ...) { va_list args; va_start(args, digest); -#if defined(HAVE_YASSL) - mysql_sha1_multi_yassl(digest, args); -#elif defined(HAVE_OPENSSL) SHA_CTX sha1_context; - const char *str; + const uchar *str; - mysql_sha1_reset(&sha1_context); - for (str= va_arg(args, const char*); str; str= va_arg(args, const char*)) - { - mysql_sha1_input(&sha1_context, (const uint8 *) str, va_arg(args, size_t)); - } - mysql_sha1_result(&sha1_context, digest); -#endif /* HAVE_YASSL */ + sha1_init_fast(&sha1_context); + for (str= va_arg(args, const uchar*); str; str= va_arg(args, const uchar*)) + sha1_input(&sha1_context, str, va_arg(args, size_t)); + + sha1_result(&sha1_context, digest); va_end(args); } +size_t my_sha1_context_size() +{ + return sizeof(SHA_CTX); +} + +void my_sha1_init(void *context) +{ + sha1_init((SHA_CTX *)context); +} + +void my_sha1_input(void *context, const uchar *buf, size_t len) +{ + sha1_input((SHA_CTX *)context, buf, len); +} + +void my_sha1_result(void *context, uchar *digest) +{ + sha1_result((SHA_CTX *)context, digest); +} diff --git a/sql/sql_plugin_services.h b/sql/sql_plugin_services.h index 38b4c4074be..43e711d145e 100644 --- a/sql/sql_plugin_services.h +++ b/sql/sql_plugin_services.h @@ -1,5 +1,5 @@ /* Copyright (c) 2009, 2010, Oracle and/or its affiliates. - Copyright (c) 2012, 2013, Monty Program Ab + Copyright (c) 2012, 2014, Monty Program Ab 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 @@ -61,7 +61,11 @@ static struct thd_timezone_service_st thd_timezone_handler= { static struct my_sha1_service_st my_sha1_handler = { my_sha1, - my_sha1_multi + my_sha1_multi, + my_sha1_context_size, + my_sha1_init, + my_sha1_input, + my_sha1_result }; static struct logger_service_st logger_service_handler= { From d6141a553c566b3c8f997ae811dd4c00d9019613 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 26 Sep 2014 20:03:20 +0200 Subject: [PATCH 070/153] MD5 service --- include/my_md5.h | 2 +- include/mysql/plugin.h | 2 +- include/mysql/plugin_audit.h.pp | 15 +++ include/mysql/plugin_auth.h.pp | 15 +++ include/mysql/plugin_ftparser.h.pp | 15 +++ include/mysql/service_md5.h | 69 ++++++++++ include/mysql/services.h | 1 + include/service_versions.h | 1 + libservices/CMakeLists.txt | 1 + libservices/my_md5_service.c | 18 +++ mysys_ssl/my_md5.cc | 124 ++++++++++++++---- sql/item_strfunc.cc | 3 +- sql/sql_plugin_services.h | 10 ++ sql/table.cc | 2 +- storage/perfschema/pfs_digest.cc | 2 +- storage/perfschema/table_events_statements.cc | 2 +- storage/perfschema/unittest/CMakeLists.txt | 2 +- 17 files changed, 254 insertions(+), 30 deletions(-) create mode 100644 include/mysql/service_md5.h create mode 100644 libservices/my_md5_service.c diff --git a/include/my_md5.h b/include/my_md5.h index 77557fb9346..141ea309cae 100644 --- a/include/my_md5.h +++ b/include/my_md5.h @@ -28,7 +28,7 @@ extern "C" { #endif -void compute_md5_hash(char *digest, const char *buf, int len); +#define compute_md5_hash(A,B,C) my_md5(A,B,C) /* Convert an array of bytes to a hexadecimal representation. diff --git a/include/mysql/plugin.h b/include/mysql/plugin.h index ceb6ac93ff5..03bf59ad7ac 100644 --- a/include/mysql/plugin.h +++ b/include/mysql/plugin.h @@ -75,7 +75,7 @@ typedef struct st_mysql_xid MYSQL_XID; #define MYSQL_PLUGIN_INTERFACE_VERSION 0x0104 /* MariaDB plugin interface version */ -#define MARIA_PLUGIN_INTERFACE_VERSION 0x0108 +#define MARIA_PLUGIN_INTERFACE_VERSION 0x0109 /* The allowable types of plugins diff --git a/include/mysql/plugin_audit.h.pp b/include/mysql/plugin_audit.h.pp index 48bb552857d..ce456806fb8 100644 --- a/include/mysql/plugin_audit.h.pp +++ b/include/mysql/plugin_audit.h.pp @@ -123,6 +123,21 @@ size_t my_sha1_context_size(); void my_sha1_init(void *context); void my_sha1_input(void *context, const unsigned char *buf, size_t len); void my_sha1_result(void *context, unsigned char *digest); +#include +extern struct my_md5_service_st { + void (*my_md5_type)(unsigned char*, const char*, size_t); + void (*my_md5_multi_type)(unsigned char*, ...); + size_t (*my_md5_context_size_type)(); + void (*my_md5_init_type)(void *); + void (*my_md5_input_type)(void *, const unsigned char *, size_t); + void (*my_md5_result_type)(void *, unsigned char *); +} *my_md5_service; +void my_md5(unsigned char*, const char*, size_t); +void my_md5_multi(unsigned char*, ...); +size_t my_md5_context_size(); +void my_md5_init(void *context); +void my_md5_input(void *context, const unsigned char *buf, size_t len); +void my_md5_result(void *context, unsigned char *digest); #include typedef struct logger_handle_st LOGGER_HANDLE; extern struct logger_service_st { diff --git a/include/mysql/plugin_auth.h.pp b/include/mysql/plugin_auth.h.pp index 4b45a1f44fd..fefbb06ab8c 100644 --- a/include/mysql/plugin_auth.h.pp +++ b/include/mysql/plugin_auth.h.pp @@ -123,6 +123,21 @@ size_t my_sha1_context_size(); void my_sha1_init(void *context); void my_sha1_input(void *context, const unsigned char *buf, size_t len); void my_sha1_result(void *context, unsigned char *digest); +#include +extern struct my_md5_service_st { + void (*my_md5_type)(unsigned char*, const char*, size_t); + void (*my_md5_multi_type)(unsigned char*, ...); + size_t (*my_md5_context_size_type)(); + void (*my_md5_init_type)(void *); + void (*my_md5_input_type)(void *, const unsigned char *, size_t); + void (*my_md5_result_type)(void *, unsigned char *); +} *my_md5_service; +void my_md5(unsigned char*, const char*, size_t); +void my_md5_multi(unsigned char*, ...); +size_t my_md5_context_size(); +void my_md5_init(void *context); +void my_md5_input(void *context, const unsigned char *buf, size_t len); +void my_md5_result(void *context, unsigned char *digest); #include typedef struct logger_handle_st LOGGER_HANDLE; extern struct logger_service_st { diff --git a/include/mysql/plugin_ftparser.h.pp b/include/mysql/plugin_ftparser.h.pp index e1e3704e506..0d28f6a00ff 100644 --- a/include/mysql/plugin_ftparser.h.pp +++ b/include/mysql/plugin_ftparser.h.pp @@ -123,6 +123,21 @@ size_t my_sha1_context_size(); void my_sha1_init(void *context); void my_sha1_input(void *context, const unsigned char *buf, size_t len); void my_sha1_result(void *context, unsigned char *digest); +#include +extern struct my_md5_service_st { + void (*my_md5_type)(unsigned char*, const char*, size_t); + void (*my_md5_multi_type)(unsigned char*, ...); + size_t (*my_md5_context_size_type)(); + void (*my_md5_init_type)(void *); + void (*my_md5_input_type)(void *, const unsigned char *, size_t); + void (*my_md5_result_type)(void *, unsigned char *); +} *my_md5_service; +void my_md5(unsigned char*, const char*, size_t); +void my_md5_multi(unsigned char*, ...); +size_t my_md5_context_size(); +void my_md5_init(void *context); +void my_md5_input(void *context, const unsigned char *buf, size_t len); +void my_md5_result(void *context, unsigned char *digest); #include typedef struct logger_handle_st LOGGER_HANDLE; extern struct logger_service_st { diff --git a/include/mysql/service_md5.h b/include/mysql/service_md5.h new file mode 100644 index 00000000000..faf967a5739 --- /dev/null +++ b/include/mysql/service_md5.h @@ -0,0 +1,69 @@ +#ifndef MYSQL_SERVICE_MD5_INCLUDED +/* Copyright (c) 2013, Monty Program Ab + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file + my md5 service + + Functions to calculate MD5 hash from a memory buffer +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef MYSQL_ABI_CHECK +#include +#endif + +#define MY_MD5_HASH_SIZE 16 /* Hash size in bytes */ + +extern struct my_md5_service_st { + void (*my_md5_type)(unsigned char*, const char*, size_t); + void (*my_md5_multi_type)(unsigned char*, ...); + size_t (*my_md5_context_size_type)(); + void (*my_md5_init_type)(void *); + void (*my_md5_input_type)(void *, const unsigned char *, size_t); + void (*my_md5_result_type)(void *, unsigned char *); +} *my_md5_service; + +#ifdef MYSQL_DYNAMIC_PLUGIN + +#define my_md5(A,B,C) my_md5_service->my_md5_type(A,B,C) +#define my_md5_multi my_md5_service->my_md5_multi_type +#define my_md5_context_size() my_md5_service->my_md5_context_size_type() +#define my_md5_init(A) my_md5_service->my_md5_init_type(A) +#define my_md5_input(A,B,C) my_md5_service->my_md5_input_type(A,B,C) +#define my_md5_result(A,B) my_md5_service->my_md5_result_type(A,B) + +#else + +void my_md5(unsigned char*, const char*, size_t); +void my_md5_multi(unsigned char*, ...); +size_t my_md5_context_size(); +void my_md5_init(void *context); +void my_md5_input(void *context, const unsigned char *buf, size_t len); +void my_md5_result(void *context, unsigned char *digest); + +#endif + +#ifdef __cplusplus +} +#endif + +#define MYSQL_SERVICE_MD5_INCLUDED +#endif + diff --git a/include/mysql/services.h b/include/mysql/services.h index 62cac338703..a969cfb388e 100644 --- a/include/mysql/services.h +++ b/include/mysql/services.h @@ -27,6 +27,7 @@ extern "C" { #include #include #include +#include #include #include #include diff --git a/include/service_versions.h b/include/service_versions.h index 765a15f12e5..c9d7571fa10 100644 --- a/include/service_versions.h +++ b/include/service_versions.h @@ -29,6 +29,7 @@ #define VERSION_progress_report 0x0100 #define VERSION_thd_timezone 0x0100 #define VERSION_my_sha1 0x0101 +#define VERSION_my_md5 0x0100 #define VERSION_logger 0x0100 #define VERSION_thd_autoinc 0x0100 #define VERSION_thd_error_context 0x0100 diff --git a/libservices/CMakeLists.txt b/libservices/CMakeLists.txt index d70a98802f5..12f7d6cc1a8 100644 --- a/libservices/CMakeLists.txt +++ b/libservices/CMakeLists.txt @@ -25,6 +25,7 @@ SET(MYSQLSERVICES_SOURCES progress_report_service.c debug_sync_service.c my_sha1_service.c + my_md5_service.c kill_statement_service.c logger_service.c) diff --git a/libservices/my_md5_service.c b/libservices/my_md5_service.c new file mode 100644 index 00000000000..f9db24d0179 --- /dev/null +++ b/libservices/my_md5_service.c @@ -0,0 +1,18 @@ +/* Copyright (c) 2013 Monty Program Ab + Use is subject to license terms. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include +SERVICE_VERSION my_md5_service= (void*)VERSION_my_md5; diff --git a/mysys_ssl/my_md5.cc b/mysys_ssl/my_md5.cc index 4c14366a4e3..697655244eb 100644 --- a/mysys_ssl/my_md5.cc +++ b/mysys_ssl/my_md5.cc @@ -1,4 +1,5 @@ -/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2012, Oracle and/or its affiliates. + Copyright (c) 2014, SkySQL Ab. 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 @@ -24,45 +25,124 @@ #include #include +#include #if defined(HAVE_YASSL) -#include "my_config.h" #include "md5.hpp" -static void my_md5_hash(char *digest, const char *buf, int len) +typedef TaoCrypt::MD5 MD5_CTX; + +static void md5_init(MD5_CTX *context) { - TaoCrypt::MD5 hasher; - hasher.Update((TaoCrypt::byte *) buf, len); - hasher.Final((TaoCrypt::byte *) digest); + context->Init(); +} + +/* + this is a variant of md5_init to be used in this file only. + does nothing for yassl, because the context's constructor was called automatically. +*/ +static void md5_init_fast(MD5_CTX *context) +{ +} + +static void md5_input(MD5_CTX *context, const uchar *buf, unsigned len) +{ + context->Update((const TaoCrypt::byte *) buf, len); +} + +static void md5_result(MD5_CTX *context, uchar digest[MD5_HASH_SIZE]) +{ + context->Final((TaoCrypt::byte *) digest); } #elif defined(HAVE_OPENSSL) #include -static void my_md5_hash(unsigned char* digest, unsigned const char *buf, int len) +static void md5_init(MD5_CTX *context) { - MD5_CTX ctx; - MD5_Init (&ctx); - MD5_Update (&ctx, buf, len); - MD5_Final (digest, &ctx); + MD5_Init(context); +} + +static void md5_init_fast(MD5_CTX *context) +{ + md5_init(context); +} + +static void md5_input(MD5_CTX *context, const uchar *buf, unsigned len) +{ + MD5_Update(context, buf, len); +} + +static void md5_result(MD5_CTX *context, uchar digest[MD5_HASH_SIZE]) +{ + MD5_Final(digest, context); } #endif /* HAVE_YASSL */ /** - Wrapper function to compute MD5 message digest. + Wrapper function to compute MD5 message digest. - @param digest [out] Computed MD5 digest - @param buf [in] Message to be computed - @param len [in] Length of the message + @param digest [out] Computed MD5 digest + @param buf [in] Message to be computed + @param len [in] Length of the message - @return void + @return void */ -void compute_md5_hash(char *digest, const char *buf, int len) +void my_md5(uchar *digest, const char *buf, size_t len) { -#if defined(HAVE_YASSL) - my_md5_hash(digest, buf, len); -#elif defined(HAVE_OPENSSL) - my_md5_hash((unsigned char*)digest, (unsigned const char*)buf, len); -#endif /* HAVE_YASSL */ + MD5_CTX md5_context; + + md5_init_fast(&md5_context); + md5_input(&md5_context, (const uchar *)buf, len); + md5_result(&md5_context, digest); +} + + +/** + Wrapper function to compute MD5 message digest for + two messages in order to emulate md5(msg1, msg2). + + @param digest [out] Computed MD5 digest + @param buf1 [in] First message + @param len1 [in] Length of first message + @param buf2 [in] Second message + @param len2 [in] Length of second message + + @return void +*/ +void my_md5_multi(uchar *digest, ...) +{ + va_list args; + va_start(args, digest); + + MD5_CTX md5_context; + const uchar *str; + + md5_init_fast(&md5_context); + for (str= va_arg(args, const uchar*); str; str= va_arg(args, const uchar*)) + md5_input(&md5_context, str, va_arg(args, size_t)); + + md5_result(&md5_context, digest); + va_end(args); +} + +size_t my_md5_context_size() +{ + return sizeof(MD5_CTX); +} + +void my_md5_init(void *context) +{ + md5_init((MD5_CTX *)context); +} + +void my_md5_input(void *context, const uchar *buf, size_t len) +{ + md5_input((MD5_CTX *)context, buf, len); +} + +void my_md5_result(void *context, uchar *digest) +{ + md5_result((MD5_CTX *)context, digest); } diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index ec6ab0f3040..fa6ba706718 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -163,8 +163,7 @@ String *Item_func_md5::val_str_ascii(String *str) uchar digest[16]; null_value=0; - compute_md5_hash((char *) digest, (const char *) sptr->ptr(), - sptr->length()); + compute_md5_hash(digest, (const char *) sptr->ptr(), sptr->length()); if (str->alloc(32)) // Ensure that memory is free { null_value=1; diff --git a/sql/sql_plugin_services.h b/sql/sql_plugin_services.h index 43e711d145e..417c16c1112 100644 --- a/sql/sql_plugin_services.h +++ b/sql/sql_plugin_services.h @@ -68,6 +68,15 @@ static struct my_sha1_service_st my_sha1_handler = { my_sha1_result }; +static struct my_md5_service_st my_md5_handler = { + my_md5, + my_md5_multi, + my_md5_context_size, + my_md5_init, + my_md5_input, + my_md5_result +}; + static struct logger_service_st logger_service_handler= { logger_init_mutexes, logger_open, @@ -100,6 +109,7 @@ static struct st_service_ref list_of_services[]= { "thd_kill_statement_service", VERSION_kill_statement, &thd_kill_statement_handler }, { "thd_timezone_service", VERSION_thd_timezone, &thd_timezone_handler }, { "my_sha1_service", VERSION_my_sha1, &my_sha1_handler}, + { "my_md5_service", VERSION_my_md5, &my_md5_handler}, { "logger_service", VERSION_logger, &logger_service_handler }, { "thd_autoinc_service", VERSION_thd_autoinc, &thd_autoinc_handler }, { "thd_error_context_service", VERSION_thd_error_context, &thd_error_conext_handler }, diff --git a/sql/table.cc b/sql/table.cc index d720a16f6e5..4f642cadaa2 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -4125,7 +4125,7 @@ void TABLE::reset_item_list(List *item_list) const void TABLE_LIST::calc_md5(char *buffer) { uchar digest[16]; - compute_md5_hash((char*) digest, select_stmt.str, + compute_md5_hash(digest, select_stmt.str, select_stmt.length); sprintf((char *) buffer, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", diff --git a/storage/perfschema/pfs_digest.cc b/storage/perfschema/pfs_digest.cc index 473f4edce7a..bafc22e4b75 100644 --- a/storage/perfschema/pfs_digest.cc +++ b/storage/perfschema/pfs_digest.cc @@ -192,7 +192,7 @@ find_or_create_digest(PFS_thread *thread, PFS_digest_key hash_key; memset(& hash_key, 0, sizeof(hash_key)); /* Compute MD5 Hash of the tokens received. */ - compute_md5_hash((char *) hash_key.m_md5, + compute_md5_hash(hash_key.m_md5, (char *) digest_storage->m_token_array, digest_storage->m_byte_count); /* Add the current schema to the key */ diff --git a/storage/perfschema/table_events_statements.cc b/storage/perfschema/table_events_statements.cc index c6d0bc2e24e..d520c712e5b 100644 --- a/storage/perfschema/table_events_statements.cc +++ b/storage/perfschema/table_events_statements.cc @@ -296,7 +296,7 @@ void table_events_statements_common::make_row_part_2(PSI_digest_storage *digest) safe_byte_count <= PSI_MAX_DIGEST_STORAGE_SIZE) { PFS_digest_key md5; - compute_md5_hash((char *) md5.m_md5, + compute_md5_hash(md5.m_md5, (char *) digest->m_token_array, safe_byte_count); diff --git a/storage/perfschema/unittest/CMakeLists.txt b/storage/perfschema/unittest/CMakeLists.txt index 6add43de7f9..6ef9e91cf47 100644 --- a/storage/perfschema/unittest/CMakeLists.txt +++ b/storage/perfschema/unittest/CMakeLists.txt @@ -24,4 +24,4 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ADD_DEFINITIONS(-DMYSQL_SERVER ${SSL_DEFINES}) MY_ADD_TESTS(pfs_instr_class pfs_instr_class-oom pfs_instr pfs_instr-oom pfs_account-oom pfs_host-oom pfs_timer pfs_user-oom pfs - EXT "cc" LINK_LIBRARIES perfschema mysys) + EXT "cc" LINK_LIBRARIES perfschema mysys mysys_ssl) From c6b95222c3c614342575f752a6787b83fe6ffaa4 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 26 Sep 2014 20:03:38 +0200 Subject: [PATCH 071/153] use MD5 service in innodb/xtradb --- include/mysql/service_md5.h | 2 +- libservices/my_md5_service.c | 2 +- storage/innobase/CMakeLists.txt | 25 --------- storage/innobase/handler/ha_innodb.cc | 13 ++--- storage/innobase/wsrep/md5.cc | 75 --------------------------- storage/innobase/wsrep/wsrep_md5.h | 26 ---------- storage/xtradb/CMakeLists.txt | 25 --------- storage/xtradb/handler/ha_innodb.cc | 13 ++--- storage/xtradb/wsrep/md5.cc | 75 --------------------------- storage/xtradb/wsrep/wsrep_md5.h | 26 ---------- 10 files changed, 16 insertions(+), 266 deletions(-) delete mode 100644 storage/innobase/wsrep/md5.cc delete mode 100644 storage/innobase/wsrep/wsrep_md5.h delete mode 100644 storage/xtradb/wsrep/md5.cc delete mode 100644 storage/xtradb/wsrep/wsrep_md5.h diff --git a/include/mysql/service_md5.h b/include/mysql/service_md5.h index faf967a5739..5e589e57415 100644 --- a/include/mysql/service_md5.h +++ b/include/mysql/service_md5.h @@ -1,5 +1,5 @@ #ifndef MYSQL_SERVICE_MD5_INCLUDED -/* Copyright (c) 2013, Monty Program Ab +/* Copyright (c) 2014, Monty Program Ab 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 diff --git a/libservices/my_md5_service.c b/libservices/my_md5_service.c index f9db24d0179..f993751a9a5 100644 --- a/libservices/my_md5_service.c +++ b/libservices/my_md5_service.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013 Monty Program Ab +/* Copyright (c) 2014 Monty Program Ab Use is subject to license terms. This program is free software; you can redistribute it and/or modify diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt index 79fe57dffc5..e783f3e6459 100644 --- a/storage/innobase/CMakeLists.txt +++ b/storage/innobase/CMakeLists.txt @@ -251,27 +251,6 @@ ENDIF() INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/storage/innobase/include ${CMAKE_SOURCE_DIR}/storage/innobase/handler) -IF(WITH_WSREP) - # ssl include directory - INCLUDE_DIRECTORIES(${SSL_INCLUDE_DIRS} - ${CMAKE_SOURCE_DIR}/storage/innobase/wsrep) - - IF(SSL_DEFINES) - ADD_DEFINITIONS(${SSL_DEFINES}) - ENDIF() - - LINK_LIBRARIES(${SSL_LIBRARIES}) - - # We do RESTRICT_SYMBOL_EXPORTS(yassl) elsewhere. - # In order to get correct symbol visibility, these files - # must be compiled with "-fvisibility=hidden" - IF(WITH_SSL STREQUAL "bundled" AND HAVE_VISIBILITY_HIDDEN) - SET_SOURCE_FILES_PROPERTIES( - {CMAKE_CURRENT_SOURCE_DIR}/wsrep/md5.cc - PROPERTIES COMPILE_FLAGS "-fvisibility=hidden") - ENDIF() -ENDIF() - # Sun Studio bug with -xO2 IF(CMAKE_CXX_COMPILER_ID MATCHES "SunPro" AND CMAKE_CXX_FLAGS_RELEASE MATCHES "O2" @@ -420,10 +399,6 @@ SET(INNOBASE_SOURCES ut/ut0wqueue.cc ut/ut0timer.cc) -IF(WITH_WSREP) - SET(INNOBASE_SOURCES ${INNOBASE_SOURCES} wsrep/md5.cc) -ENDIF() - IF(WITH_INNODB) # Legacy option SET(WITH_INNOBASE_STORAGE_ENGINE TRUE) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 2b0223a6c50..ef5387edca1 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -122,7 +122,7 @@ this program; if not, write to the Free Software Foundation, Inc., #include "dict0priv.h" #include "../storage/innobase/include/ut0byte.h" #include -#include +#include extern my_bool wsrep_certify_nonPK; class binlog_trx_data; @@ -8142,7 +8142,8 @@ wsrep_calc_row_hash( ulint col_type; uint i; - void *ctx = wsrep_md5_init(); + void *ctx = alloca(my_md5_context_size()); + my_md5_init(ctx); n_fields = table->s->fields; @@ -8191,14 +8192,14 @@ wsrep_calc_row_hash( */ if (field->is_null_in_record(row)) { - wsrep_md5_update(ctx, (char*)&null_byte, 1); + my_md5_input(ctx, &null_byte, 1); } else { - wsrep_md5_update(ctx, (char*)&true_byte, 1); - wsrep_md5_update(ctx, (char*)ptr, len); + my_md5_input(ctx, &true_byte, 1); + my_md5_input(ctx, ptr, len); } } - wsrep_compute_md5_hash((char*)digest, ctx); + my_md5_result(ctx, digest); return(0); } diff --git a/storage/innobase/wsrep/md5.cc b/storage/innobase/wsrep/md5.cc deleted file mode 100644 index d3d83c65301..00000000000 --- a/storage/innobase/wsrep/md5.cc +++ /dev/null @@ -1,75 +0,0 @@ -/* - Copyright (c) 2014 SkySQL AB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "my_config.h" - -#if defined(HAVE_YASSL) -#include "md5.hpp" -#elif defined(HAVE_OPENSSL) -#include -#endif /* HAVE_YASSL */ - -#ifdef WITH_WSREP - -/* Initialize md5 object. */ -void *wsrep_md5_init() -{ -#if defined(HAVE_YASSL) - TaoCrypt::MD5 *hasher= new TaoCrypt::MD5; - return (void*)hasher; -#elif defined(HAVE_OPENSSL) - MD5_CTX *ctx = new MD5_CTX(); - MD5_Init (ctx); - return (void *)ctx; -#endif /* HAVE_YASSL */ -} - -/** - Supply message to be hashed. - - @param ctx [IN] Pointer to MD5 context - @param buf [IN] Message to be computed. - @param len [IN] Length of the message. -*/ -void wsrep_md5_update(void *ctx, char* buf, int len) -{ -#if defined(HAVE_YASSL) - ((TaoCrypt::MD5 *)ctx)->Update((TaoCrypt::byte *) buf, len); -#elif defined(HAVE_OPENSSL) - MD5_Update((MD5_CTX*)(ctx), buf, len); -#endif /* HAVE_YASSL */ -} - -/** - Place computed MD5 digest into the given buffer. - - @param digest [OUT] Computed MD5 digest - @param ctx [IN] Pointer to MD5 context -*/ -void wsrep_compute_md5_hash(char *digest, void *ctx) -{ -#if defined(HAVE_YASSL) - ((TaoCrypt::MD5*)ctx)->Final((TaoCrypt::byte *) digest); - delete (TaoCrypt::MD5*)ctx; -#elif defined(HAVE_OPENSSL) - MD5_Final ((unsigned char*)digest, (MD5_CTX*)ctx); - delete (MD5_CTX*)ctx; -#endif /* HAVE_YASSL */ -} - -#endif /* WITH_WSREP */ - diff --git a/storage/innobase/wsrep/wsrep_md5.h b/storage/innobase/wsrep/wsrep_md5.h deleted file mode 100644 index 1339f7f4b86..00000000000 --- a/storage/innobase/wsrep/wsrep_md5.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef WSREP_MD5_INCLUDED -#define WSREP_MD5_INCLUDED - -/* Copyright (c) 2014 SkySQL AB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -*/ - -#ifdef WITH_WSREP -void *wsrep_md5_init(); -void wsrep_md5_update(void *ctx, char* buf, int len); -void wsrep_compute_md5_hash(char *digest, void *ctx); -#endif /* WITH_WSREP */ - -#endif /* WSREP_MD5_INCLUDED */ diff --git a/storage/xtradb/CMakeLists.txt b/storage/xtradb/CMakeLists.txt index c29888b8b15..e34add61886 100644 --- a/storage/xtradb/CMakeLists.txt +++ b/storage/xtradb/CMakeLists.txt @@ -268,27 +268,6 @@ ENDIF() INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/storage/xtradb/include ${CMAKE_SOURCE_DIR}/storage/xtradb/handler) -IF(WITH_WSREP) - # ssl include directory - INCLUDE_DIRECTORIES(${SSL_INCLUDE_DIRS} - ${CMAKE_SOURCE_DIR}/storage/xtradb/wsrep) - - IF(SSL_DEFINES) - ADD_DEFINITIONS(${SSL_DEFINES}) - ENDIF() - - LINK_LIBRARIES(${SSL_LIBRARIES}) - - # We do RESTRICT_SYMBOL_EXPORTS(yassl) elsewhere. - # In order to get correct symbol visibility, these files - # must be compiled with "-fvisibility=hidden" - IF(WITH_SSL STREQUAL "bundled" AND HAVE_VISIBILITY_HIDDEN) - SET_SOURCE_FILES_PROPERTIES( - {CMAKE_CURRENT_SOURCE_DIR}/wsrep/md5.cc - PROPERTIES COMPILE_FLAGS "-fvisibility=hidden") - ENDIF() -ENDIF() - # Sun Studio bug with -xO2 IF(CMAKE_CXX_COMPILER_ID MATCHES "SunPro" AND CMAKE_CXX_FLAGS_RELEASE MATCHES "O2" @@ -430,10 +409,6 @@ SET(INNOBASE_SOURCES ut/ut0wqueue.cc ut/ut0timer.cc) -IF(WITH_WSREP) - SET(INNOBASE_SOURCES ${INNOBASE_SOURCES} wsrep/md5.cc) -ENDIF() - IF(NOT XTRADB_OK) MESSAGE(FATAL_ERROR "Percona XtraDB is not supported on this platform") ENDIF() diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 6773dc7c346..76de9efe080 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -125,7 +125,7 @@ this program; if not, write to the Free Software Foundation, Inc., #include "dict0priv.h" #include "../storage/innobase/include/ut0byte.h" #include -#include +#include extern my_bool wsrep_certify_nonPK; class binlog_trx_data; @@ -8605,7 +8605,8 @@ wsrep_calc_row_hash( ulint col_type; uint i; - void *ctx = wsrep_md5_init(); + void *ctx = alloca(my_md5_context_size()); + my_md5_init(ctx); n_fields = table->s->fields; @@ -8654,14 +8655,14 @@ wsrep_calc_row_hash( */ if (field->is_null_in_record(row)) { - wsrep_md5_update(ctx, (char*)&null_byte, 1); + my_md5_input(ctx, &null_byte, 1); } else { - wsrep_md5_update(ctx, (char*)&true_byte, 1); - wsrep_md5_update(ctx, (char*)ptr, len); + my_md5_input(ctx, &true_byte, 1); + my_md5_input(ctx, ptr, len); } } - wsrep_compute_md5_hash((char*)digest, ctx); + my_md5_result(ctx, digest); return(0); } diff --git a/storage/xtradb/wsrep/md5.cc b/storage/xtradb/wsrep/md5.cc deleted file mode 100644 index d3d83c65301..00000000000 --- a/storage/xtradb/wsrep/md5.cc +++ /dev/null @@ -1,75 +0,0 @@ -/* - Copyright (c) 2014 SkySQL AB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "my_config.h" - -#if defined(HAVE_YASSL) -#include "md5.hpp" -#elif defined(HAVE_OPENSSL) -#include -#endif /* HAVE_YASSL */ - -#ifdef WITH_WSREP - -/* Initialize md5 object. */ -void *wsrep_md5_init() -{ -#if defined(HAVE_YASSL) - TaoCrypt::MD5 *hasher= new TaoCrypt::MD5; - return (void*)hasher; -#elif defined(HAVE_OPENSSL) - MD5_CTX *ctx = new MD5_CTX(); - MD5_Init (ctx); - return (void *)ctx; -#endif /* HAVE_YASSL */ -} - -/** - Supply message to be hashed. - - @param ctx [IN] Pointer to MD5 context - @param buf [IN] Message to be computed. - @param len [IN] Length of the message. -*/ -void wsrep_md5_update(void *ctx, char* buf, int len) -{ -#if defined(HAVE_YASSL) - ((TaoCrypt::MD5 *)ctx)->Update((TaoCrypt::byte *) buf, len); -#elif defined(HAVE_OPENSSL) - MD5_Update((MD5_CTX*)(ctx), buf, len); -#endif /* HAVE_YASSL */ -} - -/** - Place computed MD5 digest into the given buffer. - - @param digest [OUT] Computed MD5 digest - @param ctx [IN] Pointer to MD5 context -*/ -void wsrep_compute_md5_hash(char *digest, void *ctx) -{ -#if defined(HAVE_YASSL) - ((TaoCrypt::MD5*)ctx)->Final((TaoCrypt::byte *) digest); - delete (TaoCrypt::MD5*)ctx; -#elif defined(HAVE_OPENSSL) - MD5_Final ((unsigned char*)digest, (MD5_CTX*)ctx); - delete (MD5_CTX*)ctx; -#endif /* HAVE_YASSL */ -} - -#endif /* WITH_WSREP */ - diff --git a/storage/xtradb/wsrep/wsrep_md5.h b/storage/xtradb/wsrep/wsrep_md5.h deleted file mode 100644 index 1339f7f4b86..00000000000 --- a/storage/xtradb/wsrep/wsrep_md5.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef WSREP_MD5_INCLUDED -#define WSREP_MD5_INCLUDED - -/* Copyright (c) 2014 SkySQL AB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -*/ - -#ifdef WITH_WSREP -void *wsrep_md5_init(); -void wsrep_md5_update(void *ctx, char* buf, int len); -void wsrep_compute_md5_hash(char *digest, void *ctx); -#endif /* WITH_WSREP */ - -#endif /* WSREP_MD5_INCLUDED */ From 8877adb773abeafafcdee18fe30fca1c8589ee2c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 26 Sep 2014 17:02:47 +0200 Subject: [PATCH 072/153] fixing embedded: first set of changes (storage engines don't work yet) --- plugin/feedback/CMakeLists.txt | 1 - sql/sql_class.cc | 21 +++++---- sql/sql_class.h | 80 +++++++++++++++++----------------- sql/wsrep_var.h | 2 +- 4 files changed, 50 insertions(+), 54 deletions(-) diff --git a/plugin/feedback/CMakeLists.txt b/plugin/feedback/CMakeLists.txt index 9070de26ccb..a243ba07751 100644 --- a/plugin/feedback/CMakeLists.txt +++ b/plugin/feedback/CMakeLists.txt @@ -18,7 +18,6 @@ IF(WIN32) ENDIF(WIN32) MYSQL_ADD_PLUGIN(FEEDBACK ${FEEDBACK_SOURCES} - RECOMPILE_FOR_EMBEDDED LINK_LIBRARIES ${SSL_LIBRARIES} ${MAYBE_STATIC_ONLY} DEFAULT) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 82e4f99eed0..56c14613829 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -891,15 +891,6 @@ THD::THD(bool is_wsrep_applier) bootstrap(0), derived_tables_processing(FALSE), spcont(NULL), -#ifdef WITH_WSREP - wsrep_applier(is_wsrep_applier), - wsrep_applier_closing(false), - wsrep_client_thread(false), - wsrep_apply_toi(false), - wsrep_po_handle(WSREP_PO_INITIALIZER), - wsrep_po_cnt(0), - wsrep_apply_format(0), -#endif m_parser_state(NULL), #if defined(ENABLED_DEBUG_SYNC) debug_sync_control(0), @@ -907,6 +898,15 @@ THD::THD(bool is_wsrep_applier) wait_for_commit_ptr(0), main_da(0, false, false), m_stmt_da(&main_da) +#ifdef WITH_WSREP + ,wsrep_applier(is_wsrep_applier) + ,wsrep_applier_closing(false) + ,wsrep_client_thread(false) + ,wsrep_apply_toi(false) + ,wsrep_po_handle(WSREP_PO_INITIALIZER) + ,wsrep_po_cnt(0) + ,wsrep_apply_format(0) +#endif { ulong tmp; @@ -1030,6 +1030,7 @@ THD::THD(bool is_wsrep_applier) wsrep_mysql_replicated = 0; wsrep_TOI_pre_query = NULL; wsrep_TOI_pre_query_len = 0; + wsrep_info[sizeof(wsrep_info) - 1] = '\0'; /* make sure it is 0-terminated */ #endif /* Call to init() below requires fully initialized Open_tables_state. */ reset_open_tables_state(this); @@ -1072,8 +1073,6 @@ THD::THD(bool is_wsrep_applier) thr_lock_info_init(&lock_info); /* safety: will be reset after start */ lock_info.mysql_thd= (void *)this; - wsrep_info[sizeof(wsrep_info) - 1] = '\0'; /* make sure it is 0-terminated */ - m_internal_handler= NULL; m_binlog_invoker= INVOKER_NONE; arena_for_cached_items= 0; diff --git a/sql/sql_class.h b/sql/sql_class.h index ed447d9fc8f..2db9618a824 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -640,12 +640,11 @@ typedef struct system_variables ulong wt_timeout_short, wt_deadlock_search_depth_short; ulong wt_timeout_long, wt_deadlock_search_depth_long; -#ifdef WITH_WSREP my_bool wsrep_on; my_bool wsrep_causal_reads; uint wsrep_sync_wait; ulong wsrep_retry_autocommit; -#endif + double long_query_time_double; my_bool pseudo_slave_mode; @@ -2737,45 +2736,6 @@ public: query_id_t first_query_id; } binlog_evt_union; -#ifdef WITH_WSREP - const bool wsrep_applier; /* dedicated slave applier thread */ - bool wsrep_applier_closing; /* applier marked to close */ - bool wsrep_client_thread; /* to identify client threads*/ - bool wsrep_PA_safe; - bool wsrep_converted_lock_session; - bool wsrep_apply_toi; /* applier processing in TOI */ - enum wsrep_exec_mode wsrep_exec_mode; - query_id_t wsrep_last_query_id; - enum wsrep_query_state wsrep_query_state; - enum wsrep_conflict_state wsrep_conflict_state; - mysql_mutex_t LOCK_wsrep_thd; - mysql_cond_t COND_wsrep_thd; - // changed from wsrep_seqno_t to wsrep_trx_meta_t in wsrep API rev 75 - // wsrep_seqno_t wsrep_trx_seqno; - wsrep_trx_meta_t wsrep_trx_meta; - uint32 wsrep_rand; - Relay_log_info* wsrep_rli; - rpl_group_info* wsrep_rgi; - wsrep_ws_handle_t wsrep_ws_handle; - ulong wsrep_retry_counter; // of autocommit - char* wsrep_retry_query; - size_t wsrep_retry_query_len; - enum enum_server_command wsrep_retry_command; - enum wsrep_consistency_check_mode - wsrep_consistency_check; - wsrep_stats_var* wsrep_status_vars; - int wsrep_mysql_replicated; - const char* wsrep_TOI_pre_query; /* a query to apply before - the actual TOI query */ - size_t wsrep_TOI_pre_query_len; - wsrep_po_handle_t wsrep_po_handle; - size_t wsrep_po_cnt; -#ifdef GTID_SUPPORT - rpl_sid wsrep_po_sid; -#endif /* GTID_SUPPORT */ - void* wsrep_apply_format; -#endif /* WITH_WSREP */ - char wsrep_info[128]; /* string for dynamic proc info */ /** Internal parser state. Note that since the parser is not re-entrant, we keep only one parser @@ -3782,6 +3742,44 @@ public: return (temporary_tables || (rgi_slave && rgi_have_temporary_tables())); } + +#ifdef WITH_WSREP + const bool wsrep_applier; /* dedicated slave applier thread */ + bool wsrep_applier_closing; /* applier marked to close */ + bool wsrep_client_thread; /* to identify client threads*/ + bool wsrep_PA_safe; + bool wsrep_converted_lock_session; + bool wsrep_apply_toi; /* applier processing in TOI */ + enum wsrep_exec_mode wsrep_exec_mode; + query_id_t wsrep_last_query_id; + enum wsrep_query_state wsrep_query_state; + enum wsrep_conflict_state wsrep_conflict_state; + mysql_mutex_t LOCK_wsrep_thd; + mysql_cond_t COND_wsrep_thd; + wsrep_trx_meta_t wsrep_trx_meta; + uint32 wsrep_rand; + Relay_log_info* wsrep_rli; + rpl_group_info* wsrep_rgi; + wsrep_ws_handle_t wsrep_ws_handle; + ulong wsrep_retry_counter; // of autocommit + char* wsrep_retry_query; + size_t wsrep_retry_query_len; + enum enum_server_command wsrep_retry_command; + enum wsrep_consistency_check_mode + wsrep_consistency_check; + wsrep_stats_var* wsrep_status_vars; + int wsrep_mysql_replicated; + const char* wsrep_TOI_pre_query; /* a query to apply before + the actual TOI query */ + size_t wsrep_TOI_pre_query_len; + wsrep_po_handle_t wsrep_po_handle; + size_t wsrep_po_cnt; +#ifdef GTID_SUPPORT + rpl_sid wsrep_po_sid; +#endif /* GTID_SUPPORT */ + void* wsrep_apply_format; + char wsrep_info[128]; /* string for dynamic proc info */ +#endif /* WITH_WSREP */ }; diff --git a/sql/wsrep_var.h b/sql/wsrep_var.h index 654b76be617..6914204148d 100644 --- a/sql/wsrep_var.h +++ b/sql/wsrep_var.h @@ -93,7 +93,7 @@ extern bool wsrep_desync_update UPDATE_ARGS; #define WSREP_NONE #define wsrep_provider_init(X) -#define wsrep_init_vars() (1) +#define wsrep_init_vars() (0) #define wsrep_start_position_init(X) #define wsrep_sst_auth_init(X) From 7aabc2ded2b63fed1e149276bfb5f8e0fd7d723f Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 27 Sep 2014 22:29:10 +0200 Subject: [PATCH 073/153] fixing embedded: WaaS. Wsrep as a Service. --- include/mysql/service_wsrep.h | 205 ++++++++++++++++++ include/mysql/services.h | 1 + include/service_versions.h | 1 + libmysqld/CMakeLists.txt | 1 + libservices/CMakeLists.txt | 1 + libservices/wsrep_service.c | 20 ++ mysql-test/r/handlersocket.result | 2 +- mysql-test/r/plugin.result | 6 +- .../suite/plugins/r/show_all_plugins.result | 4 +- sql/CMakeLists.txt | 2 + sql/mdl.cc | 16 +- sql/sql_base.cc | 2 +- sql/sql_class.cc | 2 +- sql/sql_plugin_services.h | 41 ++++ sql/wsrep_dummy.cc | 126 +++++++++++ sql/wsrep_mysqld.cc | 144 ++++++++---- sql/wsrep_mysqld.h | 71 +----- sql/wsrep_thd.cc | 20 +- sql/wsrep_thd.h | 5 +- sql/wsrep_utils.cc | 3 +- storage/innobase/handler/ha_innodb.cc | 91 +++----- storage/innobase/handler/ha_innodb.h | 33 +-- storage/innobase/handler/handler0alter.cc | 4 - storage/innobase/include/ha_prototypes.h | 13 +- storage/innobase/lock/lock0lock.cc | 7 +- storage/innobase/row/row0upd.cc | 5 +- storage/innobase/srv/srv0conc.cc | 7 +- storage/innobase/trx/trx0sys.cc | 4 +- storage/innobase/trx/trx0trx.cc | 4 +- storage/xtradb/handler/ha_innodb.cc | 50 ++--- storage/xtradb/handler/ha_innodb.h | 15 -- storage/xtradb/include/ha_prototypes.h | 8 - storage/xtradb/lock/lock0lock.cc | 7 +- storage/xtradb/lock/lock0wait.cc | 2 + storage/xtradb/row/row0upd.cc | 5 +- storage/xtradb/srv/srv0conc.cc | 7 +- storage/xtradb/trx/trx0roll.cc | 2 + storage/xtradb/trx/trx0sys.cc | 4 +- storage/xtradb/trx/trx0trx.cc | 4 +- 39 files changed, 617 insertions(+), 328 deletions(-) create mode 100644 include/mysql/service_wsrep.h create mode 100644 libservices/wsrep_service.c create mode 100644 sql/wsrep_dummy.cc diff --git a/include/mysql/service_wsrep.h b/include/mysql/service_wsrep.h new file mode 100644 index 00000000000..11872469cc7 --- /dev/null +++ b/include/mysql/service_wsrep.h @@ -0,0 +1,205 @@ +#ifndef MYSQL_SERVICE_WSREP_INCLUDED +/* Copyright (c) 2013, Monty Program Ab + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file + wsrep service + + Interface to WSREP functionality in the server. + For engines that want to support galera. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +enum wsrep_conflict_state { + NO_CONFLICT, + MUST_ABORT, + ABORTING, + ABORTED, + MUST_REPLAY, + REPLAYING, + RETRY_AUTOCOMMIT, + CERT_FAILURE, +}; + +enum wsrep_exec_mode { + LOCAL_STATE, + REPL_RECV, + TOTAL_ORDER, + LOCAL_COMMIT +}; + +enum wsrep_query_state { + QUERY_IDLE, + QUERY_EXEC, + QUERY_COMMITTING, + QUERY_EXITING, + QUERY_ROLLINGBACK, +}; + +enum wsrep_trx_status { + WSREP_TRX_OK, + WSREP_TRX_CERT_FAIL, /* certification failure, must abort */ + WSREP_TRX_SIZE_EXCEEDED, /* trx size exceeded */ + WSREP_TRX_ERROR, /* native mysql error */ +}; + +struct xid_t; +struct wsrep; +struct wsrep_ws_handle; +struct wsrep_buf; + +extern struct wsrep_service_st { + struct wsrep * (*get_wsrep_func)(); + my_bool (*get_wsrep_certify_nonPK_func)(); + my_bool (*get_wsrep_debug_func)(); + my_bool (*get_wsrep_drupal_282555_workaround_func)(); + my_bool (*get_wsrep_load_data_splitting_func)(); + my_bool (*get_wsrep_log_conflicts_func)(); + long (*get_wsrep_protocol_version_func)(); + my_bool (*wsrep_aborting_thd_contains_func)(THD *thd); + void (*wsrep_aborting_thd_enqueue_func)(THD *thd); + bool (*wsrep_consistency_check_func)(THD *thd); + int (*wsrep_is_wsrep_xid_func)(const struct xid_t *xid); + void (*wsrep_lock_rollback_func)(); + int (*wsrep_on_func)(MYSQL_THD); + void (*wsrep_post_commit_func)(THD* thd, bool all); + bool (*wsrep_prepare_key_func)(const unsigned char*, size_t, const unsigned char*, size_t, struct wsrep_buf*, size_t*); + enum wsrep_trx_status (*wsrep_run_wsrep_commit_func)(THD *thd, handlerton *hton, bool all); + void (*wsrep_thd_LOCK_func)(THD *thd); + void (*wsrep_thd_UNLOCK_func)(THD *thd); + void (*wsrep_thd_awake_func)(THD *thd, my_bool signal); + enum wsrep_conflict_state (*wsrep_thd_conflict_state_func)(MYSQL_THD, my_bool); + const char * (*wsrep_thd_conflict_state_str_func)(THD *thd); + enum wsrep_exec_mode (*wsrep_thd_exec_mode_func)(THD *thd); + const char * (*wsrep_thd_exec_mode_str_func)(THD *thd); + enum wsrep_conflict_state (*wsrep_thd_get_conflict_state_func)(MYSQL_THD); + my_bool (*wsrep_thd_is_BF_func)(MYSQL_THD , my_bool); + my_bool (*wsrep_thd_is_wsrep_func)(MYSQL_THD thd); + char * (*wsrep_thd_query_func)(THD *thd); + enum wsrep_query_state (*wsrep_thd_query_state_func)(THD *thd); + const char * (*wsrep_thd_query_state_str_func)(THD *thd); + int (*wsrep_thd_retry_counter_func)(THD *thd); + void (*wsrep_thd_set_conflict_state_func)(THD *thd, enum wsrep_conflict_state state); + long long (*wsrep_thd_trx_seqno_func)(THD *thd); + struct wsrep_ws_handle * (*wsrep_thd_ws_handle_func)(THD *thd); + int (*wsrep_trx_is_aborting_func)(MYSQL_THD thd); + int (*wsrep_trx_order_before_func)(MYSQL_THD, MYSQL_THD); + void (*wsrep_unlock_rollback_func)(); +} *wsrep_service; + +#ifdef MYSQL_DYNAMIC_PLUGIN +#define get_wsrep() wsrep_service->get_wsrep_func() +#define get_wsrep_certify_nonPK() wsrep_service->get_wsrep_certify_nonPK_func() +#define get_wsrep_debug() wsrep_service->get_wsrep_debug_func() +#define get_wsrep_drupal_282555_workaround() wsrep_service->get_wsrep_drupal_282555_workaround_func() +#define get_wsrep_load_data_splitting() wsrep_service->get_wsrep_load_data_splitting_func() +#define get_wsrep_log_conflicts() wsrep_service->get_wsrep_log_conflicts_func() +#define get_wsrep_protocol_version() wsrep_service->get_wsrep_protocol_version_func() +#define wsrep_aborting_thd_contains(T) wsrep_service->wsrep_aborting_thd_contains_func(T) +#define wsrep_aborting_thd_enqueue(T) wsrep_service->wsrep_aborting_thd_enqueue_func(T) +#define wsrep_consistency_check(T) wsrep_service->wsrep_consistency_check_func(T) +#define wsrep_is_wsrep_xid(X) wsrep_service->wsrep_is_wsrep_xid_func(X) +#define wsrep_lock_rollback() wsrep_service->wsrep_lock_rollback_func() +#define wsrep_on(X) wsrep_service->wsrep_on_func(X) +#define wsrep_post_commit(T,A) wsrep_service->wsrep_post_commit_func(T,A) +#define wsrep_prepare_key(A,B,C,D,E,F) wsrep_service->wsrep_prepare_key_func(A,B,C,D,E,F) +#define wsrep_run_wsrep_commit(T,H,A) wsrep_service->wsrep_run_wsrep_commit_func(T,H,A) +#define wsrep_thd_LOCK(T) wsrep_service->wsrep_thd_LOCK_func(T) +#define wsrep_thd_UNLOCK(T) wsrep_service->wsrep_thd_UNLOCK_func(T) +#define wsrep_thd_awake(T,S) wsrep_service->wsrep_thd_awake_func(T,S) +#define wsrep_thd_conflict_state(T,S) wsrep_service->wsrep_thd_conflict_state_func(T,S) +#define wsrep_thd_conflict_state_str(T) wsrep_service->wsrep_thd_conflict_state_str_func(T) +#define wsrep_thd_exec_mode(T) wsrep_service->wsrep_thd_exec_mode_func(T) +#define wsrep_thd_exec_mode_str(T) wsrep_service->wsrep_thd_exec_mode_str_func(T) +#define wsrep_thd_get_conflict_state(T) wsrep_service->wsrep_thd_get_conflict_state_func(T) +#define wsrep_thd_is_BF(T,S) wsrep_service->wsrep_thd_is_BF_func(T,S) +#define wsrep_thd_is_wsrep(T) wsrep_service->wsrep_thd_is_wsrep_func(T) +#define wsrep_thd_query(T) wsrep_service->wsrep_thd_query_func(T) +#define wsrep_thd_query_state(T) wsrep_service->wsrep_thd_query_state_func(T) +#define wsrep_thd_query_state_str(T) wsrep_service->wsrep_thd_query_state_str_func(T) +#define wsrep_thd_retry_counter(T) wsrep_service->wsrep_thd_retry_counter_func(T) +#define wsrep_thd_set_conflict_state(T,S) wsrep_service->wsrep_thd_set_conflict_state_func(T,S) +#define wsrep_thd_trx_seqno(T) wsrep_service->wsrep_thd_trx_seqno_func(T) +#define wsrep_thd_ws_handle(T) wsrep_service->wsrep_thd_ws_handle_func(T) +#define wsrep_trx_is_aborting(T) wsrep_service->wsrep_trx_is_aborting_func(T) +#define wsrep_trx_order_before(T1,T2) wsrep_service->wsrep_trx_order_before_func(T1,T2) +#define wsrep_unlock_rollback() wsrep_service->wsrep_unlock_rollback_func() + +#define wsrep_debug get_wsrep_debug() +#define wsrep_log_conflicts get_wsrep_log_conflicts() +#define wsrep_certify_nonPK get_wsrep_certify_nonPK() +#define wsrep_load_data_splitting get_wsrep_load_data_splitting() +#define wsrep_drupal_282555_workaround get_wsrep_drupal_282555_workaround() +#define wsrep_protocol_version get_wsrep_protocol_version() + +#else + +extern my_bool wsrep_debug; +extern my_bool wsrep_log_conflicts; +extern my_bool wsrep_certify_nonPK; +extern my_bool wsrep_load_data_splitting; +extern my_bool wsrep_drupal_282555_workaround; +extern long wsrep_protocol_version; + +bool wsrep_consistency_check(THD *thd); +bool wsrep_prepare_key(const unsigned char* cache_key, size_t cache_key_len, const unsigned char* row_id, size_t row_id_len, struct wsrep_buf* key, size_t* key_len); +char *wsrep_thd_query(THD *thd); +const char *wsrep_thd_conflict_state_str(THD *thd); +const char *wsrep_thd_exec_mode_str(THD *thd); +const char *wsrep_thd_query_state_str(THD *thd); +enum wsrep_conflict_state wsrep_thd_conflict_state(MYSQL_THD thd, my_bool sync); +enum wsrep_conflict_state wsrep_thd_get_conflict_state(MYSQL_THD thd); +enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd); +enum wsrep_query_state wsrep_thd_query_state(THD *thd); +enum wsrep_trx_status wsrep_run_wsrep_commit(THD *thd, handlerton *hton, bool all); +int wsrep_is_wsrep_xid(const struct xid_t* xid); +int wsrep_on(MYSQL_THD thd); +int wsrep_thd_retry_counter(THD *thd); +int wsrep_trx_is_aborting(MYSQL_THD thd); +int wsrep_trx_order_before(MYSQL_THD thd1, MYSQL_THD thd2); +long get_wsrep_protocol_version(); +long long wsrep_thd_trx_seqno(THD *thd); +my_bool get_wsrep_certify_nonPK(); +my_bool get_wsrep_debug(); +my_bool get_wsrep_drupal_282555_workaround(); +my_bool get_wsrep_load_data_splitting(); +my_bool get_wsrep_log_conflicts(); +my_bool wsrep_aborting_thd_contains(THD *thd); +my_bool wsrep_thd_is_BF(MYSQL_THD thd, my_bool sync); +my_bool wsrep_thd_is_wsrep(MYSQL_THD thd); +struct wsrep *get_wsrep(); +struct wsrep_ws_handle *wsrep_thd_ws_handle(THD *thd); +void wsrep_aborting_thd_enqueue(THD *thd); +void wsrep_lock_rollback(); +void wsrep_post_commit(THD* thd, bool all); +void wsrep_thd_LOCK(THD *thd); +void wsrep_thd_UNLOCK(THD *thd); +void wsrep_thd_awake(THD *thd, my_bool signal); +void wsrep_thd_set_conflict_state(THD *thd, enum wsrep_conflict_state state); +void wsrep_unlock_rollback(); + +#endif + +#ifdef __cplusplus +} +#endif + +#define MYSQL_SERVICE_WSREP_INCLUDED +#endif + diff --git a/include/mysql/services.h b/include/mysql/services.h index a969cfb388e..4ff30fdd1bb 100644 --- a/include/mysql/services.h +++ b/include/mysql/services.h @@ -31,6 +31,7 @@ extern "C" { #include #include #include +/*#include */ #ifdef __cplusplus } diff --git a/include/service_versions.h b/include/service_versions.h index c9d7571fa10..da3a7edc012 100644 --- a/include/service_versions.h +++ b/include/service_versions.h @@ -30,6 +30,7 @@ #define VERSION_thd_timezone 0x0100 #define VERSION_my_sha1 0x0101 #define VERSION_my_md5 0x0100 +#define VERSION_wsrep 0x0100 #define VERSION_logger 0x0100 #define VERSION_thd_autoinc 0x0100 #define VERSION_thd_error_context 0x0100 diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt index 0920be53baf..f44c5daa17c 100644 --- a/libmysqld/CMakeLists.txt +++ b/libmysqld/CMakeLists.txt @@ -105,6 +105,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc ../sql/compat56.cc ../sql/table_cache.cc ../sql/item_inetfunc.cc + ../sql/wsrep_dummy.cc ${GEN_SOURCES} ${MYSYS_LIBWRAP_SOURCE} ) diff --git a/libservices/CMakeLists.txt b/libservices/CMakeLists.txt index 12f7d6cc1a8..46be68a5b7f 100644 --- a/libservices/CMakeLists.txt +++ b/libservices/CMakeLists.txt @@ -26,6 +26,7 @@ SET(MYSQLSERVICES_SOURCES debug_sync_service.c my_sha1_service.c my_md5_service.c + wsrep_service.c kill_statement_service.c logger_service.c) diff --git a/libservices/wsrep_service.c b/libservices/wsrep_service.c new file mode 100644 index 00000000000..5faf1a12d05 --- /dev/null +++ b/libservices/wsrep_service.c @@ -0,0 +1,20 @@ +/* Copyright (C) 2014 SkySQL Ab. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include + +/* file reserved for the future use */ +SERVICE_VERSION wsrep_service= (void *) VERSION_wsrep; + diff --git a/mysql-test/r/handlersocket.result b/mysql-test/r/handlersocket.result index b519e2e7c93..453a32cedc4 100644 --- a/mysql-test/r/handlersocket.result +++ b/mysql-test/r/handlersocket.result @@ -5,7 +5,7 @@ plugin_version 1.0 plugin_status ACTIVE plugin_type DAEMON plugin_library handlersocket.so -plugin_library_version 1.8 +plugin_library_version 1.9 plugin_author higuchi dot akira at dena dot jp plugin_description Direct access into InnoDB plugin_license BSD diff --git a/mysql-test/r/plugin.result b/mysql-test/r/plugin.result index 630f0141d18..0bd1e1e6dcd 100644 --- a/mysql-test/r/plugin.result +++ b/mysql-test/r/plugin.result @@ -15,7 +15,7 @@ PLUGIN_STATUS ACTIVE PLUGIN_TYPE STORAGE ENGINE PLUGIN_TYPE_VERSION # PLUGIN_LIBRARY ha_example.so -PLUGIN_LIBRARY_VERSION 1.8 +PLUGIN_LIBRARY_VERSION 1.9 PLUGIN_AUTHOR Brian Aker, MySQL AB PLUGIN_DESCRIPTION Example storage engine PLUGIN_LICENSE GPL @@ -28,7 +28,7 @@ PLUGIN_STATUS ACTIVE PLUGIN_TYPE DAEMON PLUGIN_TYPE_VERSION # PLUGIN_LIBRARY ha_example.so -PLUGIN_LIBRARY_VERSION 1.8 +PLUGIN_LIBRARY_VERSION 1.9 PLUGIN_AUTHOR Sergei Golubchik PLUGIN_DESCRIPTION Unusable Daemon PLUGIN_LICENSE GPL @@ -67,7 +67,7 @@ PLUGIN_STATUS DELETED PLUGIN_TYPE STORAGE ENGINE PLUGIN_TYPE_VERSION # PLUGIN_LIBRARY ha_example.so -PLUGIN_LIBRARY_VERSION 1.8 +PLUGIN_LIBRARY_VERSION 1.9 PLUGIN_AUTHOR Brian Aker, MySQL AB PLUGIN_DESCRIPTION Example storage engine PLUGIN_LICENSE GPL diff --git a/mysql-test/suite/plugins/r/show_all_plugins.result b/mysql-test/suite/plugins/r/show_all_plugins.result index 854eb339ce0..55aa43a646d 100644 --- a/mysql-test/suite/plugins/r/show_all_plugins.result +++ b/mysql-test/suite/plugins/r/show_all_plugins.result @@ -4,8 +4,8 @@ Variable_name Value Opened_plugin_libraries 0 select * from information_schema.all_plugins where plugin_library='ha_example.so'; PLUGIN_NAME PLUGIN_VERSION PLUGIN_STATUS PLUGIN_TYPE PLUGIN_TYPE_VERSION PLUGIN_LIBRARY PLUGIN_LIBRARY_VERSION PLUGIN_AUTHOR PLUGIN_DESCRIPTION PLUGIN_LICENSE LOAD_OPTION PLUGIN_MATURITY PLUGIN_AUTH_VERSION -EXAMPLE 0.1 NOT INSTALLED STORAGE ENGINE MYSQL_VERSION_ID ha_example.so 1.8 Brian Aker, MySQL AB Example storage engine GPL OFF Experimental 0.1 -UNUSABLE 3.14 NOT INSTALLED DAEMON MYSQL_VERSION_ID ha_example.so 1.8 Sergei Golubchik Unusable Daemon GPL OFF Experimental 3.14.15.926 +EXAMPLE 0.1 NOT INSTALLED STORAGE ENGINE MYSQL_VERSION_ID ha_example.so 1.9 Brian Aker, MySQL AB Example storage engine GPL OFF Experimental 0.1 +UNUSABLE 3.14 NOT INSTALLED DAEMON MYSQL_VERSION_ID ha_example.so 1.9 Sergei Golubchik Unusable Daemon GPL OFF Experimental 3.14.15.926 show status like '%libraries%'; Variable_name Value Opened_plugin_libraries 1 diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index b02389ccc17..32499662a7c 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -29,6 +29,8 @@ IF(WITH_WSREP AND NOT EMBEDDED_LIBRARY) wsrep_thd.cc ) SET(WSREP_LIB wsrep) +ELSE() + SET(WSREP_SOURCES wsrep_dummy.cc) ENDIF() INCLUDE_DIRECTORIES( diff --git a/sql/mdl.cc b/sql/mdl.cc index 15428c96d73..42f12a47afd 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -1501,7 +1501,7 @@ void MDL_lock::Ticket_list::add_ticket(MDL_ticket *ticket) DBUG_ASSERT(ticket->get_lock()); #ifdef WITH_WSREP if ((this == &(ticket->get_lock()->m_waiting)) && - wsrep_thd_is_BF((void *)(ticket->get_ctx()->get_thd()), false)) + wsrep_thd_is_BF(ticket->get_ctx()->get_thd(), false)) { Ticket_iterator itw(ticket->get_lock()->m_waiting); Ticket_iterator itg(ticket->get_lock()->m_granted); @@ -1513,10 +1513,10 @@ void MDL_lock::Ticket_list::add_ticket(MDL_ticket *ticket) while ((waiting= itw++) && !added) { - if (!wsrep_thd_is_BF((void *)(waiting->get_ctx()->get_thd()), true)) + if (!wsrep_thd_is_BF(waiting->get_ctx()->get_thd(), true)) { WSREP_DEBUG("MDL add_ticket inserted before: %lu %s", - wsrep_thd_thread_id(waiting->get_ctx()->get_thd()), + thd_get_thread_id(waiting->get_ctx()->get_thd()), wsrep_thd_query(waiting->get_ctx()->get_thd())); m_list.insert_after(prev, ticket); added= true; @@ -1911,11 +1911,11 @@ MDL_lock::can_grant_lock(enum_mdl_type type_arg, ticket->is_incompatible_when_granted(type_arg)) { #ifdef WITH_WSREP - if (wsrep_thd_is_BF((void *)(requestor_ctx->get_thd()),false) && + if (wsrep_thd_is_BF(requestor_ctx->get_thd(),false) && key.mdl_namespace() == MDL_key::GLOBAL) { WSREP_DEBUG("global lock granted for BF: %lu %s", - wsrep_thd_thread_id(requestor_ctx->get_thd()), + thd_get_thread_id(requestor_ctx->get_thd()), wsrep_thd_query(requestor_ctx->get_thd())); can_grant = true; } @@ -1945,12 +1945,12 @@ MDL_lock::can_grant_lock(enum_mdl_type type_arg, } else { - if (wsrep_thd_is_BF((void *)(requestor_ctx->get_thd()), false) && + if (wsrep_thd_is_BF(requestor_ctx->get_thd(), false) && key.mdl_namespace() == MDL_key::GLOBAL) { WSREP_DEBUG("global lock granted for BF (waiting queue): %lu %s", - wsrep_thd_thread_id(requestor_ctx->get_thd()), - wsrep_thd_query(requestor_ctx->get_thd())); + thd_get_thread_id(requestor_ctx->get_thd()), + wsrep_thd_query(requestor_ctx->get_thd())); can_grant = true; } } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 00689aad1f3..356f672657e 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -9019,7 +9019,7 @@ bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use, if (!thd_table->needs_reopen()) { signalled|= mysql_lock_abort_for_thread(thd, thd_table); - if (thd && WSREP(thd) && wsrep_thd_is_BF((void *)thd, true)) + if (thd && WSREP(thd) && wsrep_thd_is_BF(thd, true)) { WSREP_DEBUG("remove_table_from_cache: %llu", (unsigned long long) thd->real_id); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 56c14613829..782e4a27317 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1949,7 +1949,7 @@ bool THD::notify_shared_lock(MDL_context_owner *ctx_in_use, if (!thd_table->needs_reopen()) { signalled|= mysql_lock_abort_for_thread(this, thd_table); - if (this && WSREP(this) && wsrep_thd_is_BF((void *)this, FALSE)) + if (this && WSREP(this) && wsrep_thd_is_BF(this, FALSE)) { WSREP_DEBUG("remove_table_from_cache: %llu", (unsigned long long) this->real_id); diff --git a/sql/sql_plugin_services.h b/sql/sql_plugin_services.h index 417c16c1112..399de854218 100644 --- a/sql/sql_plugin_services.h +++ b/sql/sql_plugin_services.h @@ -16,6 +16,7 @@ /* support for Services */ #include +#include struct st_service_ref { const char *name; @@ -99,6 +100,45 @@ static struct thd_error_context_service_st thd_error_conext_handler= { thd_get_error_context_description }; +static struct wsrep_service_st wsrep_handler = { + get_wsrep, + get_wsrep_certify_nonPK, + get_wsrep_debug, + get_wsrep_drupal_282555_workaround, + get_wsrep_load_data_splitting, + get_wsrep_log_conflicts, + get_wsrep_protocol_version, + wsrep_aborting_thd_contains, + wsrep_aborting_thd_enqueue, + wsrep_consistency_check, + wsrep_is_wsrep_xid, + wsrep_lock_rollback, + wsrep_on, + wsrep_post_commit, + wsrep_prepare_key, + wsrep_run_wsrep_commit, + wsrep_thd_LOCK, + wsrep_thd_UNLOCK, + wsrep_thd_awake, + wsrep_thd_conflict_state, + wsrep_thd_conflict_state_str, + wsrep_thd_exec_mode, + wsrep_thd_exec_mode_str, + wsrep_thd_get_conflict_state, + wsrep_thd_is_BF, + wsrep_thd_is_wsrep, + wsrep_thd_query, + wsrep_thd_query_state, + wsrep_thd_query_state_str, + wsrep_thd_retry_counter, + wsrep_thd_set_conflict_state, + wsrep_thd_trx_seqno, + wsrep_thd_ws_handle, + wsrep_trx_is_aborting, + wsrep_trx_order_before, + wsrep_unlock_rollback +}; + static struct st_service_ref list_of_services[]= { { "my_snprintf_service", VERSION_my_snprintf, &my_snprintf_handler }, @@ -112,6 +152,7 @@ static struct st_service_ref list_of_services[]= { "my_md5_service", VERSION_my_md5, &my_md5_handler}, { "logger_service", VERSION_logger, &logger_service_handler }, { "thd_autoinc_service", VERSION_thd_autoinc, &thd_autoinc_handler }, + { "wsrep_service", VERSION_wsrep, &wsrep_handler }, { "thd_error_context_service", VERSION_thd_error_context, &thd_error_conext_handler }, }; diff --git a/sql/wsrep_dummy.cc b/sql/wsrep_dummy.cc new file mode 100644 index 00000000000..e937ef9be5c --- /dev/null +++ b/sql/wsrep_dummy.cc @@ -0,0 +1,126 @@ +/* Copyright (C) 2014 SkySQL Ab. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + +#include +#include +#include + +my_bool wsrep_thd_is_BF(THD *, my_bool) +{ return 0; } + +int wsrep_trx_order_before(THD *, THD *) +{ return 0; } + +enum wsrep_conflict_state wsrep_thd_conflict_state(THD *, my_bool) +{ return NO_CONFLICT; } + +int wsrep_is_wsrep_xid(const XID*) +{ return 0; } + +bool wsrep_prepare_key(const uchar*, size_t, const uchar*, size_t, struct wsrep_buf*, size_t*) +{ return 0; } + +struct wsrep *get_wsrep() +{ return 0; } + +my_bool get_wsrep_certify_nonPK() +{ return 0; } + +my_bool get_wsrep_debug() +{ return 0; } + +my_bool get_wsrep_drupal_282555_workaround() +{ return 0; } + +my_bool get_wsrep_load_data_splitting() +{ return 0; } + +my_bool get_wsrep_log_conflicts() +{ return 0; } + +long get_wsrep_protocol_version() +{ return 0; } + +my_bool wsrep_aborting_thd_contains(THD *) +{ return 0; } + +void wsrep_aborting_thd_enqueue(THD *) +{ } + +bool wsrep_consistency_check(THD *) +{ return 0; } + +void wsrep_lock_rollback() +{ } + +int wsrep_on(THD *thd) +{ return 0; } + +void wsrep_post_commit(THD*, bool) +{ } + +enum wsrep_trx_status wsrep_run_wsrep_commit(THD *, handlerton *, bool) +{ return WSREP_TRX_ERROR; } + +void wsrep_thd_LOCK(THD *) +{ } + +void wsrep_thd_UNLOCK(THD *) +{ } + +void wsrep_thd_awake(THD *, my_bool) +{ } + +const char *wsrep_thd_conflict_state_str(THD *) +{ return 0; } + +enum wsrep_exec_mode wsrep_thd_exec_mode(THD *) +{ return LOCAL_STATE; } + +const char *wsrep_thd_exec_mode_str(THD *) +{ return NULL; } + +enum wsrep_conflict_state wsrep_thd_get_conflict_state(THD *) +{ return NO_CONFLICT; } + +my_bool wsrep_thd_is_wsrep(THD *) +{ return 0; } + +char *wsrep_thd_query(THD *) +{ return 0; } + +enum wsrep_query_state wsrep_thd_query_state(THD *) +{ return QUERY_IDLE; } + +const char *wsrep_thd_query_state_str(THD *) +{ return 0; } + +int wsrep_thd_retry_counter(THD *) +{ return 0; } + +void wsrep_thd_set_conflict_state(THD *, enum wsrep_conflict_state) +{ } + +longlong wsrep_thd_trx_seqno(THD *) +{ return -1; } + +struct wsrep_ws_handle* wsrep_thd_ws_handle(THD *) +{ return 0; } + +int wsrep_trx_is_aborting(THD *) +{ return 0; } + +void wsrep_unlock_rollback() +{ } diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index f47310ba49f..0dd273a0df7 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -782,14 +782,15 @@ int wsrep_init() return rcode; } -extern int wsrep_on(void *); - void wsrep_init_startup (bool first) { if (wsrep_init()) unireg_abort(1); - wsrep_thr_lock_init(wsrep_thd_is_BF, wsrep_abort_thd, - wsrep_debug, wsrep_convert_LOCK_to_trx, wsrep_on); + wsrep_thr_lock_init( + (wsrep_thd_is_brute_force_fun)wsrep_thd_is_BF, + (wsrep_abort_thd_fun)wsrep_abort_thd, + wsrep_debug, wsrep_convert_LOCK_to_trx, + (wsrep_on_fun)wsrep_on); /* Skip replication start if no cluster address */ if (!wsrep_cluster_address || strlen(wsrep_cluster_address) == 0) return; @@ -1187,12 +1188,9 @@ err: } -bool wsrep_prepare_key_for_innodb(const uchar* cache_key, - size_t cache_key_len, - const uchar* row_id, - size_t row_id_len, - wsrep_buf_t* key, - size_t* key_len) +bool wsrep_prepare_key(const uchar* cache_key, size_t cache_key_len, + const uchar* row_id, size_t row_id_len, + wsrep_buf_t* key, size_t* key_len) { if (*key_len < 3) return false; @@ -2112,9 +2110,9 @@ int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len) } -extern int wsrep_on(void *thd) +extern int wsrep_on(THD *thd) { - return (int)(WSREP(((THD*)thd))); + return (int)(WSREP(thd)); } @@ -2124,9 +2122,9 @@ extern "C" bool wsrep_thd_is_wsrep_on(THD *thd) } -extern "C" bool wsrep_consistency_check(void *thd) +bool wsrep_consistency_check(THD *thd) { - return ((THD*)thd)->wsrep_consistency_check == CONSISTENCY_CHECK_RUNNING; + return thd->wsrep_consistency_check == CONSISTENCY_CHECK_RUNNING; } @@ -2143,20 +2141,19 @@ extern "C" void wsrep_thd_set_query_state( } -extern "C" void wsrep_thd_set_conflict_state( - THD *thd, enum wsrep_conflict_state state) +void wsrep_thd_set_conflict_state(THD *thd, enum wsrep_conflict_state state) { thd->wsrep_conflict_state= state; } -extern "C" enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd) +enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd) { return thd->wsrep_exec_mode; } -extern "C" const char *wsrep_thd_exec_mode_str(THD *thd) +const char *wsrep_thd_exec_mode_str(THD *thd) { return (!thd) ? "void" : @@ -2167,13 +2164,13 @@ extern "C" const char *wsrep_thd_exec_mode_str(THD *thd) } -extern "C" enum wsrep_query_state wsrep_thd_query_state(THD *thd) +enum wsrep_query_state wsrep_thd_query_state(THD *thd) { return thd->wsrep_query_state; } -extern "C" const char *wsrep_thd_query_state_str(THD *thd) +const char *wsrep_thd_query_state_str(THD *thd) { return (!thd) ? "void" : @@ -2185,13 +2182,13 @@ extern "C" const char *wsrep_thd_query_state_str(THD *thd) } -extern "C" enum wsrep_conflict_state wsrep_thd_conflict_state(THD *thd) +enum wsrep_conflict_state wsrep_thd_get_conflict_state(THD *thd) { return thd->wsrep_conflict_state; } -extern "C" const char *wsrep_thd_conflict_state_str(THD *thd) +const char *wsrep_thd_conflict_state_str(THD *thd) { return (!thd) ? "void" : @@ -2205,19 +2202,19 @@ extern "C" const char *wsrep_thd_conflict_state_str(THD *thd) } -extern "C" wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd) +wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd) { return &thd->wsrep_ws_handle; } -extern "C" void wsrep_thd_LOCK(THD *thd) +void wsrep_thd_LOCK(THD *thd) { mysql_mutex_lock(&thd->LOCK_wsrep_thd); } -extern "C" void wsrep_thd_UNLOCK(THD *thd) +void wsrep_thd_UNLOCK(THD *thd) { mysql_mutex_unlock(&thd->LOCK_wsrep_thd); } @@ -2234,14 +2231,7 @@ extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd) return thd->wsrep_rand; } - -extern "C" my_thread_id wsrep_thd_thread_id(THD *thd) -{ - return thd->thread_id; -} - - -extern "C" wsrep_seqno_t wsrep_thd_trx_seqno(THD *thd) +longlong wsrep_thd_trx_seqno(THD *thd) { return (thd) ? thd->wsrep_trx_meta.gtid.seqno : WSREP_SEQNO_UNDEFINED; } @@ -2253,7 +2243,7 @@ extern "C" query_id_t wsrep_thd_query_id(THD *thd) } -extern "C" char *wsrep_thd_query(THD *thd) +char *wsrep_thd_query(THD *thd) { return (thd) ? thd->query() : NULL; } @@ -2288,30 +2278,29 @@ extern "C" void wsrep_thd_awake(THD *thd, my_bool signal) } -extern "C" int wsrep_thd_retry_counter(THD *thd) +int wsrep_thd_retry_counter(THD *thd) { return(thd->wsrep_retry_counter); } extern int -wsrep_trx_order_before(void *thd1, void *thd2) +wsrep_trx_order_before(THD *thd1, THD *thd2) { - if (wsrep_thd_trx_seqno((THD*)thd1) < wsrep_thd_trx_seqno((THD*)thd2)) { + if (wsrep_thd_trx_seqno(thd1) < wsrep_thd_trx_seqno(thd2)) { WSREP_DEBUG("BF conflict, order: %lld %lld\n", - (long long)wsrep_thd_trx_seqno((THD*)thd1), - (long long)wsrep_thd_trx_seqno((THD*)thd2)); + (long long)wsrep_thd_trx_seqno(thd1), + (long long)wsrep_thd_trx_seqno(thd2)); return 1; } WSREP_DEBUG("waiting for BF, trx order: %lld %lld\n", - (long long)wsrep_thd_trx_seqno((THD*)thd1), - (long long)wsrep_thd_trx_seqno((THD*)thd2)); + (long long)wsrep_thd_trx_seqno(thd1), + (long long)wsrep_thd_trx_seqno(thd2)); return 0; } -extern "C" int -wsrep_trx_is_aborting(void *thd_ptr) +int wsrep_trx_is_aborting(THD *thd_ptr) { if (thd_ptr) { if ((((THD *)thd_ptr)->wsrep_conflict_state == MUST_ABORT) || @@ -2456,3 +2445,72 @@ int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len) return wsrep_to_buf_helper(thd, stmt_query.c_ptr(), stmt_query.length(), buf, buf_len); } + +/***** callbacks for wsrep service ************/ + +my_bool get_wsrep_debug() +{ + return wsrep_debug; +} + +my_bool get_wsrep_load_data_splitting() +{ + return wsrep_load_data_splitting; +} + +long get_wsrep_protocol_version() +{ + return wsrep_protocol_version; +} + +my_bool get_wsrep_drupal_282555_workaround() +{ + return wsrep_drupal_282555_workaround; +} + +my_bool get_wsrep_log_conflicts() +{ + return wsrep_log_conflicts; +} + +wsrep_t *get_wsrep() +{ + return wsrep; +} + +my_bool get_wsrep_certify_nonPK() +{ + return wsrep_certify_nonPK; +} + +void wsrep_lock_rollback() +{ + mysql_mutex_lock(&LOCK_wsrep_rollback); +} + +void wsrep_unlock_rollback() +{ + mysql_cond_signal(&COND_wsrep_rollback); + mysql_mutex_unlock(&LOCK_wsrep_rollback); +} + +my_bool wsrep_aborting_thd_contains(THD *thd) +{ + wsrep_aborting_thd_t abortees = wsrep_aborting_thd; + while (abortees) + { + if (abortees->aborting_thd == thd) + return true; + abortees = abortees->next; + } + return false; +} + +void wsrep_aborting_thd_enqueue(THD *thd) +{ + wsrep_aborting_thd_t aborting = (wsrep_aborting_thd_t) + my_malloc(sizeof(struct wsrep_aborting_thd), MYF(0)); + aborting->aborting_thd = thd; + aborting->next = wsrep_aborting_thd; + wsrep_aborting_thd = aborting; +} diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index c81ed794659..ce12c13b5a8 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -18,6 +18,9 @@ #ifndef WSREP_MYSQLD_H #define WSREP_MYSQLD_H +#include +#include + #ifdef WITH_WSREP typedef struct st_mysql_show_var SHOW_VAR; @@ -33,32 +36,6 @@ typedef struct st_mysql_show_var SHOW_VAR; class set_var; class THD; -enum wsrep_exec_mode { - LOCAL_STATE, - REPL_RECV, - TOTAL_ORDER, - LOCAL_COMMIT -}; - -enum wsrep_query_state { - QUERY_IDLE, - QUERY_EXEC, - QUERY_COMMITTING, - QUERY_EXITING, - QUERY_ROLLINGBACK, -}; - -enum wsrep_conflict_state { - NO_CONFLICT, - MUST_ABORT, - ABORTING, - ABORTED, - MUST_REPLAY, - REPLAYING, - RETRY_AUTOCOMMIT, - CERT_FAILURE, -}; - enum wsrep_consistency_check_mode { NO_CONSISTENCY_CHECK, CONSISTENCY_CHECK_DECLARED, @@ -90,27 +67,21 @@ extern const char* wsrep_data_home_dir; extern const char* wsrep_dbug_option; extern long wsrep_slave_threads; extern int wsrep_slave_count_change; -extern MYSQL_PLUGIN_IMPORT my_bool wsrep_debug; extern my_bool wsrep_convert_LOCK_to_trx; extern ulong wsrep_retry_autocommit; extern my_bool wsrep_auto_increment_control; -extern my_bool wsrep_drupal_282555_workaround; extern my_bool wsrep_incremental_data_collection; extern const char* wsrep_start_position; extern ulong wsrep_max_ws_size; extern ulong wsrep_max_ws_rows; extern const char* wsrep_notify_cmd; -extern my_bool wsrep_certify_nonPK; extern long wsrep_max_protocol_version; -extern long wsrep_protocol_version; extern ulong wsrep_forced_binlog_format; extern ulong wsrep_OSU_method_options; extern my_bool wsrep_desync; extern my_bool wsrep_recovery; extern my_bool wsrep_replicate_myisam; -extern my_bool wsrep_log_conflicts; extern ulong wsrep_mysql_replication_bundle; -extern my_bool wsrep_load_data_splitting; extern my_bool wsrep_restart_slave; extern my_bool wsrep_restart_slave_activated; extern my_bool wsrep_slave_FK_checks; @@ -157,34 +128,18 @@ void wsrep_init_startup(bool before); // Other wsrep global variables extern my_bool wsrep_inited; // whether wsrep is initialized ? -extern "C" enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd); -extern "C" enum wsrep_conflict_state wsrep_thd_conflict_state(THD *thd); -extern "C" enum wsrep_query_state wsrep_thd_query_state(THD *thd); -extern "C" const char * wsrep_thd_exec_mode_str(THD *thd); -extern "C" const char * wsrep_thd_conflict_state_str(THD *thd); -extern "C" const char * wsrep_thd_query_state_str(THD *thd); -extern "C" wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd); extern "C" void wsrep_thd_set_exec_mode(THD *thd, enum wsrep_exec_mode mode); extern "C" void wsrep_thd_set_query_state( THD *thd, enum wsrep_query_state state); -extern "C" void wsrep_thd_set_conflict_state( - THD *thd, enum wsrep_conflict_state state); extern "C" void wsrep_thd_set_trx_to_replay(THD *thd, uint64 trx_id); -extern "C" void wsrep_thd_LOCK(THD *thd); -extern "C" void wsrep_thd_UNLOCK(THD *thd); extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd); extern "C" time_t wsrep_thd_query_start(THD *thd); -extern "C" my_thread_id wsrep_thd_thread_id(THD *thd); -extern "C" int64_t wsrep_thd_trx_seqno(THD *thd); extern "C" query_id_t wsrep_thd_query_id(THD *thd); -extern "C" char * wsrep_thd_query(THD *thd); extern "C" query_id_t wsrep_thd_wsrep_last_query_id(THD *thd); extern "C" void wsrep_thd_set_wsrep_last_query_id(THD *thd, query_id_t id); -extern "C" void wsrep_thd_awake(THD *thd, my_bool signal); -extern "C" int wsrep_thd_retry_counter(THD *thd); extern void wsrep_close_client_connections(my_bool wait_to_end); @@ -231,7 +186,7 @@ extern wsrep_seqno_t wsrep_locked_seqno; "%s: \n " \ " THD: %lu, mode: %s, state: %s, conflict: %s, seqno: %lld\n " \ " SQL: %s", \ - role, wsrep_thd_thread_id(thd), wsrep_thd_exec_mode_str(thd), \ + role, thd_get_thread_id(thd), wsrep_thd_exec_mode_str(thd), \ wsrep_thd_query_state_str(thd), \ wsrep_thd_conflict_state_str(thd), (long long)wsrep_thd_trx_seqno(thd), \ wsrep_thd_query(thd) \ @@ -252,24 +207,12 @@ extern wsrep_seqno_t wsrep_locked_seqno; extern void wsrep_ready_wait(); -enum wsrep_trx_status { - WSREP_TRX_OK, - WSREP_TRX_CERT_FAIL, /* certification failure, must abort */ - WSREP_TRX_SIZE_EXCEEDED, /* trx size exceeded */ - WSREP_TRX_ERROR, /* native mysql error */ -}; - -extern enum wsrep_trx_status -wsrep_run_wsrep_commit(THD *thd, handlerton *hton, bool all); class Ha_trx_info; struct THD_TRANS; void wsrep_register_hton(THD* thd, bool all); -void wsrep_post_commit(THD* thd, bool all); void wsrep_brute_force_killer(THD *thd); int wsrep_hire_brute_force_killer(THD *thd, uint64_t trx_id); -extern "C" bool wsrep_consistency_check(void *thd_ptr); - /* this is visible for client build so that innodb plugin gets this */ typedef struct wsrep_aborting_thd { struct wsrep_aborting_thd *next; @@ -335,10 +278,6 @@ void wsrep_init_sidno(const wsrep_uuid_t&); void wsrep_xid_init(xid_t*, const wsrep_uuid_t*, wsrep_seqno_t); const wsrep_uuid_t* wsrep_xid_uuid(const xid_t*); wsrep_seqno_t wsrep_xid_seqno(const xid_t*); -extern "C" int wsrep_is_wsrep_xid(const void* xid); - -extern "C" my_thread_id wsrep_thd_thread_id(THD *thd); -extern "C" char *wsrep_thd_query(THD *thd); extern bool wsrep_grant_mdl_exception(MDL_context *requestor_ctx, @@ -375,7 +314,6 @@ int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len); #define WSREP_CLIENT(thd) (0) #define wsrep_emulate_bin_log (0) #define wsrep_xid_seqno(X) (0) -#define wsrep_is_wsrep_xid(X) (0) #define wsrep_to_isolation (0) #define wsrep_recovery (0) #define wsrep_init() (1) @@ -385,7 +323,6 @@ int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len); #define wsrep_sync_wait(...) (0) #define wsrep_to_isolation_begin(...) (0) #define wsrep_register_hton(...) do { } while(0) -#define wsrep_post_commit(...) do { } while(0) #define wsrep_check_opts() (0) #define wsrep_stop_replication(X) do { } while(0) #define wsrep_inited (0) diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc index 0779535d7fb..b9ff0ecf8a8 100644 --- a/sql/wsrep_thd.cc +++ b/sql/wsrep_thd.cc @@ -491,12 +491,11 @@ void wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe) } } -int wsrep_thd_conflict_state(void *thd_ptr, my_bool sync) +enum wsrep_conflict_state wsrep_thd_conflict_state(THD *thd, my_bool sync) { - int state = -1; - if (thd_ptr) + enum wsrep_conflict_state state = NO_CONFLICT; + if (thd) { - THD* thd = (THD*)thd_ptr; if (sync) mysql_mutex_lock(&thd->LOCK_wsrep_thd); state = thd->wsrep_conflict_state; @@ -505,26 +504,23 @@ int wsrep_thd_conflict_state(void *thd_ptr, my_bool sync) return state; } -my_bool wsrep_thd_is_wsrep(void *thd_ptr) +my_bool wsrep_thd_is_wsrep(THD *thd) { my_bool status = FALSE; - if (thd_ptr) + if (thd) { - THD* thd = (THD*)thd_ptr; - status = (WSREP(thd) && WSREP_PROVIDER_EXISTS); } return status; } -my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync) +my_bool wsrep_thd_is_BF(THD *thd, my_bool sync) { my_bool status = FALSE; - if (thd_ptr) + if (thd) { - THD* thd = (THD*)thd_ptr; // THD can be BF only if provider exists - if (wsrep_thd_is_wsrep(thd_ptr)) + if (wsrep_thd_is_wsrep(thd)) { if (sync) mysql_mutex_lock(&thd->LOCK_wsrep_thd); diff --git a/sql/wsrep_thd.h b/sql/wsrep_thd.h index cc3a7c7b9d1..9914e98dcdb 100644 --- a/sql/wsrep_thd.h +++ b/sql/wsrep_thd.h @@ -32,11 +32,10 @@ int wsrep_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr, my_bool signal); extern void wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe); -extern my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync); +extern my_bool wsrep_thd_is_BF(THD *thd, my_bool sync); extern my_bool wsrep_thd_is_wsrep(void *thd_ptr); -extern int wsrep_thd_conflict_state(void *thd_ptr, my_bool sync); -//extern "C" my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync); +enum wsrep_conflict_state wsrep_thd_conflict_state(void *thd_ptr, my_bool sync); extern "C" my_bool wsrep_thd_is_BF_or_commit(void *thd_ptr, my_bool sync); extern "C" my_bool wsrep_thd_is_local(void *thd_ptr, my_bool sync); extern "C" int wsrep_thd_in_locking_session(void *thd_ptr); diff --git a/sql/wsrep_utils.cc b/sql/wsrep_utils.cc index cdee1c2cece..e7509d393d8 100644 --- a/sql/wsrep_utils.cc +++ b/sql/wsrep_utils.cc @@ -514,9 +514,8 @@ wsrep_seqno_t wsrep_xid_seqno(const XID* xid) } extern -int wsrep_is_wsrep_xid(const void* xid_ptr) +int wsrep_is_wsrep_xid(const XID* xid) { - const XID* xid= reinterpret_cast(xid_ptr); return (xid->formatID == 1 && xid->gtrid_length == WSREP_XID_GTRID_LEN && xid->bqual_length == 0 && diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index ef5387edca1..d866d6b7764 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -114,6 +114,9 @@ this program; if not, write to the Free Software Foundation, Inc., #include "ha_innodb.h" #include "i_s.h" +#include +#include + # ifndef MYSQL_PLUGIN_IMPORT # define MYSQL_PLUGIN_IMPORT /* nothing */ # endif /* MYSQL_PLUGIN_IMPORT */ @@ -121,17 +124,12 @@ this program; if not, write to the Free Software Foundation, Inc., #ifdef WITH_WSREP #include "dict0priv.h" #include "../storage/innobase/include/ut0byte.h" -#include #include -extern my_bool wsrep_certify_nonPK; class binlog_trx_data; extern handlerton *binlog_hton; extern MYSQL_PLUGIN_IMPORT MYSQL_BIN_LOG mysql_bin_log; -extern MYSQL_PLUGIN_IMPORT mysql_mutex_t LOCK_wsrep_rollback; -extern MYSQL_PLUGIN_IMPORT mysql_cond_t COND_wsrep_rollback; -extern MYSQL_PLUGIN_IMPORT wsrep_aborting_thd_t wsrep_aborting_thd; static inline wsrep_ws_handle_t* wsrep_ws_handle(THD* thd, const trx_t* trx) { @@ -139,14 +137,6 @@ wsrep_ws_handle(THD* thd, const trx_t* trx) { (wsrep_trx_id_t)trx->id); } -extern bool wsrep_prepare_key_for_innodb(const uchar *cache_key, - size_t cache_key_len, - const uchar* row_id, - size_t row_id_len, - wsrep_buf_t* key, - size_t* key_len); - -extern handlerton * wsrep_hton; extern TC_LOG* tc_log; extern void wsrep_cleanup_transaction(THD *thd); static int @@ -3702,7 +3692,7 @@ innobase_commit_low( #ifdef WITH_WSREP THD* thd = (THD*)trx->mysql_thd; const char* tmp = 0; - if (wsrep_on((void*)thd)) { + if (wsrep_on(thd)) { #ifdef WSREP_PROC_INFO char info[64]; info[sizeof(info) - 1] = '\0'; @@ -3721,7 +3711,7 @@ innobase_commit_low( trx_commit_for_mysql(trx); } #ifdef WITH_WSREP - if (wsrep_on((void*)thd)) { thd_proc_info(thd, tmp); } + if (wsrep_on(thd)) { thd_proc_info(thd, tmp); } #endif /* WITH_WSREP */ } @@ -4449,7 +4439,7 @@ innobase_kill_query( #ifdef WITH_WSREP wsrep_thd_LOCK(thd); - if (wsrep_thd_conflict_state(thd) != NO_CONFLICT) { + if (wsrep_thd_get_conflict_state(thd) != NO_CONFLICT) { /* if victim has been signaled by BF thread and/or aborting is already progressing, following query aborting is not necessary any more. @@ -7584,7 +7574,7 @@ no_commit: ; } else if (src_table == prebuilt->table) { #ifdef WITH_WSREP - switch (wsrep_run_wsrep_commit(user_thd, wsrep_hton, 1)) + switch (wsrep_run_wsrep_commit(user_thd, 0, 1)) { case WSREP_TRX_OK: break; @@ -7609,7 +7599,7 @@ no_commit: prebuilt->sql_stat_start = TRUE; } else { #ifdef WITH_WSREP - switch (wsrep_run_wsrep_commit(user_thd, wsrep_hton, 1)) + switch (wsrep_run_wsrep_commit(user_thd, 0, 1)) { case WSREP_TRX_OK: break; @@ -9735,7 +9725,7 @@ wsrep_append_foreign_key( wsrep_buf_t wkey_part[3]; wsrep_key_t wkey = {wkey_part, 3}; - if (!wsrep_prepare_key_for_innodb( + if (!wsrep_prepare_key( (const uchar*)cache_key, cache_key_len + 1, (const uchar*)key, len+1, @@ -9746,6 +9736,7 @@ wsrep_append_foreign_key( wsrep_thd_query(thd) : "void"); return DB_ERROR; } + wsrep_t *wsrep= get_wsrep(); rcode = (int)wsrep->append_key( wsrep, wsrep_ws_handle(thd, trx), @@ -9781,7 +9772,7 @@ wsrep_append_key( #ifdef WSREP_DEBUG_PRINT fprintf(stderr, "%s conn %ld, trx %llu, keylen %d, table %s ", (shared) ? "Shared" : "Exclusive", - wsrep_thd_thread_id(thd), (long long)trx->id, key_len, + thd_get_thread_id(thd), (long long)trx->id, key_len, table_share->table_name.str); for (int i=0; itable_cache_key.str, table_share->table_cache_key.length, (const uchar*)key, key_len, @@ -9802,6 +9793,7 @@ wsrep_append_key( DBUG_RETURN(HA_ERR_INTERNAL_ERROR); } + wsrep_t *wsrep= get_wsrep(); int rcode = (int)wsrep->append_key( wsrep, wsrep_ws_handle(thd, trx), @@ -9838,7 +9830,7 @@ ha_innobase::wsrep_append_keys( if (table_share && table_share->tmp_table != NO_TMP_TABLE) { WSREP_DEBUG("skipping tmp table DML: THD: %lu tmp: %d SQL: %s", - wsrep_thd_thread_id(thd), + thd_get_thread_id(thd), table_share->tmp_table, (wsrep_thd_query(thd)) ? wsrep_thd_query(thd) : "void"); @@ -17518,7 +17510,7 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, WSREP_DEBUG("BF kill (%lu, seqno: %lld), victim: (%lu) trx: %lu", signal, (long long)bf_seqno, - wsrep_thd_thread_id(thd), + thd_get_thread_id(thd), victim_trx->id); WSREP_DEBUG("Aborting query: %s", @@ -17534,10 +17526,10 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, if(wsrep_thd_exec_mode(thd) != LOCAL_STATE) { WSREP_DEBUG("withdraw for BF trx: %lu, state: %d", victim_trx->id, - wsrep_thd_conflict_state(thd)); + wsrep_thd_get_conflict_state(thd)); } - switch (wsrep_thd_conflict_state(thd)) { + switch (wsrep_thd_get_conflict_state(thd)) { case NO_CONFLICT: wsrep_thd_set_conflict_state(thd, MUST_ABORT); break; @@ -17552,7 +17544,7 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, case ABORTING: // fall through default: WSREP_DEBUG("victim %lu in state %d", - victim_trx->id, wsrep_thd_conflict_state(thd)); + victim_trx->id, wsrep_thd_get_conflict_state(thd)); wsrep_thd_UNLOCK(thd); DBUG_RETURN(0); break; @@ -17563,7 +17555,7 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, enum wsrep_status rcode; WSREP_DEBUG("kill query for: %ld", - wsrep_thd_thread_id(thd)); + thd_get_thread_id(thd)); WSREP_DEBUG("kill trx QUERY_COMMITTING for %lu", victim_trx->id); @@ -17571,6 +17563,7 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, wsrep_abort_slave_trx(bf_seqno, wsrep_thd_trx_seqno(thd)); } else { + wsrep_t *wsrep= get_wsrep(); rcode = wsrep->abort_pre_commit( wsrep, bf_seqno, (wsrep_trx_id_t)victim_trx->id @@ -17611,7 +17604,7 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, victim_trx->lock.was_chosen_as_deadlock_victim= TRUE; if (victim_trx->lock.wait_lock) { WSREP_DEBUG("victim has wait flag: %ld", - wsrep_thd_thread_id(thd)); + thd_get_thread_id(thd)); lock_t* wait_lock = victim_trx->lock.wait_lock; if (wait_lock) { WSREP_DEBUG("canceling wait lock"); @@ -17624,9 +17617,9 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, } else { /* abort currently executing query */ DBUG_PRINT("wsrep",("sending KILL_QUERY to: %ld", - wsrep_thd_thread_id(thd))); + thd_get_thread_id(thd))); WSREP_DEBUG("kill query for: %ld", - wsrep_thd_thread_id(thd)); + thd_get_thread_id(thd)); /* Note that innobase_kill_connection will take lock_mutex and trx_mutex */ wsrep_thd_UNLOCK(thd); @@ -17641,9 +17634,6 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, break; case QUERY_IDLE: { - bool skip_abort= false; - wsrep_aborting_thd_t abortees; - WSREP_DEBUG("kill IDLE for %lu", victim_trx->id); if (wsrep_thd_exec_mode(thd) == REPL_RECV) { @@ -17657,35 +17647,22 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, /* This will lock thd from proceeding after net_read() */ wsrep_thd_set_conflict_state(thd, ABORTING); - mysql_mutex_lock(&LOCK_wsrep_rollback); + wsrep_lock_rollback(); - abortees = wsrep_aborting_thd; - while (abortees && !skip_abort) { - /* check if we have a kill message for this already */ - if (abortees->aborting_thd == thd) { - skip_abort = true; - WSREP_WARN("duplicate thd aborter %lu", - wsrep_thd_thread_id(thd)); - } - abortees = abortees->next; - } - if (!skip_abort) { - wsrep_aborting_thd_t aborting = (wsrep_aborting_thd_t) - my_malloc(sizeof(struct wsrep_aborting_thd), - MYF(0)); - aborting->aborting_thd = thd; - aborting->next = wsrep_aborting_thd; - wsrep_aborting_thd = aborting; - DBUG_PRINT("wsrep",("enqueuing trx abort for %lu", - wsrep_thd_thread_id(thd))); - WSREP_DEBUG("enqueuing trx abort for (%lu)", - wsrep_thd_thread_id(thd)); + if (wsrep_aborting_thd_contains(thd)) { + WSREP_WARN("duplicate thd aborter %lu", + thd_get_thread_id(thd)); + } else { + wsrep_aborting_thd_enqueue(thd); + DBUG_PRINT("wsrep",("enqueuing trx abort for %lu", + thd_get_thread_id(thd))); + WSREP_DEBUG("enqueuing trx abort for (%lu)", + thd_get_thread_id(thd)); } DBUG_PRINT("wsrep",("signalling wsrep rollbacker")); WSREP_DEBUG("signaling aborter"); - mysql_cond_signal(&COND_wsrep_rollback); - mysql_mutex_unlock(&LOCK_wsrep_rollback); + wsrep_unlock_rollback(); wsrep_thd_UNLOCK(thd); break; diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 9c190bb90cb..c1706a059e2 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -476,38 +476,7 @@ __attribute__((nonnull)); extern void mysql_bin_log_commit_pos(THD *thd, ulonglong *out_pos, const char **out_file); #ifdef WITH_WSREP -#include -//extern "C" int wsrep_trx_order_before(void *thd1, void *thd2); - -extern "C" bool wsrep_thd_is_wsrep_on(THD *thd); - -extern "C" enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd); -extern "C" enum wsrep_conflict_state wsrep_thd_conflict_state(THD *thd); -extern "C" enum wsrep_query_state wsrep_thd_query_state(THD *thd); -extern "C" const char * wsrep_thd_exec_mode_str(THD *thd); -extern "C" const char * wsrep_thd_conflict_state_str(THD *thd); -extern "C" const char * wsrep_thd_query_state_str(THD *thd); -extern "C" wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd); - -extern "C" void wsrep_thd_set_exec_mode(THD *thd, enum wsrep_exec_mode mode); -extern "C" void wsrep_thd_set_query_state( - THD *thd, enum wsrep_query_state state); -extern "C" void wsrep_thd_set_conflict_state( - THD *thd, enum wsrep_conflict_state state); - -extern "C" void wsrep_thd_set_trx_to_replay(THD *thd, uint64 trx_id); - -extern "C"void wsrep_thd_LOCK(THD *thd); -extern "C"void wsrep_thd_UNLOCK(THD *thd); -extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd); -extern "C" time_t wsrep_thd_query_start(THD *thd); -extern "C" my_thread_id wsrep_thd_thread_id(THD *thd); -extern "C" int64_t wsrep_thd_trx_seqno(THD *thd); -extern "C" query_id_t wsrep_thd_query_id(THD *thd); -extern "C" char * wsrep_thd_query(THD *thd); -extern "C" query_id_t wsrep_thd_wsrep_last_query_id(THD *thd); -extern "C" void wsrep_thd_set_wsrep_last_query_id(THD *thd, query_id_t id); -extern "C" void wsrep_thd_awake(THD* thd, my_bool signal); +#include #endif extern const struct _ft_vft ft_vft_result; diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 5ba6df883aa..123dbdf254d 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -49,10 +49,6 @@ Smart ALTER TABLE #include "pars0pars.h" #include "row0sel.h" #include "ha_innodb.h" -#ifdef WITH_WSREP -//#include "wsrep_api.h" -#include // PROCESS_ACL -#endif /** Operations for creating secondary indexes (no rebuild needed) */ static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_ONLINE_CREATE diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h index 563a01f747d..212df1a1283 100644 --- a/storage/innobase/include/ha_prototypes.h +++ b/storage/innobase/include/ha_prototypes.h @@ -291,18 +291,11 @@ UNIV_INTERN int wsrep_innobase_kill_one_trx(void *thd_ptr, const trx_t *bf_trx, trx_t *victim_trx, ibool signal); -my_bool wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe); -int wsrep_thd_conflict_state(void *thd_ptr, my_bool sync); -my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync); -my_bool wsrep_thd_is_wsrep(void *thd_ptr); -int wsrep_trx_order_before(void *thd1, void *thd2); int wsrep_innobase_mysql_sort(int mysql_type, uint charset_number, - unsigned char* str, unsigned int str_length, - unsigned int buf_length); -int -wsrep_on(void *thd_ptr); -extern "C" int wsrep_is_wsrep_xid(const void*); + unsigned char* str, unsigned int str_length, + unsigned int buf_length); #endif /* WITH_WSREP */ + /**********************************************************************//** Determines the connection character set. @return connection character set */ diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 5265d3c8cf5..bf665eb1955 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -50,11 +50,8 @@ Created 5/7/1996 Heikki Tuuri #include "dict0boot.h" #include -#ifdef WITH_WSREP -extern my_bool wsrep_debug; -extern my_bool wsrep_log_conflicts; -#include "ha_prototypes.h" -#endif +#include + /* Restricts the length of search we will do in the waits-for graph of transactions */ #define LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK 1000000 diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index adced7059e4..b0581945835 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -51,10 +51,9 @@ Created 12/27/1996 Heikki Tuuri #include "pars0sym.h" #include "eval0eval.h" #include "buf0lru.h" -#ifdef WITH_WSREP -extern my_bool wsrep_debug; -#endif +#include +#include /* What kind of latch and lock can we assume when the control comes to ------------------------------------------------------------------- diff --git a/storage/innobase/srv/srv0conc.cc b/storage/innobase/srv/srv0conc.cc index cbf81f8e8f7..8942eb20080 100644 --- a/storage/innobase/srv/srv0conc.cc +++ b/storage/innobase/srv/srv0conc.cc @@ -41,11 +41,8 @@ Created 2011/04/18 Sunny Bains #include "sync0sync.h" #include "trx0trx.h" -#include "mysql/plugin.h" -#ifdef WITH_WSREP -extern "C" int wsrep_trx_is_aborting(void *thd_ptr); -extern my_bool wsrep_debug; -#endif +#include +#include /** Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket. */ diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc index 4af61d4869b..9dc0ef96460 100644 --- a/storage/innobase/trx/trx0sys.cc +++ b/storage/innobase/trx/trx0sys.cc @@ -44,9 +44,7 @@ Created 3/26/1996 Heikki Tuuri #include "os0file.h" #include "read0read.h" -#ifdef WITH_WSREP -#include "ha_prototypes.h" /* wsrep_is_wsrep_xid() */ -#endif /* */ +#include /** The file format tag structure with id and name. */ struct file_format_t { diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 48073667b2f..96e843647ea 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -29,6 +29,8 @@ Created 3/26/1996 Heikki Tuuri #include "trx0trx.ic" #endif +#include + #include "trx0undo.h" #include "trx0rseg.h" #include "log0log.h" @@ -1028,7 +1030,7 @@ trx_write_serialisation_history( #ifdef WITH_WSREP sys_header = trx_sysf_get(mtr); /* Update latest MySQL wsrep XID in trx sys header. */ - if (wsrep_is_wsrep_xid((const void *)&trx->xid)) + if (wsrep_is_wsrep_xid(&trx->xid)) { trx_sys_update_wsrep_checkpoint(&trx->xid, sys_header, mtr); } diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 76de9efe080..1355c8a22a1 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -117,6 +117,9 @@ this program; if not, write to the Free Software Foundation, Inc., #include "i_s.h" #include "xtradb_i_s.h" +#include +#include + # ifndef MYSQL_PLUGIN_IMPORT # define MYSQL_PLUGIN_IMPORT /* nothing */ # endif /* MYSQL_PLUGIN_IMPORT */ @@ -141,13 +144,6 @@ wsrep_ws_handle(THD* thd, const trx_t* trx) { (wsrep_trx_id_t)trx->id); } -extern bool wsrep_prepare_key_for_innodb(const uchar *cache_key, - size_t cache_key_len, - const uchar* row_id, - size_t row_id_len, - wsrep_buf_t* key, - size_t* key_len); - extern handlerton * wsrep_hton; extern TC_LOG* tc_log; extern void wsrep_cleanup_transaction(THD *thd); @@ -4136,7 +4132,7 @@ innobase_commit_low( #ifdef WITH_WSREP THD* thd = (THD*)trx->mysql_thd; const char* tmp = 0; - if (wsrep_on((void*)thd)) { + if (wsrep_on(thd)) { #ifdef WSREP_PROC_INFO char info[64]; info[sizeof(info) - 1] = '\0'; @@ -4155,7 +4151,7 @@ innobase_commit_low( trx_commit_for_mysql(trx); } #ifdef WITH_WSREP - if (wsrep_on((void*)thd)) { thd_proc_info(thd, tmp); } + if (wsrep_on(thd)) { thd_proc_info(thd, tmp); } #endif /* WITH_WSREP */ } @@ -4933,7 +4929,7 @@ innobase_kill_connection( #ifdef WITH_WSREP wsrep_thd_LOCK(thd); - if (wsrep_thd_conflict_state(thd) != NO_CONFLICT) { + if (wsrep_thd_get_conflict_state(thd) != NO_CONFLICT) { /* if victim has been signaled by BF thread and/or aborting is already progressing, following query aborting is not necessary any more. @@ -10250,7 +10246,7 @@ wsrep_append_foreign_key( wsrep_buf_t wkey_part[3]; wsrep_key_t wkey = {wkey_part, 3}; - if (!wsrep_prepare_key_for_innodb( + if (!wsrep_prepare_key( (const uchar*)cache_key, cache_key_len + 1, (const uchar*)key, len+1, @@ -10296,7 +10292,7 @@ wsrep_append_key( #ifdef WSREP_DEBUG_PRINT fprintf(stderr, "%s conn %ld, trx %lu, keylen %d, table %s ", (shared) ? "Shared" : "Exclusive", - wsrep_thd_thread_id(thd), (long long)trx->id, key_len, + thd_get_thread_id(thd), (long long)trx->id, key_len, table_share->table_name.str); for (int i=0; itable_cache_key.str, table_share->table_cache_key.length, (const uchar*)key, key_len, @@ -10353,7 +10349,7 @@ ha_innobase::wsrep_append_keys( if (table_share && table_share->tmp_table != NO_TMP_TABLE) { WSREP_DEBUG("skipping tmp table DML: THD: %lu tmp: %d SQL: %s", - wsrep_thd_thread_id(thd), + thd_get_thread_id(thd), table_share->tmp_table, (wsrep_thd_query(thd)) ? wsrep_thd_query(thd) : "void"); @@ -18444,7 +18440,7 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, WSREP_DEBUG("BF kill (%lu, seqno: %lld), victim: (%lu) trx: %lu", signal, (long long)bf_seqno, - wsrep_thd_thread_id(thd), + thd_get_thread_id(thd), victim_trx->id); WSREP_DEBUG("Aborting query: %s", @@ -18460,10 +18456,10 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, if(wsrep_thd_exec_mode(thd) != LOCAL_STATE) { WSREP_DEBUG("withdraw for BF trx: %lu, state: %d", victim_trx->id, - wsrep_thd_conflict_state(thd)); + wsrep_thd_get_conflict_state(thd)); } - switch (wsrep_thd_conflict_state(thd)) { + switch (wsrep_thd_get_conflict_state(thd)) { case NO_CONFLICT: wsrep_thd_set_conflict_state(thd, MUST_ABORT); break; @@ -18478,7 +18474,7 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, case ABORTING: // fall through default: WSREP_DEBUG("victim %lu in state %d", - victim_trx->id, wsrep_thd_conflict_state(thd)); + victim_trx->id, wsrep_thd_get_conflict_state(thd)); wsrep_thd_UNLOCK(thd); DBUG_RETURN(0); break; @@ -18489,7 +18485,7 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, enum wsrep_status rcode; WSREP_DEBUG("kill query for: %ld", - wsrep_thd_thread_id(thd)); + thd_get_thread_id(thd)); WSREP_DEBUG("kill trx QUERY_COMMITTING for %lu", victim_trx->id); @@ -18537,7 +18533,7 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, victim_trx->lock.was_chosen_as_deadlock_victim= TRUE; if (victim_trx->lock.wait_lock) { WSREP_DEBUG("victim has wait flag: %ld", - wsrep_thd_thread_id(thd)); + thd_get_thread_id(thd)); lock_t* wait_lock = victim_trx->lock.wait_lock; if (wait_lock) { WSREP_DEBUG("canceling wait lock"); @@ -18550,9 +18546,9 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, } else { /* abort currently executing query */ DBUG_PRINT("wsrep",("sending KILL_QUERY to: %ld", - wsrep_thd_thread_id(thd))); + thd_get_thread_id(thd))); WSREP_DEBUG("kill query for: %ld", - wsrep_thd_thread_id(thd)); + thd_get_thread_id(thd)); /* Note that innobase_kill_connection will take lock_mutex and trx_mutex */ wsrep_thd_UNLOCK(thd); @@ -18591,7 +18587,7 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, if (abortees->aborting_thd == thd) { skip_abort = true; WSREP_WARN("duplicate thd aborter %lu", - wsrep_thd_thread_id(thd)); + thd_get_thread_id(thd)); } abortees = abortees->next; } @@ -18602,10 +18598,10 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, aborting->aborting_thd = thd; aborting->next = wsrep_aborting_thd; wsrep_aborting_thd = aborting; - DBUG_PRINT("wsrep",("enqueuing trx abort for %lu", - wsrep_thd_thread_id(thd))); + DBUG_PRINT("wsrep",("enqueuing trx abort for %lu", + thd_get_thread_id(thd))); WSREP_DEBUG("enqueuing trx abort for (%lu)", - wsrep_thd_thread_id(thd)); + thd_get_thread_id(thd)); } DBUG_PRINT("wsrep",("signalling wsrep rollbacker")); @@ -18660,7 +18656,7 @@ wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd, static int innobase_wsrep_set_checkpoint(handlerton* hton, const XID* xid) { DBUG_ASSERT(hton == innodb_hton_ptr); - if (wsrep_is_wsrep_xid((const void *)xid)) { + if (wsrep_is_wsrep_xid(xid)) { mtr_t mtr; mtr_start(&mtr); trx_sysf_t* sys_header = trx_sysf_get(&mtr); diff --git a/storage/xtradb/handler/ha_innodb.h b/storage/xtradb/handler/ha_innodb.h index d6a1b738fe7..0c76c286030 100644 --- a/storage/xtradb/handler/ha_innodb.h +++ b/storage/xtradb/handler/ha_innodb.h @@ -487,33 +487,18 @@ struct trx_t; extern "C" bool wsrep_thd_is_wsrep_on(THD *thd); -extern "C" enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd); -extern "C" enum wsrep_conflict_state wsrep_thd_conflict_state(THD *thd); -extern "C" enum wsrep_query_state wsrep_thd_query_state(THD *thd); -extern "C" const char * wsrep_thd_exec_mode_str(THD *thd); -extern "C" const char * wsrep_thd_conflict_state_str(THD *thd); -extern "C" const char * wsrep_thd_query_state_str(THD *thd); -extern "C" wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd); extern "C" void wsrep_thd_set_exec_mode(THD *thd, enum wsrep_exec_mode mode); extern "C" void wsrep_thd_set_query_state( THD *thd, enum wsrep_query_state state); -extern "C" void wsrep_thd_set_conflict_state( - THD *thd, enum wsrep_conflict_state state); extern "C" void wsrep_thd_set_trx_to_replay(THD *thd, uint64 trx_id); -extern "C"void wsrep_thd_LOCK(THD *thd); -extern "C"void wsrep_thd_UNLOCK(THD *thd); extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd); extern "C" time_t wsrep_thd_query_start(THD *thd); -extern "C" my_thread_id wsrep_thd_thread_id(THD *thd); -extern "C" int64_t wsrep_thd_trx_seqno(THD *thd); extern "C" query_id_t wsrep_thd_query_id(THD *thd); -extern "C" char * wsrep_thd_query(THD *thd); extern "C" query_id_t wsrep_thd_wsrep_last_query_id(THD *thd); extern "C" void wsrep_thd_set_wsrep_last_query_id(THD *thd, query_id_t id); -extern "C" void wsrep_thd_awake(THD* thd, my_bool signal); #endif extern const struct _ft_vft ft_vft_result; diff --git a/storage/xtradb/include/ha_prototypes.h b/storage/xtradb/include/ha_prototypes.h index 4ebaee3c89e..f038b307a6e 100644 --- a/storage/xtradb/include/ha_prototypes.h +++ b/storage/xtradb/include/ha_prototypes.h @@ -290,17 +290,9 @@ UNIV_INTERN int wsrep_innobase_kill_one_trx(void *thd_ptr, const trx_t *bf_trx, trx_t *victim_trx, ibool signal); -my_bool wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe); -int wsrep_thd_conflict_state(void *thd_ptr, my_bool sync); -my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync); -my_bool wsrep_thd_is_wsrep(void *thd_ptr); -int wsrep_trx_order_before(void *thd1, void *thd2); int wsrep_innobase_mysql_sort(int mysql_type, uint charset_number, unsigned char* str, unsigned int str_length, unsigned int buf_length); -int -wsrep_on(void *thd_ptr); -extern "C" int wsrep_is_wsrep_xid(const void*); #endif /* WITH_WSREP */ /**********************************************************************//** Determines the connection character set. diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc index d308e04d07d..8cf77e1ec82 100644 --- a/storage/xtradb/lock/lock0lock.cc +++ b/storage/xtradb/lock/lock0lock.cc @@ -50,11 +50,8 @@ Created 5/7/1996 Heikki Tuuri #include "dict0boot.h" #include -#ifdef WITH_WSREP -extern my_bool wsrep_debug; -extern my_bool wsrep_log_conflicts; -#include "ha_prototypes.h" -#endif +#include + /* Restricts the length of search we will do in the waits-for graph of transactions */ #define LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK 1000000 diff --git a/storage/xtradb/lock/lock0wait.cc b/storage/xtradb/lock/lock0wait.cc index 388c847f580..77aa0261a0f 100644 --- a/storage/xtradb/lock/lock0wait.cc +++ b/storage/xtradb/lock/lock0wait.cc @@ -33,6 +33,8 @@ Created 25/5/2010 Sunny Bains #include "ha_prototypes.h" #include "lock0priv.h" +#include + /*********************************************************************//** Print the contents of the lock_sys_t::waiting_threads array. */ static diff --git a/storage/xtradb/row/row0upd.cc b/storage/xtradb/row/row0upd.cc index bdd2a691368..a642f7932b7 100644 --- a/storage/xtradb/row/row0upd.cc +++ b/storage/xtradb/row/row0upd.cc @@ -53,10 +53,9 @@ Created 12/27/1996 Heikki Tuuri #include "pars0sym.h" #include "eval0eval.h" #include "buf0lru.h" -#ifdef WITH_WSREP -extern my_bool wsrep_debug; -#endif +#include +#include /* What kind of latch and lock can we assume when the control comes to ------------------------------------------------------------------- diff --git a/storage/xtradb/srv/srv0conc.cc b/storage/xtradb/srv/srv0conc.cc index 5868e4e012b..c4cf1b9ab7b 100644 --- a/storage/xtradb/srv/srv0conc.cc +++ b/storage/xtradb/srv/srv0conc.cc @@ -42,11 +42,8 @@ Created 2011/04/18 Sunny Bains #include "btr0types.h" #include "trx0trx.h" -#include "mysql/plugin.h" -#ifdef WITH_WSREP -extern "C" int wsrep_trx_is_aborting(void *thd_ptr); -extern my_bool wsrep_debug; -#endif +#include +#include /** Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket. */ diff --git a/storage/xtradb/trx/trx0roll.cc b/storage/xtradb/trx/trx0roll.cc index eb2af877a6d..b349614badf 100644 --- a/storage/xtradb/trx/trx0roll.cc +++ b/storage/xtradb/trx/trx0roll.cc @@ -29,6 +29,8 @@ Created 3/26/1996 Heikki Tuuri #include "trx0roll.ic" #endif +#include + #include "fsp0fsp.h" #include "mach0data.h" #include "trx0rseg.h" diff --git a/storage/xtradb/trx/trx0sys.cc b/storage/xtradb/trx/trx0sys.cc index 19d14bf6f38..9b59ae14278 100644 --- a/storage/xtradb/trx/trx0sys.cc +++ b/storage/xtradb/trx/trx0sys.cc @@ -48,6 +48,8 @@ Created 3/26/1996 Heikki Tuuri #include "ha_prototypes.h" /* wsrep_is_wsrep_xid() */ #endif /* */ +#include + /** The file format tag structure with id and name. */ struct file_format_t { ulint id; /*!< id of the file format */ @@ -362,7 +364,7 @@ trx_sys_update_wsrep_checkpoint( #endif /* UNIV_DEBUG */ ut_ad(xid && mtr); - ut_a(xid->formatID == -1 || wsrep_is_wsrep_xid((const void *)xid)); + ut_a(xid->formatID == -1 || wsrep_is_wsrep_xid(xid)); if (mach_read_from_4(sys_header + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_MAGIC_N_FLD) diff --git a/storage/xtradb/trx/trx0trx.cc b/storage/xtradb/trx/trx0trx.cc index d26517637cd..30d4b7f6546 100644 --- a/storage/xtradb/trx/trx0trx.cc +++ b/storage/xtradb/trx/trx0trx.cc @@ -30,6 +30,8 @@ Created 3/26/1996 Heikki Tuuri #include "trx0trx.ic" #endif +#include + #include "trx0undo.h" #include "trx0rseg.h" #include "log0log.h" @@ -1226,7 +1228,7 @@ trx_write_serialisation_history( #ifdef WITH_WSREP sys_header = trx_sysf_get(mtr); /* Update latest MySQL wsrep XID in trx sys header. */ - if (wsrep_is_wsrep_xid((const void *)&trx->xid)) + if (wsrep_is_wsrep_xid(&trx->xid)) { trx_sys_update_wsrep_checkpoint(&trx->xid, sys_header, mtr); } From 425dc6d2fd80531d553e25790f6a6e7e199445f6 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 28 Sep 2014 09:13:05 +0200 Subject: [PATCH 074/153] small cleanup --- sql/events.cc | 27 --------------------------- sql/mysqld.cc | 10 +++++----- sql/wsrep_mysqld.cc | 30 ++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 32 deletions(-) diff --git a/sql/events.cc b/sql/events.cc index 999df79a4c0..fa40086c1f7 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -1202,33 +1202,6 @@ int wsrep_create_event_query(THD *thd, uchar** buf, size_t* buf_len) } return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(), buf, buf_len); } -static int -wsrep_alter_query_string(THD *thd, String *buf) -{ - /* Append the "ALTER" part of the query */ - if (buf->append(STRING_WITH_LEN("ALTER "))) - return 1; - /* Append definer */ - append_definer(thd, buf, &(thd->lex->definer->user), &(thd->lex->definer->host)); - /* Append the left part of thd->query after event name part */ - if (buf->append(thd->lex->stmt_definition_begin, - thd->lex->stmt_definition_end - - thd->lex->stmt_definition_begin)) - return 1; - - return 0; -} -int wsrep_alter_event_query(THD *thd, uchar** buf, size_t* buf_len) -{ - String log_query; - - if (wsrep_alter_query_string(thd, &log_query)) - { - WSREP_WARN("events alter string failed: %s", thd->query()); - return 1; - } - return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(), buf, buf_len); -} #endif /* WITH_WSREP */ /** @} (End of group Event_Scheduler) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 7fe1adc346e..2c57c164446 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4841,12 +4841,12 @@ static int init_server_components() unireg_abort(1); /* need to configure logging before initializing storage engines */ - if (!opt_bin_log_used) + if (!opt_bin_log_used && !WSREP_ON) { - if (!WSREP_ON && opt_log_slave_updates) + if (opt_log_slave_updates) sql_print_warning("You need to use --log-bin to make " "--log-slave-updates work."); - if (!WSREP_ON && binlog_format_used) + if (binlog_format_used) sql_print_warning("You need to use --log-bin to make " "--binlog-format work."); } @@ -9214,8 +9214,8 @@ static int get_options(int *argc_ptr, char ***argv_ptr) (Yes, this is a hack, but it's required as the definition of max_relay_log_size allows it to be set to 0). */ - max_relay_log_size_var= intern_find_sys_var("max_relay_log_size", 0); - max_binlog_size_var= intern_find_sys_var("max_binlog_size", 0); + max_relay_log_size_var= intern_find_sys_var(STRING_WITH_LEN("max_relay_log_size")); + max_binlog_size_var= intern_find_sys_var(STRING_WITH_LEN("max_binlog_size")); if (max_binlog_size_var && max_relay_log_size_var) { max_relay_log_size_var->option.min_value= diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 0dd273a0df7..8dc9c776def 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -22,6 +22,7 @@ #include "rpl_filter.h" #include "sql_callback.h" #include "sp_head.h" +#include "sql_show.h" #include "sp.h" #include "wsrep_priv.h" #include "wsrep_thd.h" @@ -1271,6 +1272,35 @@ int wsrep_to_buf_helper( return ret; } +static int +wsrep_alter_query_string(THD *thd, String *buf) +{ + /* Append the "ALTER" part of the query */ + if (buf->append(STRING_WITH_LEN("ALTER "))) + return 1; + /* Append definer */ + append_definer(thd, buf, &(thd->lex->definer->user), &(thd->lex->definer->host)); + /* Append the left part of thd->query after event name part */ + if (buf->append(thd->lex->stmt_definition_begin, + thd->lex->stmt_definition_end - + thd->lex->stmt_definition_begin)) + return 1; + + return 0; +} + +int wsrep_alter_event_query(THD *thd, uchar** buf, size_t* buf_len) +{ + String log_query; + + if (wsrep_alter_query_string(thd, &log_query)) + { + WSREP_WARN("events alter string failed: %s", thd->query()); + return 1; + } + return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(), buf, buf_len); +} + #include "sql_show.h" static int create_view_query(THD *thd, uchar** buf, size_t* buf_len) From 13af416a82796648dffdffbda0da6d60513d7ddf Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 28 Sep 2014 11:08:07 +0200 Subject: [PATCH 075/153] cleanup: wsrep_check_opts --- sql/mysqld.cc | 12 +- sql/wsrep_check_opts.cc | 403 +++++++--------------------------------- sql/wsrep_mysqld.h | 4 +- 3 files changed, 68 insertions(+), 351 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 2c57c164446..4119e0e5554 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4142,15 +4142,6 @@ static int init_common_variables() SQLCOM_END + 8); #endif -#ifdef WITH_WSREP - /* - This is a protection against mutually incompatible option values. - Note WSREP_ON == global_system_variables.wsrep_on - */ - if (WSREP_ON && wsrep_check_opts (remaining_argc, remaining_argv)) - global_system_variables.wsrep_on= 0; -#endif /* WITH_WSREP */ - if (get_options(&remaining_argc, &remaining_argv)) return 1; set_server_version(); @@ -4990,6 +4981,9 @@ a file name for --log-bin-index option", opt_binlog_index_name); } plugins_are_initialized= TRUE; /* Don't separate from init function */ + if (wsrep_check_opts()) + unireg_abort(1); + /* we do want to exit if there are any other unknown options */ if (remaining_argc > 1) { diff --git a/sql/wsrep_check_opts.cc b/sql/wsrep_check_opts.cc index 5ec18c79978..a4c12e7deb2 100644 --- a/sql/wsrep_check_opts.cc +++ b/sql/wsrep_check_opts.cc @@ -1,4 +1,5 @@ /* Copyright 2011 Codership Oy + Copyright 2014 SkySQL Ab. 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 @@ -13,367 +14,89 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -//#include -#include -//#include -//#include +#include "mysqld.h" +#include "sys_vars_shared.h" +#include "wsrep.h" +#include "wsrep_sst.h" +//#include +//#include "wsrep_mysqld.h" -#include "wsrep_mysqld.h" +extern char *my_bind_addr_str; -#include -#include -#include -#include - -/* This file is about checking for correctness of mysql configuration options */ - -struct opt +int wsrep_check_opts() { - const char* const name; - const char* value; -}; - -/* A list of options to check. - * At first we assume default values and then see if they are changed on CLI or - * in my.cnf */ -static struct opt opts[] = -{ - { "wsrep_slave_threads", "1" }, // mysqld.cc - { "bind_address", "0.0.0.0" }, // mysqld.cc - { "wsrep_sst_method", "rsync" }, // mysqld.cc - { "wsrep_sst_receive_address","AUTO"}, // mysqld.cc - { "binlog_format", "ROW" }, // mysqld.cc - { "wsrep_provider", "none" }, // mysqld.cc - { "query_cache_type", "0" }, // mysqld.cc - { "query_cache_size", "0" }, // mysqld.cc - { "locked_in_memory", "0" }, // mysqld.cc - { "wsrep_cluster_address", "0" }, // mysqld.cc - { "locks_unsafe_for_binlog", "0" }, // ha_innodb.cc - { "autoinc_lock_mode", "1" }, // ha_innodb.cc - { 0, 0 } -}; - -enum -{ - WSREP_SLAVE_THREADS, - BIND_ADDRESS, - WSREP_SST_METHOD, - WSREP_SST_RECEIVE_ADDRESS, - BINLOG_FORMAT, - WSREP_PROVIDER, - QUERY_CACHE_TYPE, - QUERY_CACHE_SIZE, - LOCKED_IN_MEMORY, - WSREP_CLUSTER_ADDRESS, - LOCKS_UNSAFE_FOR_BINLOG, - AUTOINC_LOCK_MODE -}; - - -/* A class to make a copy of argv[] vector */ -struct argv_copy -{ - int const argc_; - char** argv_; - - argv_copy (int const argc, const char* const argv[]) : - argc_ (argc), - argv_ (reinterpret_cast(calloc(argc_, sizeof(char*)))) + if (wsrep_slave_threads > 1) + { + sys_var *autoinc_lock_mode= + intern_find_sys_var(STRING_WITH_LEN("innodb_autoinc_lock_mode")); + bool is_null; + if (autoinc_lock_mode && + autoinc_lock_mode->val_int(&is_null, 0, OPT_GLOBAL, 0) != 2) { - if (argv_) - { - for (int i = 0; i < argc_; ++i) - { - argv_[i] = strdup(argv[i]); - - if (!argv_[i]) - { - argv_free (); // free whatever bee allocated - return; - } - } - } + WSREP_ERROR("Parallel applying (wsrep_slave_threads > 1) requires" + " innodb_autoinc_lock_mode = 2."); + return 1; } - ~argv_copy () { argv_free (); } - -private: - argv_copy (const argv_copy&); - argv_copy& operator= (const argv_copy&); - - void argv_free() - { - if (argv_) - { - for (int i = 0; (i < argc_) && argv_[i] ; ++i) free (argv_[i]); - free (argv_); - argv_ = 0; - } - } -}; - -/* a short corresponding to '--' byte sequence */ -static short const long_opt_prefix ('-' + ('-' << 8)); - -/* Normalizes long options to have '_' instead of '-' */ -static int -normalize_opts (argv_copy& a) -{ - if (a.argv_) - { - for (int i = 0; i < a.argc_; ++i) - { - char* ptr = a.argv_[i]; - if (long_opt_prefix == *(short*)ptr) // long option - { - ptr += 2; - const char* end = strchr(ptr, '='); - - if (!end) end = ptr + strlen(ptr); - - for (; ptr != end; ++ptr) if ('-' == *ptr) *ptr = '_'; - } - } - - return 0; - } - - return EINVAL; -} - -/* Find required options in the argument list and change their values */ -static int -find_opts (argv_copy& a, struct opt* const opts) -{ - for (int i = 0; i < a.argc_; ++i) - { - char* ptr = a.argv_[i] + 2; // we're interested only in long options - - struct opt* opt = opts; - for (; 0 != opt->name; ++opt) - { - if (!strstr(ptr, opt->name)) continue; // try next option - - /* 1. try to find value after the '=' */ - opt->value = strchr(ptr, '=') + 1; - - /* 2. if no '=', try next element in the argument vector */ - if (reinterpret_cast(1) == opt->value) - { - /* also check that the next element is not an option itself */ - if (i + 1 < a.argc_ && *(a.argv_[i + 1]) != '-') - { - ++i; - opt->value = a.argv_[i]; - } - else opt->value = ""; // no value supplied (like boolean opt) - } - - break; // option found, break inner loop - } - } - - return 0; -} - -/* Parses string for an integer. Returns 0 on success. */ -int get_long_long (const struct opt& opt, long long* const val, int const base) -{ - const char* const str = opt.value; - - if ('\0' != *str) - { - char* endptr; - - *val = strtoll (str, &endptr, base); - - if ('k' == *endptr || 'K' == *endptr) - { - *val *= 1024L; - endptr++; - } - else if ('m' == *endptr || 'M' == *endptr) - { - *val *= 1024L * 1024L; - endptr++; - } - else if ('g' == *endptr || 'G' == *endptr) - { - *val *= 1024L * 1024L * 1024L; - endptr++; - } - - if ('\0' == *endptr) return 0; // the whole string was a valid integer - } - - WSREP_ERROR ("Bad value for *%s: '%s'. Should be integer.", - opt.name, opt.value); - - return EINVAL; -} - -/* This is flimzy coz hell knows how mysql interprets boolean strings... - * and, no, I'm not going to become versed in how mysql handles options - - * I'd rather sing. - - Aha, http://dev.mysql.com/doc/refman/5.1/en/dynamic-system-variables.html: - Variables that have a type of “boolean†can be set to 0, 1, ON or OFF. (If you - set them on the command line or in an option file, use the numeric values.) - - So it is '0' for FALSE, '1' or empty string for TRUE - - */ -int get_bool (const struct opt& opt, bool* const val) -{ - const char* str = opt.value; - - while (isspace(*str)) ++str; // skip initial whitespaces - - ssize_t str_len = strlen(str); - switch (str_len) - { - case 0: - *val = true; - return 0; - case 1: - if ('0' == *str || '1' == *str) - { - *val = ('1' == *str); - return 0; - } - } - - WSREP_ERROR ("Bad value for *%s: '%s'. Should be '0', '1' or empty string.", - opt.name, opt.value); - - return EINVAL; -} - -static int -check_opts (int const argc, const char* const argv[], struct opt opts[]) -{ - /* First, make a copy of argv to be able to manipulate it */ - argv_copy a(argc, argv); - - if (!a.argv_) - { - WSREP_ERROR ("Could not copy argv vector: not enough memory."); - return ENOMEM; - } - - int err = normalize_opts (a); - if (err) - { - WSREP_ERROR ("Failed to normalize options."); - return err; - } - - err = find_opts (a, opts); - if (err) - { - WSREP_ERROR ("Failed to parse options."); - return err; - } - - /* At this point we have updated default values in our option list to - what has been specified on the command line / my.cnf */ - - long long slave_threads; - err = get_long_long (opts[WSREP_SLAVE_THREADS], &slave_threads, 10); - if (err) return err; - - int rcode = 0; - - if (slave_threads > 1) - /* Need to check AUTOINC_LOCK_MODE and LOCKS_UNSAFE_FOR_BINLOG */ - { - long long autoinc_lock_mode; - err = get_long_long (opts[AUTOINC_LOCK_MODE], &autoinc_lock_mode, 10); - if (err) return err; - - bool locks_unsafe_for_binlog; - err = get_bool (opts[LOCKS_UNSAFE_FOR_BINLOG],&locks_unsafe_for_binlog); - if (err) return err; - - if (autoinc_lock_mode != 2) - { - WSREP_ERROR ("Parallel applying (wsrep_slave_threads > 1) requires" - " innodb_autoinc_lock_mode = 2."); - rcode = EINVAL; - } - } - - bool locked_in_memory; - err = get_bool (opts[LOCKED_IN_MEMORY], &locked_in_memory); - if (err) { WSREP_ERROR("get_bool error: %s", strerror(err)); return err; } if (locked_in_memory) { - WSREP_ERROR ("Memory locking is not supported (locked_in_memory=%s)", - locked_in_memory ? "ON" : "OFF"); - rcode = EINVAL; + WSREP_ERROR("Memory locking is not supported (locked_in_memory=ON)"); + return 1; } - if (!strcasecmp(opts[WSREP_SST_METHOD].value,"mysqldump")) + if (!strcasecmp(wsrep_sst_method, "mysqldump")) { - if (!strcasecmp(opts[BIND_ADDRESS].value, "127.0.0.1") || - !strcasecmp(opts[BIND_ADDRESS].value, "localhost")) - { - WSREP_ERROR ("wsrep_sst_method is set to 'mysqldump' yet " - "mysqld bind_address is set to '%s', which makes it " - "impossible to receive state transfer from another " - "node, since mysqld won't accept such connections. " - "If you wish to use mysqldump state transfer method, " - "set bind_address to allow mysql client connections " - "from other cluster members (e.g. 0.0.0.0).", - opts[BIND_ADDRESS].value); - rcode = EINVAL; - } + if (!strcasecmp(my_bind_addr_str, "127.0.0.1") || + !strcasecmp(my_bind_addr_str, "localhost")) + { + WSREP_ERROR("wsrep_sst_method is set to 'mysqldump' yet " + "mysqld bind_address is set to '%s', which makes it " + "impossible to receive state transfer from another " + "node, since mysqld won't accept such connections. " + "If you wish to use mysqldump state transfer method, " + "set bind_address to allow mysql client connections " + "from other cluster members (e.g. 0.0.0.0).", + my_bind_addr_str); + return 1; + } } else { - // non-mysqldump SST requires wsrep_cluster_address on startup - if (strlen(opts[WSREP_CLUSTER_ADDRESS].value) == 0) - { - WSREP_ERROR ("%s SST method requires wsrep_cluster_address to be " - "configured on startup.",opts[WSREP_SST_METHOD].value); - rcode = EINVAL; - } + // non-mysqldump SST requires wsrep_cluster_address on startup + if (!wsrep_cluster_address || !wsrep_cluster_address[0]) + { + WSREP_ERROR ("%s SST method requires wsrep_cluster_address to be " + "configured on startup.", wsrep_sst_method); + return 1; + } } - if (strcasecmp(opts[WSREP_SST_RECEIVE_ADDRESS].value, "AUTO")) + if (strcasecmp(wsrep_sst_receive_address, "AUTO")) { - if (!strncasecmp(opts[WSREP_SST_RECEIVE_ADDRESS].value, - "127.0.0.1", strlen("127.0.0.1")) || - !strncasecmp(opts[WSREP_SST_RECEIVE_ADDRESS].value, - "localhost", strlen("localhost"))) - { - WSREP_WARN ("wsrep_sst_receive_address is set to '%s' which " - "makes it impossible for another host to reach this " - "one. Please set it to the address which this node " - "can be connected at by other cluster members.", - opts[WSREP_SST_RECEIVE_ADDRESS].value); -// rcode = EINVAL; - } + if (!strncasecmp(wsrep_sst_receive_address, STRING_WITH_LEN("127.0.0.1")) || + !strncasecmp(wsrep_sst_receive_address, STRING_WITH_LEN("localhost"))) + { + WSREP_WARN("wsrep_sst_receive_address is set to '%s' which " + "makes it impossible for another host to reach this " + "one. Please set it to the address which this node " + "can be connected at by other cluster members.", + wsrep_sst_receive_address); + } } - if (strcasecmp(opts[WSREP_PROVIDER].value, "none")) + if (strcasecmp(wsrep_provider, "NONE")) { - if (strcasecmp(opts[BINLOG_FORMAT].value, "ROW")) - { - WSREP_ERROR ("Only binlog_format = 'ROW' is currently supported. " - "Configured value: '%s'. Please adjust your " - "configuration.", opts[BINLOG_FORMAT].value); + if (global_system_variables.binlog_format != BINLOG_FORMAT_ROW) + { + WSREP_ERROR("Only binlog_format = 'ROW' is currently supported. " + "Configured value: '%s'. Please adjust your " + "configuration.", + binlog_format_names[global_system_variables.binlog_format]); - rcode = EINVAL; - } + return 1; + } } - - return rcode; -} - -int -wsrep_check_opts (int const argc, char* const* const argv) -{ - return check_opts (argc, argv, opts); + } + return 0; } diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index ce12c13b5a8..d9ac32d1f6c 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -152,8 +152,8 @@ extern void wsrep_kill_mysql(THD *thd); /* new defines */ extern void wsrep_stop_replication(THD *thd); extern bool wsrep_start_replication(); -extern bool wsrep_sync_wait (THD* thd, uint mask = WSREP_SYNC_WAIT_BEFORE_READ); -extern int wsrep_check_opts (int argc, char* const* argv); +extern bool wsrep_sync_wait(THD* thd, uint mask = WSREP_SYNC_WAIT_BEFORE_READ); +extern int wsrep_check_opts(); extern void wsrep_prepend_PATH (const char* path); /* some inline functions are defined in wsrep_mysqld_inl.h */ From eaec266eb16c8f02835f76ac987fca5de4debd51 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 28 Sep 2014 12:41:51 +0200 Subject: [PATCH 076/153] restore and fix wsrep status variables --- sql/mysqld.cc | 3 + sql/sql_class.cc | 2 - sql/sql_class.h | 1 - sql/sql_parse.cc | 8 --- sql/wsrep_mysqld.h | 1 + sql/wsrep_var.cc | 138 +++++++++++++++++---------------------------- 6 files changed, 56 insertions(+), 97 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 4119e0e5554..17f8169259e 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -8174,6 +8174,9 @@ SHOW_VAR status_vars[]= { {"Uptime", (char*) &show_starttime, SHOW_SIMPLE_FUNC}, #ifdef ENABLED_PROFILING {"Uptime_since_flush_status",(char*) &show_flushstatustime, SHOW_SIMPLE_FUNC}, +#endif +#ifdef WITH_WSREP + {"wsrep", (char*) &wsrep_show_status, SHOW_FUNC}, #endif {NullS, NullS, SHOW_LONG} }; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 782e4a27317..dde0a9a2f7a 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1026,7 +1026,6 @@ THD::THD(bool is_wsrep_applier) wsrep_retry_query_len = 0; wsrep_retry_command = COM_CONNECT; wsrep_consistency_check = NO_CONSISTENCY_CHECK; - wsrep_status_vars = 0; wsrep_mysql_replicated = 0; wsrep_TOI_pre_query = NULL; wsrep_TOI_pre_query_len = 0; @@ -1635,7 +1634,6 @@ THD::~THD() mysql_mutex_destroy(&LOCK_wsrep_thd); if (wsrep_rli) delete wsrep_rli; if (wsrep_rgi) delete wsrep_rgi; - if (wsrep_status_vars) wsrep->stats_free(wsrep, wsrep_status_vars); #endif /* Close connection */ #ifndef EMBEDDED_LIBRARY diff --git a/sql/sql_class.h b/sql/sql_class.h index 2db9618a824..4b787943ec9 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3767,7 +3767,6 @@ public: enum enum_server_command wsrep_retry_command; enum wsrep_consistency_check_mode wsrep_consistency_check; - wsrep_stats_var* wsrep_status_vars; int wsrep_mysql_replicated; const char* wsrep_TOI_pre_query; /* a query to apply before the actual TOI query */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index cdafeccd392..0180a1d97c5 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5705,14 +5705,6 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables) else status_var_add(thd->status_var.rows_sent, thd->get_sent_row_count()); -#ifdef WITH_WSREP - if (thd->wsrep_status_vars) - { - wsrep->stats_free (wsrep, thd->wsrep_status_vars); - thd->wsrep_status_vars = 0; - } -#endif - return res; } diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index d9ac32d1f6c..bc78d2beecf 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -86,6 +86,7 @@ extern my_bool wsrep_restart_slave; extern my_bool wsrep_restart_slave_activated; extern my_bool wsrep_slave_FK_checks; extern my_bool wsrep_slave_UK_checks; +extern ulong wsrep_running_threads; enum enum_wsrep_OSU_method { WSREP_OSU_TOI, WSREP_OSU_RSU }; enum enum_wsrep_sync_wait { diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc index 3f4b163281b..c6e9b89ca55 100644 --- a/sql/wsrep_var.cc +++ b/sql/wsrep_var.cc @@ -15,9 +15,9 @@ #include "wsrep_var.h" +#include #include #include -#include #include #include #include "wsrep_priv.h" @@ -507,99 +507,65 @@ bool wsrep_desync_update (sys_var *self, THD* thd, enum_var_type type) return false; } -/* - * Status variables stuff below - */ -static inline void -wsrep_assign_to_mysql (SHOW_VAR* mysql, wsrep_stats_var* wsrep) +static SHOW_VAR wsrep_status_vars[]= { - mysql->name = wsrep->name; - switch (wsrep->type) { - case WSREP_VAR_INT64: - mysql->value = (char*) &wsrep->value._int64; - mysql->type = SHOW_LONGLONG; - break; - case WSREP_VAR_STRING: - mysql->value = (char*) &wsrep->value._string; - mysql->type = SHOW_CHAR_PTR; - break; - case WSREP_VAR_DOUBLE: - mysql->value = (char*) &wsrep->value._double; - mysql->type = SHOW_DOUBLE; - break; - } -} + {"connected", (char*) &wsrep_connected, SHOW_BOOL}, + {"ready", (char*) &wsrep_ready, SHOW_BOOL}, + {"cluster_state_uuid",(char*) &wsrep_cluster_state_uuid,SHOW_CHAR_PTR}, + {"cluster_conf_id", (char*) &wsrep_cluster_conf_id, SHOW_LONGLONG}, + {"cluster_status", (char*) &wsrep_cluster_status, SHOW_CHAR_PTR}, + {"cluster_size", (char*) &wsrep_cluster_size, SHOW_LONG_NOFLUSH}, + {"local_index", (char*) &wsrep_local_index, SHOW_LONG_NOFLUSH}, + {"local_bf_aborts", (char*) &wsrep_show_bf_aborts, SHOW_SIMPLE_FUNC}, + {"provider_name", (char*) &wsrep_provider_name, SHOW_CHAR_PTR}, + {"provider_version", (char*) &wsrep_provider_version, SHOW_CHAR_PTR}, + {"provider_vendor", (char*) &wsrep_provider_vendor, SHOW_CHAR_PTR}, + {"thread_count", (char*) &wsrep_running_threads, SHOW_LONG_NOFLUSH} +}; -#if DYNAMIC -// somehow this mysql status thing works only with statically allocated arrays. -static SHOW_VAR* mysql_status_vars = NULL; -static int mysql_status_len = -1; -#else -static SHOW_VAR mysql_status_vars[512 + 1]; -static const int mysql_status_len = 512; -#endif - -static void export_wsrep_status_to_mysql(THD* thd) +static int show_var_cmp(const void *var1, const void *var2) { - int wsrep_status_len, i; - - thd->wsrep_status_vars = wsrep->stats_get(wsrep); - - if (!thd->wsrep_status_vars) { - return; - } - - for (wsrep_status_len = 0; - thd->wsrep_status_vars[wsrep_status_len].name != NULL; - wsrep_status_len++); - -#if DYNAMIC - if (wsrep_status_len != mysql_status_len) { - void* tmp = realloc (mysql_status_vars, - (wsrep_status_len + 1) * sizeof(SHOW_VAR)); - if (!tmp) { - - sql_print_error ("Out of memory for wsrep status variables." - "Number of variables: %d", wsrep_status_len); - return; - } - - mysql_status_len = wsrep_status_len; - mysql_status_vars = (SHOW_VAR*)tmp; - } - /* @TODO: fix this: */ -#else - if (mysql_status_len < wsrep_status_len) wsrep_status_len= mysql_status_len; -#endif - - for (i = 0; i < wsrep_status_len; i++) - wsrep_assign_to_mysql (mysql_status_vars + i, thd->wsrep_status_vars + i); - - mysql_status_vars[wsrep_status_len].name = NullS; - mysql_status_vars[wsrep_status_len].value = NullS; - mysql_status_vars[wsrep_status_len].type = SHOW_LONG; + return strcasecmp(((SHOW_VAR*)var1)->name, ((SHOW_VAR*)var2)->name); } int wsrep_show_status (THD *thd, SHOW_VAR *var, char *buff) { - export_wsrep_status_to_mysql(thd); + uint i, maxi= SHOW_VAR_FUNC_BUFF_SIZE / sizeof(*var) - 1; + SHOW_VAR *v= (SHOW_VAR *)buff; + var->type= SHOW_ARRAY; - var->value= (char *) &mysql_status_vars; -#if 0 - {"wsrep_connected", (char*) &wsrep_connected, SHOW_BOOL}, - {"wsrep_ready", (char*) &wsrep_ready, SHOW_BOOL}, - {"wsrep_cluster_state_uuid", (char*) &wsrep_cluster_state_uuid,SHOW_CHAR_PTR}, - {"wsrep_cluster_conf_id", (char*) &wsrep_cluster_conf_id, SHOW_LONGLONG}, - {"wsrep_cluster_status", (char*) &wsrep_cluster_status, SHOW_CHAR_PTR}, - {"wsrep_cluster_size", (char*) &wsrep_cluster_size, SHOW_LONG_NOFLUSH}, - {"wsrep_local_index", (char*) &wsrep_local_index, SHOW_LONG_NOFLUSH}, - {"wsrep_local_bf_aborts", (char*) &wsrep_show_bf_aborts, SHOW_SIMPLE_FUNC}, - {"wsrep_provider_name", (char*) &wsrep_provider_name, SHOW_CHAR_PTR}, - {"wsrep_provider_version", (char*) &wsrep_provider_version, SHOW_CHAR_PTR}, - {"wsrep_provider_vendor", (char*) &wsrep_provider_vendor, SHOW_CHAR_PTR}, - {"wsrep_thread_count", (char*) &wsrep_running_threads, SHOW_LONG_NOFLUSH}, - {"wsrep", (char*) &wsrep_show_status, SHOW_FUNC}, -#endif + var->value= buff; + + for (i=0; i < array_elements(wsrep_status_vars); i++) + *v++= wsrep_status_vars[i]; + + DBUG_ASSERT(i < maxi); + + wsrep_stats_var* stats= wsrep->stats_get(wsrep); + for (wsrep_stats_var *sv= stats; i < maxi && sv && sv->name; i++, sv++, v++) + { + v->name = thd->strdup(sv->name); + switch (sv->type) { + case WSREP_VAR_INT64: + v->value = (char*)thd->memdup(&sv->value._int64, sizeof(longlong)); + v->type = SHOW_LONGLONG; + break; + case WSREP_VAR_STRING: + v->value = thd->strdup(sv->value._string); + v->type = SHOW_CHAR; + break; + case WSREP_VAR_DOUBLE: + v->value = (char*)thd->memdup(&sv->value._double, sizeof(double)); + v->type = SHOW_DOUBLE; + break; + } + DBUG_ASSERT(i < maxi); + } + wsrep->stats_free(wsrep, stats); + + my_qsort(buff, i, sizeof(*v), show_var_cmp); + + v->name= 0; // terminator return 0; } From b3469520a1b838f08cbebaa8047f2bd3f58fef89 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 28 Sep 2014 16:43:44 +0200 Subject: [PATCH 077/153] cleanup: remove OPT_WSREP_START_POSITION and OPT_WSREP_SST_AUTH there is no reason to initialize wsrep start position and auth from inside the get_one_option() callback --- sql/mysqld.cc | 6 ------ sql/mysqld.h | 2 -- sql/sys_vars.cc | 4 ++-- sql/wsrep_hton.cc | 5 +++-- sql/wsrep_mysqld.cc | 5 +++++ 5 files changed, 10 insertions(+), 12 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 17f8169259e..e92234ddd09 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -8772,12 +8772,6 @@ mysqld_get_one_option(int optid, case OPT_LOWER_CASE_TABLE_NAMES: lower_case_table_names_used= 1; break; - case OPT_WSREP_START_POSITION: - wsrep_start_position_init (argument); - break; - case OPT_WSREP_SST_AUTH: - wsrep_sst_auth_init (argument); - break; #if defined(ENABLED_DEBUG_SYNC) case OPT_DEBUG_SYNC_TIMEOUT: /* diff --git a/sql/mysqld.h b/sql/mysqld.h index 1f7a48050f4..d1efc5180a6 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -599,8 +599,6 @@ enum options_mysqld OPT_WANT_CORE, OPT_MYSQL_COMPATIBILITY, OPT_MYSQL_TO_BE_IMPLEMENTED, - OPT_WSREP_START_POSITION, - OPT_WSREP_SST_AUTH, OPT_which_is_always_the_last }; #endif diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 5722cd38de5..0fab83be90d 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -4553,7 +4553,7 @@ static Sys_var_charptr Sys_wsrep_sst_receive_address( static Sys_var_charptr Sys_wsrep_sst_auth( "wsrep_sst_auth", "Authentication for SST connection", - PREALLOCATED GLOBAL_VAR(wsrep_sst_auth), CMD_LINE(REQUIRED_ARG, OPT_WSREP_SST_AUTH), + PREALLOCATED GLOBAL_VAR(wsrep_sst_auth), CMD_LINE(REQUIRED_ARG), IN_SYSTEM_CHARSET, DEFAULT(NULL), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(wsrep_sst_auth_check), @@ -4582,7 +4582,7 @@ static Sys_var_mybool Sys_wsrep_on ( static Sys_var_charptr Sys_wsrep_start_position ( "wsrep_start_position", "global transaction position to start from ", PREALLOCATED GLOBAL_VAR(wsrep_start_position), - CMD_LINE(REQUIRED_ARG, OPT_WSREP_START_POSITION), + CMD_LINE(REQUIRED_ARG), IN_SYSTEM_CHARSET, DEFAULT(WSREP_START_POSITION_ZERO), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(wsrep_start_position_check), diff --git a/sql/wsrep_hton.cc b/sql/wsrep_hton.cc index 96f1431a82f..4fc9ce2bce2 100644 --- a/sql/wsrep_hton.cc +++ b/sql/wsrep_hton.cc @@ -66,10 +66,11 @@ handlerton *wsrep_hton; */ void wsrep_register_hton(THD* thd, bool all) { - if (thd->wsrep_exec_mode != TOTAL_ORDER && !thd->wsrep_apply_toi) + if (WSREP(thd) && thd->wsrep_exec_mode != TOTAL_ORDER && + !thd->wsrep_apply_toi) { THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt; - for (Ha_trx_info *i= trans->ha_list; WSREP(thd) && i; i = i->next()) + for (Ha_trx_info *i= trans->ha_list; i; i = i->next()) { if ((i->ht()->db_type == DB_TYPE_INNODB) || (i->ht()->db_type == DB_TYPE_TOKUDB)) diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 8dc9c776def..2897bb3fb69 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -572,6 +572,11 @@ int wsrep_init() int rcode= -1; DBUG_ASSERT(wsrep_inited == 0); + if (strcmp(wsrep_start_position, WSREP_START_POSITION_ZERO)) + wsrep_start_position_init(wsrep_start_position); + + wsrep_sst_auth_init(wsrep_sst_auth); + wsrep_causal_reads_update(&global_system_variables); mysql_mutex_register("sql", wsrep_mutexes, array_elements(wsrep_mutexes)); From edd1de3d1c348ef9f5bfc4f602692f4e438e7fcb Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 28 Sep 2014 17:50:02 +0200 Subject: [PATCH 078/153] cleanup: introduce CF_SKIP_WSREP_CHECK remove if() over many COM_xxx values --- sql/sql_class.h | 5 ++++ sql/sql_parse.cc | 60 +++++++++++++++++++++++------------------------- 2 files changed, 34 insertions(+), 31 deletions(-) diff --git a/sql/sql_class.h b/sql/sql_class.h index 4b787943ec9..cab2968a62b 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -4894,6 +4894,11 @@ public: */ #define CF_SKIP_QUESTIONS (1U << 1) +/** + Do not check that wsrep snapshot is ready before allowing this command +*/ +#define CF_SKIP_WSREP_CHECK (1U << 2) + void mark_transaction_to_rollback(THD *thd, bool all); /* Inline functions */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 0180a1d97c5..6aa76ebf9c7 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -265,11 +265,26 @@ void init_update_queries(void) /* Initialize the server command flags array. */ memset(server_command_flags, 0, sizeof(server_command_flags)); - server_command_flags[COM_STATISTICS]= CF_SKIP_QUERY_ID | CF_SKIP_QUESTIONS; - server_command_flags[COM_PING]= CF_SKIP_QUERY_ID | CF_SKIP_QUESTIONS; + server_command_flags[COM_STATISTICS]= CF_SKIP_QUERY_ID | CF_SKIP_QUESTIONS | CF_SKIP_WSREP_CHECK; + server_command_flags[COM_PING]= CF_SKIP_QUERY_ID | CF_SKIP_QUESTIONS | CF_SKIP_WSREP_CHECK; server_command_flags[COM_STMT_PREPARE]= CF_SKIP_QUESTIONS; - server_command_flags[COM_STMT_CLOSE]= CF_SKIP_QUESTIONS; - server_command_flags[COM_STMT_RESET]= CF_SKIP_QUESTIONS; + server_command_flags[COM_STMT_CLOSE]= CF_SKIP_QUESTIONS | CF_SKIP_WSREP_CHECK; + server_command_flags[COM_STMT_RESET]= CF_SKIP_QUESTIONS | CF_SKIP_WSREP_CHECK; + + server_command_flags[COM_QUIT]= CF_SKIP_WSREP_CHECK; + server_command_flags[COM_PROCESS_INFO]= CF_SKIP_WSREP_CHECK; + server_command_flags[COM_PROCESS_KILL]= CF_SKIP_WSREP_CHECK; + server_command_flags[COM_SHUTDOWN]= CF_SKIP_WSREP_CHECK; + server_command_flags[COM_SLEEP]= CF_SKIP_WSREP_CHECK; + server_command_flags[COM_TIME]= CF_SKIP_WSREP_CHECK; + server_command_flags[COM_END]= CF_SKIP_WSREP_CHECK; + + /* + COM_QUERY and COM_SET_OPTION are allowed to pass the early COM_xxx filter, + they're checked later in mysql_execute_command(). + */ + server_command_flags[COM_QUERY]= CF_SKIP_WSREP_CHECK; + server_command_flags[COM_SET_OPTION]= CF_SKIP_WSREP_CHECK; /* Initialize the sql command flags array. */ memset(sql_command_flags, 0, sizeof(sql_command_flags)); @@ -874,9 +889,11 @@ void cleanup_items(Item *item) } -#ifdef WITH_WSREP +#ifndef EMBEDDED_LIBRARY + static bool wsrep_node_is_ready(THD *thd) { +#ifdef WITH_WSREP if (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready) { my_message(ER_UNKNOWN_COM_ERROR, @@ -884,12 +901,9 @@ static bool wsrep_node_is_ready(THD *thd) MYF(0)); return false; } +#endif return true; } -#endif - - -#ifndef EMBEDDED_LIBRARY /** Read one command from connection and execute it (query or simple command). @@ -1069,29 +1083,13 @@ bool do_command(THD *thd) vio_description(net->vio), command, command_name[command].str)); - if (WSREP(thd)) + /* bail out if DB snapshot has not been installed. */ + if (!(server_command_flags[command] & CF_SKIP_WSREP_CHECK) && + !wsrep_node_is_ready(thd)) { - /* - * bail out if DB snapshot has not been installed. We however, - * allow queries "SET" and "SHOW", they are trapped later in execute_command - */ - if (command != COM_QUERY && - command != COM_PING && - command != COM_QUIT && - command != COM_PROCESS_INFO && - command != COM_PROCESS_KILL && - command != COM_SET_OPTION && - command != COM_SHUTDOWN && - command != COM_SLEEP && - command != COM_STATISTICS && - command != COM_TIME && - command != COM_END && - !wsrep_node_is_ready(thd)) - { - thd->protocol->end_statement(); - return_value= FALSE; - goto out; - } + thd->protocol->end_statement(); + return_value= FALSE; + goto out; } /* Restore read timeout value */ my_net_set_read_timeout(net, thd->variables.net_read_timeout); From 2156f62d2ecddf48844bfa558c7e9bc33edca53c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 29 Sep 2014 19:50:56 +0200 Subject: [PATCH 079/153] portability: use getifaddrs() instead of exec'ing /usr/sbin/ifconfig|grep|sed|awk --- cmake/os/WindowsCache.cmake | 1 + config.h.cmake | 1 + configure.cmake | 1 + sql/wsrep_utils.cc | 74 +++++++++++++------------------------ 4 files changed, 29 insertions(+), 48 deletions(-) diff --git a/cmake/os/WindowsCache.cmake b/cmake/os/WindowsCache.cmake index 4786108ec8c..8eccf47aa66 100644 --- a/cmake/os/WindowsCache.cmake +++ b/cmake/os/WindowsCache.cmake @@ -76,6 +76,7 @@ SET(HAVE_FSYNC CACHE INTERNAL "") SET(HAVE_FTIME 1 CACHE INTERNAL "") SET(HAVE_FTRUNCATE CACHE INTERNAL "") SET(HAVE_GETADDRINFO 1 CACHE INTERNAL "") +SET(HAVE_GETIFADDRS CACHE INTERNAL "") SET(HAVE_GETCWD 1 CACHE INTERNAL "") SET(HAVE_GETHOSTBYADDR_R CACHE INTERNAL "") SET(HAVE_GETHRTIME CACHE INTERNAL "") diff --git a/config.h.cmake b/config.h.cmake index 57d53975ac7..2bb62516d2b 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -163,6 +163,7 @@ #cmakedefine HAVE_FSYNC 1 #cmakedefine HAVE_FTIME 1 #cmakedefine HAVE_GETADDRINFO 1 +#cmakedefine HAVE_GETIFADDRS 1 #cmakedefine HAVE_GETCWD 1 #cmakedefine HAVE_GETHOSTBYADDR_R 1 #cmakedefine HAVE_GETHRTIME 1 diff --git a/configure.cmake b/configure.cmake index c562b583830..6997a3c3478 100644 --- a/configure.cmake +++ b/configure.cmake @@ -371,6 +371,7 @@ CHECK_FUNCTION_EXISTS (getpassphrase HAVE_GETPASSPHRASE) CHECK_FUNCTION_EXISTS (getpwnam HAVE_GETPWNAM) CHECK_FUNCTION_EXISTS (getpwuid HAVE_GETPWUID) CHECK_FUNCTION_EXISTS (getrlimit HAVE_GETRLIMIT) +CHECK_FUNCTION_EXISTS (getifaddrs HAVE_GETIFADDRS) CHECK_FUNCTION_EXISTS (getrusage HAVE_GETRUSAGE) CHECK_FUNCTION_EXISTS (getwd HAVE_GETWD) CHECK_FUNCTION_EXISTS (gmtime_r HAVE_GMTIME_R) diff --git a/sql/wsrep_utils.cc b/sql/wsrep_utils.cc index e7509d393d8..c4a992c751a 100644 --- a/sql/wsrep_utils.cc +++ b/sql/wsrep_utils.cc @@ -34,6 +34,10 @@ #include #include // getaddrinfo() +#ifdef HAVE_GETIFADDRS +#include +#endif + extern char** environ; // environment variables static wsp::string wsrep_PATH; @@ -371,7 +375,7 @@ size_t wsrep_guess_ip (char* buf, size_t buf_len) { size_t ip_len = 0; - if (my_bind_addr_str && strlen(my_bind_addr_str)) + if (my_bind_addr_str && my_bind_addr_str[0] != '\0') { unsigned int const ip_type= wsrep_check_ip(my_bind_addr_str); @@ -405,55 +409,29 @@ size_t wsrep_guess_ip (char* buf, size_t buf_len) return ip_len; } - // try to find the address of the first one -#if (TARGET_OS_LINUX == 1) - const char cmd[] = "/sbin/ifconfig | " -// "grep -m1 -1 -E '^[a-z]?eth[0-9]' | tail -n 1 | " - "grep -E '^[[:space:]]+inet addr:' | grep -m1 -v 'inet addr:127' | " - "sed 's/:/ /' | awk '{ print $3 }'"; -#elif defined(__sun__) - const char cmd[] = "/sbin/ifconfig -a | " - "/usr/gnu/bin/grep -m1 -1 -E 'net[0-9]:' | tail -n 1 | awk '{ print $2 }'"; -#elif defined(__APPLE__) || defined(__FreeBSD__) - const char cmd[] = "/sbin/route -nv get 8.8.8.8 | tail -n1 | awk '{print $(NF)}'"; -#else - char *cmd; -#error "OS not supported" +#if HAVE_GETIFADDRS + struct ifaddrs *ifaddr, *ifa; + if (getifaddrs(&ifaddr) == 0) + { + for (ifa= ifaddr; ifa != NULL; ifa = ifa->ifa_next) + { + if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET) // TODO AF_INET6 + continue; + + if (vio_getnameinfo(ifa->ifa_addr, buf, buf_len, NULL, 0, NI_NUMERICHOST)) + continue; + + if (strcmp(buf, "127.0.0.1") == 0) // lame + continue; + + freeifaddrs(ifaddr); + return strlen(buf); + } + freeifaddrs(ifaddr); + } #endif - wsp::process proc (cmd, "r"); - if (NULL != proc.pipe()) { - char* ret; - - ret = fgets (buf, buf_len, proc.pipe()); - - if (proc.wait()) return 0; - - if (NULL == ret) { - WSREP_ERROR("Failed to read output of: '%s'", cmd); - return 0; - } - } - else { - WSREP_ERROR("Failed to execute: '%s'", cmd); - return 0; - } - - // clear possible \n at the end of ip string left by fgets() - ip_len = strlen (buf); - if (ip_len > 0 && '\n' == buf[ip_len - 1]) { - ip_len--; - buf[ip_len] = '\0'; - } - - if (INADDR_NONE == inet_addr(buf)) { - if (strlen(buf) != 0) { - WSREP_WARN("Shell command returned invalid address: '%s'", buf); - } - return 0; - } - - return ip_len; + return 0; } size_t wsrep_guess_address(char* buf, size_t buf_len) From f13cf621472904db6328e5769929b6fc5f08e1cc Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 30 Sep 2014 11:04:38 +0200 Subject: [PATCH 080/153] don't enable SECURITY_HARDENED on old gcc on CentOS 5 x86 (at least) this results in a binary that cannot load plugins. Draw the line, quite arbitrarily, at gcc 4.6. --- CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c54152420f..e80f8d628fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -202,7 +202,12 @@ ENDIF() # enable security hardening features, like most distributions do # in our benchmarks that costs about ~1% of performance, depending on the load -OPTION(SECURITY_HARDENED "Use security-enhancing compiler features (stack protector, relro, etc)" ON) +IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "4.6") + SET(security_default OFF) +ELSE() + SET(security_default ON) +ENDIF() +OPTION(SECURITY_HARDENED "Use security-enhancing compiler features (stack protector, relro, etc)" ${security_default}) IF(SECURITY_HARDENED) # security-enhancing flags MY_CHECK_AND_SET_COMPILER_FLAG("-pie -fPIC") From 251239af67dd20b68e95d58122bdb9a2beafe67f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Thu, 2 Oct 2014 15:09:17 +0300 Subject: [PATCH 081/153] Fix Windows compiler error 'log2f': identifier not found --- storage/innobase/row/row0merge.cc | 9 ++++++++- storage/xtradb/row/row0merge.cc | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index ae1da31c6dd..a5e4c492ac9 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -39,6 +39,13 @@ Completed by Sunny Bains and Marko Makela #include "row0import.h" #include "handler0alter.h" #include "ha_prototypes.h" +#include "math.h" /* log() */ + +float my_log2f(float n) +{ + /* log(n) / log(2) is log2. */ + return (float)(log((double)n) / log((double)2)); +} /* Ignore posix_fadvise() on those platforms where it does not exist */ #if defined __WIN__ @@ -2222,7 +2229,7 @@ row_merge_sort( /* Find the number N which 2^N is greater or equal than num_runs */ /* N is merge sort running count */ - total_merge_sort_count = ceil(log2f(num_runs)); + total_merge_sort_count = ceil(my_log2f(num_runs)); if(total_merge_sort_count <= 0) { total_merge_sort_count=1; } diff --git a/storage/xtradb/row/row0merge.cc b/storage/xtradb/row/row0merge.cc index d54aeb91c03..84d6845363c 100644 --- a/storage/xtradb/row/row0merge.cc +++ b/storage/xtradb/row/row0merge.cc @@ -39,6 +39,13 @@ Completed by Sunny Bains and Marko Makela #include "row0import.h" #include "handler0alter.h" #include "ha_prototypes.h" +#include "math.h" /* log2() */ + +float my_log2f(float n) +{ + /* log(n) / log(2) is log2. */ + return (float)(log((double)n) / log((double)2)); +} /* Ignore posix_fadvise() on those platforms where it does not exist */ #if defined __WIN__ @@ -2228,7 +2235,7 @@ row_merge_sort( /* Find the number N which 2^N is greater or equal than num_runs */ /* N is merge sort running count */ - total_merge_sort_count = ceil(log2f(num_runs)); + total_merge_sort_count = ceil(my_log2f(num_runs)); if(total_merge_sort_count <= 0) { total_merge_sort_count=1; } From ebe4fadcd5d1286d4c29b980185f32db2c5eaf59 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 2 Oct 2014 18:54:01 +0200 Subject: [PATCH 082/153] when running mtr tests don't let galera-started rsyncd to log to syslog --- scripts/wsrep_sst_rsync.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scripts/wsrep_sst_rsync.sh b/scripts/wsrep_sst_rsync.sh index 7bcc398c727..9a880b0218f 100644 --- a/scripts/wsrep_sst_rsync.sh +++ b/scripts/wsrep_sst_rsync.sh @@ -259,11 +259,18 @@ then RSYNC_CONF="$WSREP_SST_OPT_DATA/$MODULE.conf" + if [ -n "$MYSQL_TMP_DIR" ] ; then + SILENT="log file = $MYSQL_TMP_DIR/rsynd.log" + else + SILENT="" + fi + cat << EOF > "$RSYNC_CONF" pid file = $RSYNC_PID use chroot = no read only = no timeout = 300 +$SILENT [$MODULE] path = $WSREP_SST_OPT_DATA [$MODULE-log_dir] From 7474e7baa06505c015d0d327ae923add76306a32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Thu, 2 Oct 2014 21:01:57 +0300 Subject: [PATCH 083/153] MDEV-6807: InnoDB: Assertion failure in file lock0lock.cc (lock != ctx->wait_lock) References: lp:1364840 lp:1280896 - reverted a part of fix for lp:1280896 (updating a unique key can cause parallel applying to hang ) in revision #4105. This "BF (brute force) lock skipping" caused regression which surfaced in randgen test for bug lp:1364840 --- storage/innobase/lock/lock0lock.cc | 3 --- storage/xtradb/lock/lock0lock.cc | 3 --- 2 files changed, 6 deletions(-) diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index bf665eb1955..61da49d1345 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -2079,9 +2079,6 @@ lock_rec_create( return(lock); } trx_mutex_exit(c_lock->trx); - } else if (wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { - HASH_PREPEND(lock_t, hash, lock_sys->rec_hash, - lock_rec_fold(space, page_no), lock); } else { HASH_INSERT(lock_t, hash, lock_sys->rec_hash, lock_rec_fold(space, page_no), lock); diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc index 8cf77e1ec82..018f6f9a69a 100644 --- a/storage/xtradb/lock/lock0lock.cc +++ b/storage/xtradb/lock/lock0lock.cc @@ -2090,9 +2090,6 @@ lock_rec_create( return(lock); } trx_mutex_exit(c_lock->trx); - } else if (wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { - HASH_PREPEND(lock_t, hash, lock_sys->rec_hash, - lock_rec_fold(space, page_no), lock); } else { HASH_INSERT(lock_t, hash, lock_sys->rec_hash, lock_rec_fold(space, page_no), lock); From c768af75b768d45fe045444fe316402ba10b4e29 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Sat, 4 Oct 2014 13:53:33 -0400 Subject: [PATCH 084/153] Minor modifications - Simplified test cases in wsrep.variables - Fixed a condition in wsrep_check_opts.cc - Fixed an "unbound variable" in wsrep_sst_rsync --- mysql-test/suite/wsrep/README | 7 - mysql-test/suite/wsrep/r/variables.result | 165 +++++++----------- .../wsrep/t/mysql_tzinfo_to_sql_symlink.test | 1 + mysql-test/suite/wsrep/t/variables.test | 61 +------ scripts/wsrep_sst_rsync.sh | 2 +- sql/wsrep_check_opts.cc | 94 +++++----- 6 files changed, 116 insertions(+), 214 deletions(-) diff --git a/mysql-test/suite/wsrep/README b/mysql-test/suite/wsrep/README index 988096071a4..e69de29bb2d 100644 --- a/mysql-test/suite/wsrep/README +++ b/mysql-test/suite/wsrep/README @@ -1,7 +0,0 @@ -* 'wsrep' suite is designated for tests which do not require a multi-node - galera cluster. - -* As these tests are specific to wsrep-related functionalities, they must skip - on server built without wsrep patch (vanilla). (-DWITH_WSREP=OFF) - See : include/have_wsrep.inc, include/have_wsrep_enabled.inc, not_wsrep.inc - diff --git a/mysql-test/suite/wsrep/r/variables.result b/mysql-test/suite/wsrep/r/variables.result index 438e4730f57..67206a8810f 100644 --- a/mysql-test/suite/wsrep/r/variables.result +++ b/mysql-test/suite/wsrep/r/variables.result @@ -11,112 +11,110 @@ SET SESSION wsrep_replicate_myisam= ON; ERROR HY000: Variable 'wsrep_replicate_myisam' is a GLOBAL variable and should be set with SET GLOBAL SET GLOBAL wsrep_replicate_myisam= ON; SET GLOBAL wsrep_replicate_myisam= OFF; -SET GLOBAL wsrep_provider=none; # # MDEV#5790: SHOW GLOBAL STATUS LIKE does not show the correct list of # variables when using "_" # -CALL mtr.add_suppression("WSREP: Could not open saved state file for reading.*"); SHOW GLOBAL STATUS LIKE 'wsrep%'; Variable_name Value -wsrep_local_state_uuid # -wsrep_protocol_version # -wsrep_last_committed # -wsrep_replicated # -wsrep_replicated_bytes # -wsrep_repl_keys # -wsrep_repl_keys_bytes # -wsrep_repl_data_bytes # -wsrep_repl_other_bytes # -wsrep_received # -wsrep_received_bytes # -wsrep_local_commits # -wsrep_local_cert_failures # -wsrep_local_replays # -wsrep_local_send_queue # -wsrep_local_send_queue_avg # -wsrep_local_recv_queue # -wsrep_local_recv_queue_avg # -wsrep_local_cached_downto # -wsrep_flow_control_paused_ns # -wsrep_flow_control_paused # -wsrep_flow_control_sent # -wsrep_flow_control_recv # -wsrep_cert_deps_distance # wsrep_apply_oooe # wsrep_apply_oool # wsrep_apply_window # -wsrep_commit_oooe # -wsrep_commit_oool # -wsrep_commit_window # -wsrep_local_state # -wsrep_local_state_comment # -wsrep_cert_index_size # wsrep_causal_reads # +wsrep_cert_deps_distance # +wsrep_cert_index_size # wsrep_cert_interval # -wsrep_incoming_addresses # wsrep_cluster_conf_id # wsrep_cluster_size # wsrep_cluster_state_uuid # wsrep_cluster_status # +wsrep_commit_oooe # +wsrep_commit_oool # +wsrep_commit_window # wsrep_connected # +wsrep_flow_control_paused # +wsrep_flow_control_paused_ns # +wsrep_flow_control_recv # +wsrep_flow_control_sent # +wsrep_incoming_addresses # +wsrep_last_committed # wsrep_local_bf_aborts # +wsrep_local_cached_downto # +wsrep_local_cert_failures # +wsrep_local_commits # wsrep_local_index # +wsrep_local_recv_queue # +wsrep_local_recv_queue_avg # +wsrep_local_replays # +wsrep_local_send_queue # +wsrep_local_send_queue_avg # +wsrep_local_state # +wsrep_local_state_comment # +wsrep_local_state_uuid # +wsrep_protocol_version # wsrep_provider_name # wsrep_provider_vendor # wsrep_provider_version # wsrep_ready # +wsrep_received # +wsrep_received_bytes # +wsrep_repl_data_bytes # +wsrep_repl_keys # +wsrep_repl_keys_bytes # +wsrep_repl_other_bytes # +wsrep_replicated # +wsrep_replicated_bytes # wsrep_thread_count # SHOW GLOBAL STATUS LIKE 'wsrep_%'; Variable_name Value -wsrep_local_state_uuid # -wsrep_protocol_version # -wsrep_last_committed # -wsrep_replicated # -wsrep_replicated_bytes # -wsrep_repl_keys # -wsrep_repl_keys_bytes # -wsrep_repl_data_bytes # -wsrep_repl_other_bytes # -wsrep_received # -wsrep_received_bytes # -wsrep_local_commits # -wsrep_local_cert_failures # -wsrep_local_replays # -wsrep_local_send_queue # -wsrep_local_send_queue_avg # -wsrep_local_recv_queue # -wsrep_local_recv_queue_avg # -wsrep_local_cached_downto # -wsrep_flow_control_paused_ns # -wsrep_flow_control_paused # -wsrep_flow_control_sent # -wsrep_flow_control_recv # -wsrep_cert_deps_distance # wsrep_apply_oooe # wsrep_apply_oool # wsrep_apply_window # -wsrep_commit_oooe # -wsrep_commit_oool # -wsrep_commit_window # -wsrep_local_state # -wsrep_local_state_comment # -wsrep_cert_index_size # wsrep_causal_reads # +wsrep_cert_deps_distance # +wsrep_cert_index_size # wsrep_cert_interval # -wsrep_incoming_addresses # wsrep_cluster_conf_id # wsrep_cluster_size # wsrep_cluster_state_uuid # wsrep_cluster_status # +wsrep_commit_oooe # +wsrep_commit_oool # +wsrep_commit_window # wsrep_connected # +wsrep_flow_control_paused # +wsrep_flow_control_paused_ns # +wsrep_flow_control_recv # +wsrep_flow_control_sent # +wsrep_incoming_addresses # +wsrep_last_committed # wsrep_local_bf_aborts # +wsrep_local_cached_downto # +wsrep_local_cert_failures # +wsrep_local_commits # wsrep_local_index # +wsrep_local_recv_queue # +wsrep_local_recv_queue_avg # +wsrep_local_replays # +wsrep_local_send_queue # +wsrep_local_send_queue_avg # +wsrep_local_state # +wsrep_local_state_comment # +wsrep_local_state_uuid # +wsrep_protocol_version # wsrep_provider_name # wsrep_provider_vendor # wsrep_provider_version # wsrep_ready # +wsrep_received # +wsrep_received_bytes # +wsrep_repl_data_bytes # +wsrep_repl_keys # +wsrep_repl_keys_bytes # +wsrep_repl_other_bytes # +wsrep_replicated # +wsrep_replicated_bytes # wsrep_thread_count # SHOW GLOBAL STATUS LIKE 'wsrep_local_state_comment'; Variable_name Value @@ -124,7 +122,6 @@ wsrep_local_state_comment # # Should show nothing. SHOW STATUS LIKE 'x'; Variable_name Value -SET GLOBAL wsrep_provider=none; # # MDEV#6079: xtrabackup SST failing with maria-10.0-galera # @@ -136,13 +133,11 @@ wsrep_local_state_uuid # SHOW STATUS LIKE 'wsrep_last_committed'; Variable_name Value wsrep_last_committed # -SET GLOBAL wsrep_provider=none; # # MDEV#6206: wsrep_slave_threads subtracts from max_connections # call mtr.add_suppression("safe_mutex: Found wrong usage of mutex 'LOCK_wsrep_slave_threads' and 'LOCK_global_system_variables'"); -call mtr.add_suppression("WSREP: Failed to get provider options"); SELECT @@global.wsrep_provider; @@global.wsrep_provider libgalera_smm.so @@ -151,36 +146,6 @@ SELECT @@global.wsrep_slave_threads; 1 SELECT @@global.wsrep_cluster_address; @@global.wsrep_cluster_address -NULL -SHOW STATUS LIKE 'threads_connected'; -Variable_name Value -Threads_connected 1 -SHOW STATUS LIKE 'wsrep_thread_count'; -Variable_name Value -wsrep_thread_count 0 - -SELECT @@global.wsrep_provider; -@@global.wsrep_provider -libgalera_smm.so -SELECT @@global.wsrep_cluster_address; -@@global.wsrep_cluster_address -NULL -SHOW STATUS LIKE 'threads_connected'; -Variable_name Value -Threads_connected 1 -SHOW STATUS LIKE 'wsrep_thread_count'; -Variable_name Value -wsrep_thread_count 0 - -# Setting wsrep_cluster_address triggers the creation of -# applier/rollbacker threads. -SET GLOBAL wsrep_cluster_address= 'gcomm://'; -# Wait for applier threads to get created. -SELECT @@global.wsrep_provider; -@@global.wsrep_provider -libgalera_smm.so -SELECT @@global.wsrep_cluster_address; -@@global.wsrep_cluster_address gcomm:// SHOW STATUS LIKE 'threads_connected'; Variable_name Value @@ -192,13 +157,13 @@ wsrep_thread_count 2 SET @wsrep_slave_threads_saved= @@global.wsrep_slave_threads; SET GLOBAL wsrep_slave_threads= 10; # Wait for applier threads to get created. +SHOW STATUS LIKE 'wsrep_thread_count'; +Variable_name Value +wsrep_thread_count 11 SHOW STATUS LIKE 'threads_connected'; Variable_name Value Threads_connected 1 SET GLOBAL wsrep_slave_threads= @wsrep_slave_threads_saved; -SET GLOBAL wsrep_provider= none; -SET GLOBAL wsrep_cluster_address= ''; -SET GLOBAL wsrep_provider_options= ''; # # MDEV#6411: Setting set @@global.wsrep_sst_auth=NULL causes crash # diff --git a/mysql-test/suite/wsrep/t/mysql_tzinfo_to_sql_symlink.test b/mysql-test/suite/wsrep/t/mysql_tzinfo_to_sql_symlink.test index 100e09d3afb..87554635666 100644 --- a/mysql-test/suite/wsrep/t/mysql_tzinfo_to_sql_symlink.test +++ b/mysql-test/suite/wsrep/t/mysql_tzinfo_to_sql_symlink.test @@ -1,6 +1,7 @@ --source include/have_wsrep.inc --source include/have_symlink.inc --source include/not_windows.inc +--source include/have_innodb.inc --echo # --echo # MDEV-5226 mysql_tzinfo_to_sql errors with tzdata 2013f and above diff --git a/mysql-test/suite/wsrep/t/variables.test b/mysql-test/suite/wsrep/t/variables.test index 22f4c6cb940..050d40b47a0 100644 --- a/mysql-test/suite/wsrep/t/variables.test +++ b/mysql-test/suite/wsrep/t/variables.test @@ -1,20 +1,11 @@ --source include/have_wsrep.inc - -# Set galera's base_port so that test can run in parallel with other galera -# tests. ---disable_query_log -eval SET GLOBAL wsrep_provider_options='base_port=$GALERA_BASE_PORT'; ---enable_query_log +--source include/have_innodb.inc --echo --echo # MDEV#5534: mysql_tzinfo_to_sql generates wrong query --echo # --echo # Testing wsrep_replicate_myisam variable. ---disable_query_log -eval SET GLOBAL wsrep_provider= '$WSREP_PROVIDER'; ---enable_query_log - --error ER_INCORRECT_GLOBAL_LOCAL_VAR SELECT @@session.wsrep_replicate_myisam; SELECT @@global.wsrep_replicate_myisam; @@ -25,19 +16,12 @@ SET GLOBAL wsrep_replicate_myisam= ON; # Reset it back. SET GLOBAL wsrep_replicate_myisam= OFF; -SET GLOBAL wsrep_provider=none; --echo # --echo # MDEV#5790: SHOW GLOBAL STATUS LIKE does not show the correct list of --echo # variables when using "_" --echo # -CALL mtr.add_suppression("WSREP: Could not open saved state file for reading.*"); - ---disable_query_log -eval SET GLOBAL wsrep_provider= '$WSREP_PROVIDER'; ---enable_query_log - --replace_column 2 # SHOW GLOBAL STATUS LIKE 'wsrep%'; @@ -51,17 +35,10 @@ SHOW GLOBAL STATUS LIKE 'wsrep_local_state_comment'; --echo # Should show nothing. SHOW STATUS LIKE 'x'; -# Reset it back. -SET GLOBAL wsrep_provider=none; - --echo # --echo # MDEV#6079: xtrabackup SST failing with maria-10.0-galera --echo # ---disable_query_log -eval SET GLOBAL wsrep_provider= '$WSREP_PROVIDER'; ---enable_query_log - # The following 2 variables are used in innobackupex during xtrabackup-based # SST. --echo @@ -71,19 +48,11 @@ SHOW STATUS LIKE 'wsrep_local_state_uuid'; --replace_column 2 # SHOW STATUS LIKE 'wsrep_last_committed'; -# Reset it back. -SET GLOBAL wsrep_provider=none; - --echo --echo # --echo # MDEV#6206: wsrep_slave_threads subtracts from max_connections --echo # call mtr.add_suppression("safe_mutex: Found wrong usage of mutex 'LOCK_wsrep_slave_threads' and 'LOCK_global_system_variables'"); -call mtr.add_suppression("WSREP: Failed to get provider options"); - ---disable_query_log -eval SET GLOBAL wsrep_provider= '$WSREP_PROVIDER'; ---enable_query_log --replace_regex /.*libgalera_smm.*/libgalera_smm.so/ SELECT @@global.wsrep_provider; @@ -93,41 +62,15 @@ SHOW STATUS LIKE 'threads_connected'; SHOW STATUS LIKE 'wsrep_thread_count'; --echo ---disable_query_log -eval SET GLOBAL wsrep_provider= '$WSREP_PROVIDER'; ---enable_query_log - ---replace_regex /.*libgalera_smm.*/libgalera_smm.so/ -SELECT @@global.wsrep_provider; -SELECT @@global.wsrep_cluster_address; -SHOW STATUS LIKE 'threads_connected'; -SHOW STATUS LIKE 'wsrep_thread_count'; ---echo - ---echo # Setting wsrep_cluster_address triggers the creation of ---echo # applier/rollbacker threads. -SET GLOBAL wsrep_cluster_address= 'gcomm://'; ---echo # Wait for applier threads to get created. -sleep 3; - ---replace_regex /.*libgalera_smm.*/libgalera_smm.so/ -SELECT @@global.wsrep_provider; -SELECT @@global.wsrep_cluster_address; -SHOW STATUS LIKE 'threads_connected'; -SHOW STATUS LIKE 'wsrep_thread_count'; ---echo - SET @wsrep_slave_threads_saved= @@global.wsrep_slave_threads; SET GLOBAL wsrep_slave_threads= 10; --echo # Wait for applier threads to get created. sleep 5; +SHOW STATUS LIKE 'wsrep_thread_count'; SHOW STATUS LIKE 'threads_connected'; # reset (for mtr internal checks) SET GLOBAL wsrep_slave_threads= @wsrep_slave_threads_saved; -SET GLOBAL wsrep_provider= none; -SET GLOBAL wsrep_cluster_address= ''; -SET GLOBAL wsrep_provider_options= ''; --echo # --echo # MDEV#6411: Setting set @@global.wsrep_sst_auth=NULL causes crash diff --git a/scripts/wsrep_sst_rsync.sh b/scripts/wsrep_sst_rsync.sh index 9a880b0218f..0351d3fbafb 100644 --- a/scripts/wsrep_sst_rsync.sh +++ b/scripts/wsrep_sst_rsync.sh @@ -259,7 +259,7 @@ then RSYNC_CONF="$WSREP_SST_OPT_DATA/$MODULE.conf" - if [ -n "$MYSQL_TMP_DIR" ] ; then + if [ -n "${MYSQL_TMP_DIR:-}" ] ; then SILENT="log file = $MYSQL_TMP_DIR/rsynd.log" else SILENT="" diff --git a/sql/wsrep_check_opts.cc b/sql/wsrep_check_opts.cc index a4c12e7deb2..119813bfa04 100644 --- a/sql/wsrep_check_opts.cc +++ b/sql/wsrep_check_opts.cc @@ -37,64 +37,64 @@ int wsrep_check_opts() " innodb_autoinc_lock_mode = 2."); return 1; } + } - if (locked_in_memory) + if (locked_in_memory) + { + WSREP_ERROR("Memory locking is not supported (locked_in_memory=ON)"); + return 1; + } + + if (!strcasecmp(wsrep_sst_method, "mysqldump")) + { + if (!strcasecmp(my_bind_addr_str, "127.0.0.1") || + !strcasecmp(my_bind_addr_str, "localhost")) { - WSREP_ERROR("Memory locking is not supported (locked_in_memory=ON)"); + WSREP_ERROR("wsrep_sst_method is set to 'mysqldump' yet " + "mysqld bind_address is set to '%s', which makes it " + "impossible to receive state transfer from another " + "node, since mysqld won't accept such connections. " + "If you wish to use mysqldump state transfer method, " + "set bind_address to allow mysql client connections " + "from other cluster members (e.g. 0.0.0.0).", + my_bind_addr_str); return 1; } - - if (!strcasecmp(wsrep_sst_method, "mysqldump")) + } + else + { + // non-mysqldump SST requires wsrep_cluster_address on startup + if (!wsrep_cluster_address || !wsrep_cluster_address[0]) { - if (!strcasecmp(my_bind_addr_str, "127.0.0.1") || - !strcasecmp(my_bind_addr_str, "localhost")) - { - WSREP_ERROR("wsrep_sst_method is set to 'mysqldump' yet " - "mysqld bind_address is set to '%s', which makes it " - "impossible to receive state transfer from another " - "node, since mysqld won't accept such connections. " - "If you wish to use mysqldump state transfer method, " - "set bind_address to allow mysql client connections " - "from other cluster members (e.g. 0.0.0.0).", - my_bind_addr_str); - return 1; - } + WSREP_ERROR ("%s SST method requires wsrep_cluster_address to be " + "configured on startup.", wsrep_sst_method); + return 1; } - else + } + + if (strcasecmp(wsrep_sst_receive_address, "AUTO")) + { + if (!strncasecmp(wsrep_sst_receive_address, STRING_WITH_LEN("127.0.0.1")) || + !strncasecmp(wsrep_sst_receive_address, STRING_WITH_LEN("localhost"))) { - // non-mysqldump SST requires wsrep_cluster_address on startup - if (!wsrep_cluster_address || !wsrep_cluster_address[0]) - { - WSREP_ERROR ("%s SST method requires wsrep_cluster_address to be " - "configured on startup.", wsrep_sst_method); - return 1; - } + WSREP_WARN("wsrep_sst_receive_address is set to '%s' which " + "makes it impossible for another host to reach this " + "one. Please set it to the address which this node " + "can be connected at by other cluster members.", + wsrep_sst_receive_address); } + } - if (strcasecmp(wsrep_sst_receive_address, "AUTO")) + if (strcasecmp(wsrep_provider, "NONE")) + { + if (global_system_variables.binlog_format != BINLOG_FORMAT_ROW) { - if (!strncasecmp(wsrep_sst_receive_address, STRING_WITH_LEN("127.0.0.1")) || - !strncasecmp(wsrep_sst_receive_address, STRING_WITH_LEN("localhost"))) - { - WSREP_WARN("wsrep_sst_receive_address is set to '%s' which " - "makes it impossible for another host to reach this " - "one. Please set it to the address which this node " - "can be connected at by other cluster members.", - wsrep_sst_receive_address); - } - } + WSREP_ERROR("Only binlog_format = 'ROW' is currently supported. " + "Configured value: '%s'. Please adjust your " + "configuration.", + binlog_format_names[global_system_variables.binlog_format]); - if (strcasecmp(wsrep_provider, "NONE")) - { - if (global_system_variables.binlog_format != BINLOG_FORMAT_ROW) - { - WSREP_ERROR("Only binlog_format = 'ROW' is currently supported. " - "Configured value: '%s'. Please adjust your " - "configuration.", - binlog_format_names[global_system_variables.binlog_format]); - - return 1; - } + return 1; } } return 0; From 61d8b4a29bd6295b9db153a6ebb451346cd5bc64 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Sat, 4 Oct 2014 13:59:07 -0400 Subject: [PATCH 085/153] MDEV-6833: SIGSEGV on shutdown with non-default wsrep_slave_threads thd->variables' table_plugin & tmp_table_plugin should be set to NULL for wsrep system threads. Also made a minor change to skip checking of wsrep options if wsrep_on is not set. --- sql/mysqld.cc | 6 ++++-- sql/sql_plugin.cc | 7 +++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index e92234ddd09..899140f7d71 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4981,8 +4981,10 @@ a file name for --log-bin-index option", opt_binlog_index_name); } plugins_are_initialized= TRUE; /* Don't separate from init function */ - if (wsrep_check_opts()) - unireg_abort(1); +#ifdef WITH_WSREP + if (WSREP_ON && wsrep_check_opts()) + global_system_variables.wsrep_on= 0; +#endif /* we do want to exit if there are any other unknown options */ if (remaining_argc > 1) diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index ea9748c8cb2..c50ddbb5a81 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -3074,12 +3074,12 @@ void plugin_thdvar_init(THD *thd) plugin_ref old_table_plugin= thd->variables.table_plugin; plugin_ref old_tmp_table_plugin= thd->variables.tmp_table_plugin; DBUG_ENTER("plugin_thdvar_init"); - + // This function may be called many times per THD (e.g. on COM_CHANGE_USER) thd->variables.table_plugin= NULL; thd->variables.tmp_table_plugin= NULL; cleanup_variables(thd, &thd->variables); - + thd->variables= global_system_variables; /* we are going to allocate these lazily */ @@ -3098,6 +3098,9 @@ void plugin_thdvar_init(THD *thd) intern_plugin_unlock(NULL, old_table_plugin); intern_plugin_unlock(NULL, old_tmp_table_plugin); mysql_mutex_unlock(&LOCK_plugin); + } else { + thd->variables.table_plugin= NULL; + thd->variables.tmp_table_plugin= NULL; } DBUG_VOID_RETURN; From f7c57b4a3618c99352ade432396390a70b5257fa Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Mon, 6 Oct 2014 15:26:09 -0400 Subject: [PATCH 086/153] MDEV-6667: Merged fix from maria-10.0-galera. --- sql/mysqld.cc | 10 +++++++--- sql/wsrep_mysqld.cc | 41 ++++++++--------------------------------- sql/wsrep_mysqld.h | 7 +------ 3 files changed, 16 insertions(+), 42 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 899140f7d71..d252c33ac53 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5361,9 +5361,6 @@ int mysqld_main(int argc, char **argv) } #endif - if (WSREP_ON) - wsrep_filter_new_cluster (&argc, argv); - orig_argc= argc; orig_argv= argv; my_getopt_use_args_separator= TRUE; @@ -7341,6 +7338,13 @@ struct my_option my_long_options[]= {"table_cache", 0, "Deprecated; use --table-open-cache instead.", &tc_size, &tc_size, 0, GET_ULONG, REQUIRED_ARG, TABLE_OPEN_CACHE_DEFAULT, 1, 512*1024L, 0, 1, 0}, +#ifdef WITH_WSREP + {"wsrep-new-cluster", 0, "Bootstrap a cluster. It works by overriding the " + "current value of wsrep_cluster_address. It is recommended not to add this " + "option to the config file as this will trigger bootstrap on every server " + "start.", &wsrep_new_cluster, &wsrep_new_cluster, 0, GET_BOOL, NO_ARG, + 0, 0, 0, 0, 0, 0}, +#endif /* The following options exist in 5.6 but not in 10.0 */ MYSQL_TO_BE_IMPLEMENTED_OPTION("default-tmp-storage-engine"), diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 2897bb3fb69..938ec243f61 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -82,6 +82,7 @@ my_bool wsrep_restart_slave_activated = 0; // node has dropped, and slave // restart will be needed my_bool wsrep_slave_UK_checks = 0; // slave thread does UK checks my_bool wsrep_slave_FK_checks = 0; // slave thread does FK checks +bool wsrep_new_cluster = false; // Bootstrap the cluster ? /* * End configuration options */ @@ -886,37 +887,6 @@ void wsrep_stop_replication(THD *thd) return; } -/* This one is set to true when --wsrep-new-cluster is found in the command - * line arguments */ -static my_bool wsrep_new_cluster= FALSE; -#define WSREP_NEW_CLUSTER "--wsrep-new-cluster" -/* Finds and hides --wsrep-new-cluster from the arguments list - * by moving it to the end of the list and decrementing argument count */ -void wsrep_filter_new_cluster (int* argc, char* argv[]) -{ - int i; - for (i= *argc - 1; i > 0; i--) - { - /* make a copy of the argument to convert possible underscores to hyphens. - * the copy need not to be longer than WSREP_NEW_CLUSTER option */ - char arg[sizeof(WSREP_NEW_CLUSTER) + 1]= { 0, }; - strncpy(arg, argv[i], sizeof(arg) - 1); - char* underscore(arg); - while (NULL != (underscore= strchr(underscore, '_'))) *underscore= '-'; - - if (!strcmp(arg, WSREP_NEW_CLUSTER)) - { - wsrep_new_cluster= TRUE; - *argc -= 1; - /* preserve the order of remaining arguments AND - * preserve the original argument pointers - just in case */ - char* wnc= argv[i]; - memmove(&argv[i], &argv[i + 1], (*argc - i)*sizeof(argv[i])); - argv[*argc]= wnc; /* this will be invisible to the rest of the program */ - } - } -} - bool wsrep_start_replication() { wsrep_status_t rcode; @@ -939,11 +909,16 @@ bool wsrep_start_replication() return true; } - bool const bootstrap(TRUE == wsrep_new_cluster); - wsrep_new_cluster= FALSE; + bool const bootstrap= wsrep_new_cluster; WSREP_INFO("Start replication"); + if (wsrep_new_cluster) + { + WSREP_INFO("'wsrep-new-cluster' option used, bootstrapping the cluster"); + wsrep_new_cluster= false; + } + if ((rcode = wsrep->connect(wsrep, wsrep_cluster_name, wsrep_cluster_address, diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index bc78d2beecf..67f26548043 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -87,6 +87,7 @@ extern my_bool wsrep_restart_slave_activated; extern my_bool wsrep_slave_FK_checks; extern my_bool wsrep_slave_UK_checks; extern ulong wsrep_running_threads; +extern bool wsrep_new_cluster; enum enum_wsrep_OSU_method { WSREP_OSU_TOI, WSREP_OSU_RSU }; enum enum_wsrep_sync_wait { @@ -112,11 +113,6 @@ extern const char* wsrep_provider_version; extern const char* wsrep_provider_vendor; int wsrep_show_status(THD *thd, SHOW_VAR *var, char *buff); - -/* Filters out --wsrep-new-cluster oprtion from argv[] - * should be called in the very beginning of main() */ -void wsrep_filter_new_cluster (int* argc, char* argv[]); - int wsrep_init(); void wsrep_deinit(bool free_options); void wsrep_recover(); @@ -328,7 +324,6 @@ int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len); #define wsrep_stop_replication(X) do { } while(0) #define wsrep_inited (0) #define wsrep_deinit(X) do { } while(0) -#define wsrep_filter_new_cluster(X,Y) do { } while(0) #define wsrep_recover() do { } while(0) #define wsrep_slave_threads (1) From cc8aed3eb7a671d353c453a255b53e8d91d7fa73 Mon Sep 17 00:00:00 2001 From: Monty Date: Tue, 7 Oct 2014 11:37:36 +0300 Subject: [PATCH 087/153] MDEV 4427: query timeouts Added MAX_STATEMENT_TIME user variable to automaticly kill queries after a given time limit has expired. - Added timer functions based on pthread_cond_timedwait - Added kill_handlerton() to signal storage engines about kill/timeout - Added support for GRANT ... MAX_STATEMENT_TIME=# - Copy max_statement_time to current user, if stored in mysql.user - Added status variable max_statement_time_exceeded - Added KILL_TIMEOUT - Removed digest hash from performance schema tests as they change all the time. - Updated test results that changed because of the new user variables or new fields in mysql.user This functionallity is inspired by work done by Davi Arnaut at twitter. Test case is copied from Davi's work. Documentation can be found at https://kb.askmonty.org/en/how-to-limittimeout-queries/ mysql-test/r/mysqld--help.result: Updated for new help message mysql-test/suite/perfschema/r/all_instances.result: Added new mutex mysql-test/suite/sys_vars/r/max_statement_time_basic.result: Added testing of max_statement_time mysql-test/suite/sys_vars/t/max_statement_time_basic.test: Added testing of max_statement_time mysql-test/t/max_statement_time.test: Added testing of max_statement_time mysys/CMakeLists.txt: Added thr_timer mysys/my_init.c: mysys/mysys_priv.h: Added new mutex and condition variables Added new mutex and condition variables mysys/thr_timer.c: Added timer functions based on pthread_cond_timedwait() This can be compiled with HAVE_TIMER_CREATE to benchmark agains timer_create()/timer_settime() sql/lex.h: Added MAX_STATEMENT_TIME sql/log_event.cc: Safety fix (timeout should be threated as an interrupted query) sql/mysqld.cc: Added support for timers Added status variable max_statement_time_exceeded sql/share/errmsg-utf8.txt: Added ER_QUERY_TIMEOUT sql/signal_handler.cc: Added support for KILL_TIMEOUT sql/sql_acl.cc: Added support for GRANT ... MAX_STATEMENT_TIME=# Copy max_statement_time to current user sql/sql_class.cc: Added timer functionality to THD. Added thd_kill_timeout() sql/sql_class.h: Added timer functionality to THD. Added KILL_TIMEOUT Added max_statement_time variable in similar manner as long_query_time was done. sql/sql_connect.cc: Added handling of max_statement_time_exceeded sql/sql_parse.cc: Added starting and stopping timers for queries. sql/sql_show.cc: Added max_statement_time_exceeded for user/connects status in MariaDB 10.0 sql/sql_yacc.yy: Added support for GRANT ... MAX_STATEMENT_TIME=# syntax, to be enabled in 10.0 sql/structs.h: Added max_statement_time user resource sql/sys_vars.cc: Added max_statement_time variables mysql-test/suite/roles/create_and_drop_role_invalid_user_table.test Removed test as we require all fields in mysql.user table. scripts/mysql_system_tables.sql scripts/mysql_system_tables_data.sql scripts/mysql_system_tables_fix.sql Updated mysql.user with new max_statement_time field --- .gitignore | 1 + include/thr_timer.h | 45 ++ mysql-test/r/grant.result | 9 +- mysql-test/r/max_statement_time.result | 147 +++++ mysql-test/r/mysqld--help.result | 6 + mysql-test/r/ps.result | 6 +- mysql-test/r/status_user.result | 2 + mysql-test/r/system_mysql_db.result | 1 + mysql-test/r/system_mysql_db_fix40123.result | 1 + mysql-test/r/system_mysql_db_fix50030.result | 1 + mysql-test/r/system_mysql_db_fix50117.result | 1 + .../suite/funcs_1/r/is_columns_is.result | 4 + .../suite/funcs_1/r/is_columns_mysql.result | 2 + .../suite/funcs_1/r/is_user_privileges.result | 33 + .../perfschema/r/digest_table_full.result | 8 +- .../suite/perfschema/r/rpl_gtid_func.result | 12 +- .../r/start_server_no_digests.result | 4 +- .../perfschema/r/statement_digest.result | 78 +-- .../r/statement_digest_consumers.result | 82 +-- .../r/statement_digest_long_query.result | 8 +- .../suite/perfschema/t/digest_table_full.test | 2 +- .../suite/perfschema/t/rpl_gtid_func.test | 4 +- .../perfschema/t/start_server_no_digests.test | 2 +- .../suite/perfschema/t/statement_digest.test | 2 +- .../t/statement_digest_consumers.test | 4 +- .../t/statement_digest_long_query.test | 2 +- ...te_and_drop_role_invalid_user_table.result | 25 - ...eate_and_drop_role_invalid_user_table.test | 38 -- .../suite/roles/set_role-recursive.result | 8 +- mysql-test/suite/roles/set_role-simple.result | 4 +- .../r/max_statement_time_basic.result | 172 +++++ .../sys_vars/t/max_statement_time_basic.test | 217 +++++++ mysql-test/t/grant.test | 4 +- mysql-test/t/max_statement_time.test | 189 ++++++ mysys/CMakeLists.txt | 8 +- mysys/my_init.c | 18 +- mysys/mysys_priv.h | 6 +- mysys/thr_timer.c | 589 ++++++++++++++++++ scripts/mysql_system_tables.sql | 4 +- scripts/mysql_system_tables_data.sql | 8 +- scripts/mysql_system_tables_fix.sql | 1 + sql/lex.h | 1 + sql/log_event.cc | 1 + sql/mysqld.cc | 26 +- sql/share/errmsg-utf8.txt | 2 + sql/signal_handler.cc | 4 + sql/sql_acl.cc | 59 +- sql/sql_class.cc | 32 + sql/sql_class.h | 48 +- sql/sql_connect.cc | 7 +- sql/sql_parse.cc | 4 + sql/sql_show.cc | 5 + sql/sql_yacc.yy | 8 + sql/structs.h | 9 +- sql/sys_vars.cc | 23 + sql/wsrep_mysqld.cc | 41 +- sql/wsrep_mysqld.h | 7 +- 57 files changed, 1780 insertions(+), 255 deletions(-) create mode 100644 include/thr_timer.h create mode 100644 mysql-test/r/max_statement_time.result delete mode 100644 mysql-test/suite/roles/create_and_drop_role_invalid_user_table.result delete mode 100644 mysql-test/suite/roles/create_and_drop_role_invalid_user_table.test create mode 100644 mysql-test/suite/sys_vars/r/max_statement_time_basic.result create mode 100644 mysql-test/suite/sys_vars/t/max_statement_time_basic.test create mode 100644 mysql-test/t/max_statement_time.test create mode 100644 mysys/thr_timer.c diff --git a/.gitignore b/.gitignore index 2ed53e5365d..2c7e5c890ae 100644 --- a/.gitignore +++ b/.gitignore @@ -75,6 +75,7 @@ mysql-test/mtr mysql-test/mysql-test-run mysql-test/var/ mysys/thr_lock +mysys/thr_timer packaging/rpm-oel/mysql.spec packaging/rpm-uln/mysql.10.0.11.spec packaging/solaris/postinstall-solaris diff --git a/include/thr_timer.h b/include/thr_timer.h new file mode 100644 index 00000000000..892bbc1a01f --- /dev/null +++ b/include/thr_timer.h @@ -0,0 +1,45 @@ +/* Copyright (c) 2012 Monty Program Ab + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 or later of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/* Prototypes when using thr_timer functions */ + +#ifndef _thr_timer_h +#define _thr_timer_h +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct st_timer { + struct timespec expire_time; + my_bool expired; + uint index_in_queue; + void (*func)(void*); + void *func_arg; +} thr_timer_t; + +/* Main functions for library */ +my_bool init_thr_timer(uint init_size_for_timer_queue); +void end_thr_timer(); + +/* Functions for handling one timer */ +void thr_timer_init(thr_timer_t *timer_data, void(*function)(void*), + void *arg); +my_bool thr_timer_settime(thr_timer_t *timer_data, ulonglong microseconds); +void thr_timer_end(thr_timer_t *timer_data); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _thr_timer_h */ diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index 25fe976b7ed..6c769e60780 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -58,6 +58,7 @@ authentication_string password_expired N is_role N default_role +max_statement_time 0.000000 show grants for mysqltest_1@localhost; Grants for mysqltest_1@localhost GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' REQUIRE CIPHER 'EDH-RSA-DES-CBC3-SHA' @@ -85,7 +86,7 @@ delete from mysql.user where user='mysqltest_1'; flush privileges; delete from mysql.user where user='mysqltest_1'; flush privileges; -grant usage on *.* to mysqltest_1@localhost with max_queries_per_hour 10; +grant usage on *.* to mysqltest_1@localhost with max_queries_per_hour 10 max_statement_time 60; select * from mysql.user where user="mysqltest_1"; Host localhost User mysqltest_1 @@ -132,10 +133,11 @@ authentication_string password_expired N is_role N default_role +max_statement_time 60.000000 show grants for mysqltest_1@localhost; Grants for mysqltest_1@localhost -GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' WITH MAX_QUERIES_PER_HOUR 10 -grant usage on *.* to mysqltest_1@localhost with max_updates_per_hour 20 max_connections_per_hour 30; +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' WITH MAX_QUERIES_PER_HOUR 10 MAX_STATEMENT_TIME 60.000000 +grant usage on *.* to mysqltest_1@localhost with max_updates_per_hour 20 max_connections_per_hour 30 max_statement_time 0; select * from mysql.user where user="mysqltest_1"; Host localhost User mysqltest_1 @@ -182,6 +184,7 @@ authentication_string password_expired N is_role N default_role +max_statement_time 0.000000 show grants for mysqltest_1@localhost; Grants for mysqltest_1@localhost GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' WITH MAX_QUERIES_PER_HOUR 10 MAX_UPDATES_PER_HOUR 20 MAX_CONNECTIONS_PER_HOUR 30 diff --git a/mysql-test/r/max_statement_time.result b/mysql-test/r/max_statement_time.result new file mode 100644 index 00000000000..2681575daea --- /dev/null +++ b/mysql-test/r/max_statement_time.result @@ -0,0 +1,147 @@ + +# Test the MAX_STATEMENT_TIME option. + +SET @@MAX_STATEMENT_TIME=2; +select @@max_statement_time; +@@max_statement_time +2.000000 +SELECT SLEEP(1); +SLEEP(1) +0 +SELECT SLEEP(3); +SLEEP(3) +1 +SET @@MAX_STATEMENT_TIME=0; +SELECT SLEEP(1); +SLEEP(1) +0 +SHOW STATUS LIKE "max_statement_time_exceeded"; +Variable_name Value +Max_statement_time_exceeded 1 +CREATE TABLE t1 (a INT, b VARCHAR(300)) engine=myisam; +INSERT INTO t1 VALUES (1, 'string'); +SELECT 0; +0 +0 + +# Test the MAX_STATEMENT_TIME option with SF (should have no effect). + +CREATE PROCEDURE p1() +BEGIN +declare tmp int; +SET @@MAX_STATEMENT_TIME=0.0001; +SELECT COUNT(*) INTO tmp FROM t1 WHERE b LIKE '%z%'; +SET @@MAX_STATEMENT_TIME=0; +END| +CREATE PROCEDURE p2() +BEGIN +SET @@MAX_STATEMENT_TIME=5; +END| +SELECT @@MAX_STATEMENT_TIME; +@@MAX_STATEMENT_TIME +0.000000 +CALL p1(); +CALL p2(); +SELECT @@MAX_STATEMENT_TIME; +@@MAX_STATEMENT_TIME +5.000000 +SET @@MAX_STATEMENT_TIME=0; +DROP PROCEDURE p1; +DROP PROCEDURE p2; +DROP TABLE t1; + +# MAX_STATEMENT_TIME account resource + +GRANT USAGE ON *.* TO user1@localhost WITH MAX_STATEMENT_TIME 1.005; +# con1 +SELECT @@max_statement_time; +@@max_statement_time +1.005000 +# restart and reconnect +set @global.userstat=1; +SELECT @@global.max_statement_time,@@session.max_statement_time; +@@global.max_statement_time @@session.max_statement_time +0.000000 1.005000 +select sleep(100); +sleep(100) +1 +SHOW STATUS LIKE "max_statement_time_exceeded"; +Variable_name Value +Max_statement_time_exceeded 1 +show grants for user1@localhost; +Grants for user1@localhost +GRANT USAGE ON *.* TO 'user1'@'localhost' WITH MAX_STATEMENT_TIME 1.005000 +set @global.userstat=0; +DROP USER user1@localhost; + +# MAX_STATEMENT_TIME status variables. + +flush status; +SET @@max_statement_time=0; +SELECT CONVERT(VARIABLE_VALUE, UNSIGNED) INTO @time_exceeded +FROM INFORMATION_SCHEMA.GLOBAL_STATUS +WHERE VARIABLE_NAME = 'max_statement_time_exceeded'; +SET @@max_statement_time=0.5; +SELECT SLEEP(2); +SLEEP(2) +1 +SHOW STATUS LIKE '%timeout%'; +Variable_name Value +Ssl_default_timeout 0 +Ssl_session_cache_timeouts 0 +SET @@max_statement_time=0; +# Ensure that the counters for: +# - statements that exceeded their maximum execution time +# are incremented. +SELECT 1 AS STATUS FROM INFORMATION_SCHEMA.GLOBAL_STATUS +WHERE VARIABLE_NAME = 'max_statement_time_exceeded' + AND CONVERT(VARIABLE_VALUE, UNSIGNED) > @time_exceeded; +STATUS +1 + +# Check that the appropriate error status is set. + +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); +START TRANSACTION; +SELECT * FROM t1 FOR UPDATE; +a +1 +SET @@SESSION.max_statement_time = 0.5; +UPDATE t1 SET a = 2; +ERROR 70100: Query execution was interrupted (max_statement_time exceeded) +SHOW WARNINGS; +Level Code Message +Error 1967 Query execution was interrupted (max_statement_time exceeded) +ROLLBACK; +DROP TABLE t1; + +# Test interaction with lock waits. + +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); +SET @@SESSION.max_statement_time= 0.5; +LOCK TABLES t1 WRITE; +SELECT @@SESSION.max_statement_time; +@@SESSION.max_statement_time +0.500000 +LOCK TABLES t1 READ; +ERROR 70100: Query execution was interrupted (max_statement_time exceeded) +UNLOCK TABLES; +BEGIN; +SELECT * FROM t1; +a +1 +ALTER TABLE t1 ADD COLUMN b INT; +ERROR 70100: Query execution was interrupted (max_statement_time exceeded) +ROLLBACK; +SELECT GET_LOCK('lock', 1); +GET_LOCK('lock', 1) +1 +SELECT GET_LOCK('lock', 1); +GET_LOCK('lock', 1) +NULL +SELECT RELEASE_LOCK('lock'); +RELEASE_LOCK('lock') +1 +DROP TABLE t1; diff --git a/mysql-test/r/mysqld--help.result b/mysql-test/r/mysqld--help.result index 5a2142c402c..80ba45be72a 100644 --- a/mysql-test/r/mysqld--help.result +++ b/mysql-test/r/mysqld--help.result @@ -422,6 +422,11 @@ The following options may be given as the first argument: value are used; the rest are ignored) --max-sp-recursion-depth[=#] Maximum stored procedure recursion depth + --max-statement-time=# + A SELECT query that have taken more than + max_statement_time seconds will be aborted. The argument + will be treated as a decimal value with microsecond + precision. A value of 0 (default) means no timeout --max-tmp-tables=# Maximum number of temporary tables a client can keep open at a time --max-user-connections=# @@ -1196,6 +1201,7 @@ max-relay-log-size 1073741824 max-seeks-for-key 18446744073709551615 max-sort-length 1024 max-sp-recursion-depth 0 +max-statement-time 0 max-tmp-tables 32 max-user-connections 0 max-write-lock-count 18446744073709551615 diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 7db51eadbe6..e30fa9a1966 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -1202,13 +1202,13 @@ SET @aux= "SELECT COUNT(*) prepare my_stmt from @aux; execute my_stmt; COUNT(*) -45 +46 execute my_stmt; COUNT(*) -45 +46 execute my_stmt; COUNT(*) -45 +46 deallocate prepare my_stmt; drop procedure if exists p1| drop table if exists t1| diff --git a/mysql-test/r/status_user.result b/mysql-test/r/status_user.result index 829c8abb634..766a00f6f78 100644 --- a/mysql-test/r/status_user.result +++ b/mysql-test/r/status_user.result @@ -25,6 +25,7 @@ DENIED_CONNECTIONS bigint(21) NO 0 LOST_CONNECTIONS bigint(21) NO 0 ACCESS_DENIED bigint(21) NO 0 EMPTY_QUERIES bigint(21) NO 0 +MAX_STATEMENT_TIME_EXCEEDED bigint(21) NO 0 show columns from information_schema.user_statistics; Field Type Null Key Default Extra USER varchar(128) NO @@ -50,6 +51,7 @@ DENIED_CONNECTIONS bigint(21) NO 0 LOST_CONNECTIONS bigint(21) NO 0 ACCESS_DENIED bigint(21) NO 0 EMPTY_QUERIES bigint(21) NO 0 +MAX_STATEMENT_TIME_EXCEEDED bigint(21) NO 0 show columns from information_schema.index_statistics; Field Type Null Key Default Extra TABLE_SCHEMA varchar(192) NO diff --git a/mysql-test/r/system_mysql_db.result b/mysql-test/r/system_mysql_db.result index 0204354d9e3..f195b0a607e 100644 --- a/mysql-test/r/system_mysql_db.result +++ b/mysql-test/r/system_mysql_db.result @@ -131,6 +131,7 @@ user CREATE TABLE `user` ( `password_expired` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `is_role` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `default_role` char(80) COLLATE utf8_bin NOT NULL DEFAULT '', + `max_statement_time` decimal(12,6) NOT NULL DEFAULT '0.000000', PRIMARY KEY (`Host`,`User`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Users and global privileges' show create table func; diff --git a/mysql-test/r/system_mysql_db_fix40123.result b/mysql-test/r/system_mysql_db_fix40123.result index 0204354d9e3..f195b0a607e 100644 --- a/mysql-test/r/system_mysql_db_fix40123.result +++ b/mysql-test/r/system_mysql_db_fix40123.result @@ -131,6 +131,7 @@ user CREATE TABLE `user` ( `password_expired` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `is_role` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `default_role` char(80) COLLATE utf8_bin NOT NULL DEFAULT '', + `max_statement_time` decimal(12,6) NOT NULL DEFAULT '0.000000', PRIMARY KEY (`Host`,`User`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Users and global privileges' show create table func; diff --git a/mysql-test/r/system_mysql_db_fix50030.result b/mysql-test/r/system_mysql_db_fix50030.result index 0204354d9e3..f195b0a607e 100644 --- a/mysql-test/r/system_mysql_db_fix50030.result +++ b/mysql-test/r/system_mysql_db_fix50030.result @@ -131,6 +131,7 @@ user CREATE TABLE `user` ( `password_expired` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `is_role` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `default_role` char(80) COLLATE utf8_bin NOT NULL DEFAULT '', + `max_statement_time` decimal(12,6) NOT NULL DEFAULT '0.000000', PRIMARY KEY (`Host`,`User`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Users and global privileges' show create table func; diff --git a/mysql-test/r/system_mysql_db_fix50117.result b/mysql-test/r/system_mysql_db_fix50117.result index 0204354d9e3..f195b0a607e 100644 --- a/mysql-test/r/system_mysql_db_fix50117.result +++ b/mysql-test/r/system_mysql_db_fix50117.result @@ -131,6 +131,7 @@ user CREATE TABLE `user` ( `password_expired` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `is_role` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `default_role` char(80) COLLATE utf8_bin NOT NULL DEFAULT '', + `max_statement_time` decimal(12,6) NOT NULL DEFAULT '0.000000', PRIMARY KEY (`Host`,`User`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Users and global privileges' show create table func; diff --git a/mysql-test/suite/funcs_1/r/is_columns_is.result b/mysql-test/suite/funcs_1/r/is_columns_is.result index 8f2f81a4616..c73eaa874c7 100644 --- a/mysql-test/suite/funcs_1/r/is_columns_is.result +++ b/mysql-test/suite/funcs_1/r/is_columns_is.result @@ -36,6 +36,7 @@ def information_schema CLIENT_STATISTICS CPU_TIME 6 0 NO double NULL NULL 21 NUL def information_schema CLIENT_STATISTICS DENIED_CONNECTIONS 20 0 NO bigint NULL NULL 19 0 NULL NULL NULL bigint(21) select def information_schema CLIENT_STATISTICS EMPTY_QUERIES 23 0 NO bigint NULL NULL 19 0 NULL NULL NULL bigint(21) select def information_schema CLIENT_STATISTICS LOST_CONNECTIONS 21 0 NO bigint NULL NULL 19 0 NULL NULL NULL bigint(21) select +def information_schema CLIENT_STATISTICS MAX_STATEMENT_TIME_EXCEEDED 24 0 NO bigint NULL NULL 19 0 NULL NULL NULL bigint(21) select def information_schema CLIENT_STATISTICS OTHER_COMMANDS 17 0 NO bigint NULL NULL 19 0 NULL NULL NULL bigint(21) select def information_schema CLIENT_STATISTICS ROLLBACK_TRANSACTIONS 19 0 NO bigint NULL NULL 19 0 NULL NULL NULL bigint(21) select def information_schema CLIENT_STATISTICS ROWS_DELETED 12 0 NO bigint NULL NULL 19 0 NULL NULL NULL bigint(21) select @@ -408,6 +409,7 @@ def information_schema USER_STATISTICS CPU_TIME 6 0 NO double NULL NULL 21 NULL def information_schema USER_STATISTICS DENIED_CONNECTIONS 20 0 NO bigint NULL NULL 19 0 NULL NULL NULL bigint(21) select def information_schema USER_STATISTICS EMPTY_QUERIES 23 0 NO bigint NULL NULL 19 0 NULL NULL NULL bigint(21) select def information_schema USER_STATISTICS LOST_CONNECTIONS 21 0 NO bigint NULL NULL 19 0 NULL NULL NULL bigint(21) select +def information_schema USER_STATISTICS MAX_STATEMENT_TIME_EXCEEDED 24 0 NO bigint NULL NULL 19 0 NULL NULL NULL bigint(21) select def information_schema USER_STATISTICS OTHER_COMMANDS 17 0 NO bigint NULL NULL 19 0 NULL NULL NULL bigint(21) select def information_schema USER_STATISTICS ROLLBACK_TRANSACTIONS 19 0 NO bigint NULL NULL 19 0 NULL NULL NULL bigint(21) select def information_schema USER_STATISTICS ROWS_DELETED 12 0 NO bigint NULL NULL 19 0 NULL NULL NULL bigint(21) select @@ -533,6 +535,7 @@ NULL information_schema CLIENT_STATISTICS DENIED_CONNECTIONS bigint NULL NULL NU NULL information_schema CLIENT_STATISTICS LOST_CONNECTIONS bigint NULL NULL NULL NULL bigint(21) NULL information_schema CLIENT_STATISTICS ACCESS_DENIED bigint NULL NULL NULL NULL bigint(21) NULL information_schema CLIENT_STATISTICS EMPTY_QUERIES bigint NULL NULL NULL NULL bigint(21) +NULL information_schema CLIENT_STATISTICS MAX_STATEMENT_TIME_EXCEEDED bigint NULL NULL NULL NULL bigint(21) 3.0000 information_schema COLLATIONS COLLATION_NAME varchar 32 96 utf8 utf8_general_ci varchar(32) 3.0000 information_schema COLLATIONS CHARACTER_SET_NAME varchar 32 96 utf8 utf8_general_ci varchar(32) NULL information_schema COLLATIONS ID bigint NULL NULL NULL NULL bigint(11) @@ -906,6 +909,7 @@ NULL information_schema USER_STATISTICS DENIED_CONNECTIONS bigint NULL NULL NULL NULL information_schema USER_STATISTICS LOST_CONNECTIONS bigint NULL NULL NULL NULL bigint(21) NULL information_schema USER_STATISTICS ACCESS_DENIED bigint NULL NULL NULL NULL bigint(21) NULL information_schema USER_STATISTICS EMPTY_QUERIES bigint NULL NULL NULL NULL bigint(21) +NULL information_schema USER_STATISTICS MAX_STATEMENT_TIME_EXCEEDED bigint NULL NULL NULL NULL bigint(21) 3.0000 information_schema VIEWS TABLE_CATALOG varchar 512 1536 utf8 utf8_general_ci varchar(512) 3.0000 information_schema VIEWS TABLE_SCHEMA varchar 64 192 utf8 utf8_general_ci varchar(64) 3.0000 information_schema VIEWS TABLE_NAME varchar 64 192 utf8 utf8_general_ci varchar(64) diff --git a/mysql-test/suite/funcs_1/r/is_columns_mysql.result b/mysql-test/suite/funcs_1/r/is_columns_mysql.result index d05c120bfa8..09adebfab1c 100644 --- a/mysql-test/suite/funcs_1/r/is_columns_mysql.result +++ b/mysql-test/suite/funcs_1/r/is_columns_mysql.result @@ -227,6 +227,7 @@ def mysql user is_role 44 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum def mysql user Lock_tables_priv 21 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references def mysql user max_connections 39 0 NO int NULL NULL 10 0 NULL NULL NULL int(11) unsigned select,insert,update,references def mysql user max_questions 37 0 NO int NULL NULL 10 0 NULL NULL NULL int(11) unsigned select,insert,update,references +def mysql user max_statement_time 46 0.000000 NO decimal NULL NULL 12 6 NULL NULL NULL decimal(12,6) select,insert,update,references def mysql user max_updates 38 0 NO int NULL NULL 10 0 NULL NULL NULL int(11) unsigned select,insert,update,references def mysql user max_user_connections 40 0 NO int NULL NULL 10 0 NULL NULL NULL int(11) select,insert,update,references def mysql user Password 3 NO char 41 41 NULL NULL NULL latin1 latin1_bin char(41) select,insert,update,references @@ -568,3 +569,4 @@ NULL mysql user max_user_connections int NULL NULL NULL NULL int(11) 3.0000 mysql user password_expired enum 1 3 utf8 utf8_general_ci enum('N','Y') 3.0000 mysql user is_role enum 1 3 utf8 utf8_general_ci enum('N','Y') 3.0000 mysql user default_role char 80 240 utf8 utf8_bin char(80) +NULL mysql user max_statement_time decimal NULL NULL NULL NULL decimal(12,6) diff --git a/mysql-test/suite/funcs_1/r/is_user_privileges.result b/mysql-test/suite/funcs_1/r/is_user_privileges.result index 5296a37c98d..dfbe50ad862 100644 --- a/mysql-test/suite/funcs_1/r/is_user_privileges.result +++ b/mysql-test/suite/funcs_1/r/is_user_privileges.result @@ -132,6 +132,7 @@ authentication_string password_expired N is_role N default_role +max_statement_time 0.000000 Host localhost User testuser2 Password @@ -177,6 +178,7 @@ authentication_string password_expired N is_role N default_role +max_statement_time 0.000000 Host localhost User testuser3 Password @@ -222,6 +224,7 @@ authentication_string password_expired N is_role N default_role +max_statement_time 0.000000 # # Add GRANT OPTION db_datadict.* to testuser1; GRANT UPDATE ON db_datadict.* TO 'testuser1'@'localhost' WITH GRANT OPTION; @@ -291,6 +294,7 @@ authentication_string password_expired N is_role N default_role +max_statement_time 0.000000 Host localhost User testuser2 Password @@ -336,6 +340,7 @@ authentication_string password_expired N is_role N default_role +max_statement_time 0.000000 Host localhost User testuser3 Password @@ -381,6 +386,7 @@ authentication_string password_expired N is_role N default_role +max_statement_time 0.000000 # Establish connection testuser1 (user=testuser1) SELECT * FROM information_schema.user_privileges WHERE grantee LIKE '''testuser%''' @@ -436,6 +442,7 @@ authentication_string password_expired N is_role N default_role +max_statement_time 0.000000 Host localhost User testuser2 Password @@ -481,6 +488,7 @@ authentication_string password_expired N is_role N default_role +max_statement_time 0.000000 Host localhost User testuser3 Password @@ -526,6 +534,7 @@ authentication_string password_expired N is_role N default_role +max_statement_time 0.000000 SHOW GRANTS; Grants for testuser1@localhost GRANT USAGE ON *.* TO 'testuser1'@'localhost' @@ -603,6 +612,7 @@ authentication_string password_expired N is_role N default_role +max_statement_time 0.000000 Host localhost User testuser2 Password @@ -648,6 +658,7 @@ authentication_string password_expired N is_role N default_role +max_statement_time 0.000000 Host localhost User testuser3 Password @@ -693,6 +704,7 @@ authentication_string password_expired N is_role N default_role +max_statement_time 0.000000 GRANT SELECT ON *.* TO 'testuser1'@'localhost' WITH GRANT OPTION; # # Here