From 1de149116a81f49afde70178e50855b3032c938d Mon Sep 17 00:00:00 2001 From: Sveta Smirnova Date: Fri, 20 Sep 2024 15:27:23 +0300 Subject: [PATCH] PT-2340 - Support MySQL 8.4 - Added tests for legacy style heartbeat and checksum tables --- bin/pt-heartbeat | 13 +- t/pt-heartbeat/heartbeat_table.t | 130 ++++++++++++++++++ ...e-table.sql => heartbeat-table-legacy.sql} | 0 t/pt-heartbeat/samples/heartbeat-table.sql | 11 ++ t/pt-table-checksum/privs.t | 43 ++++++ .../samples/privs-bug-916168-legacy.sql | 22 +++ 6 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 t/pt-heartbeat/heartbeat_table.t rename t/pt-heartbeat/samples/{precision-time-table.sql => heartbeat-table-legacy.sql} (100%) create mode 100644 t/pt-heartbeat/samples/heartbeat-table.sql create mode 100644 t/pt-table-checksum/samples/privs-bug-916168-legacy.sql diff --git a/bin/pt-heartbeat b/bin/pt-heartbeat index 5ed48dcc..af30ed66 100755 --- a/bin/pt-heartbeat +++ b/bin/pt-heartbeat @@ -6316,14 +6316,25 @@ sub main { die "Heartbeat table $db_tbl does not have a ts column" unless $tbl_struct->{is_col}->{ts}; + my $deprecated_cols = 0; + if ( $tbl_struct->{is_col}->{exec_master_log_file} && !$tbl_struct->{is_col}->{exec_source_log_file} ) { - $exec_source_log_pos_col = 'exec_master_log_file'; + $relay_source_log_file_col = 'exec_master_log_file'; + $deprecated_cols = 1; } if ( $tbl_struct->{is_col}->{exec_master_log_pos} && !$tbl_struct->{is_col}->{exec_source_log_pos} ) { $exec_source_log_pos_col = 'exec_master_log_pos'; + $deprecated_cols = 1; + } + + if ( $deprecated_cols ) { + warn "The current heartbeat table uses deprecated column names. Support for these names " + . "will be occasionally removed. Please update the table definition with command:\n" + . "ALTER TABLE `$db`.`$tbl` RENAME COLUMN exec_master_log_file TO exec_source_log_file, " + . "RENAME COLUMN exec_master_log_pos TO exec_source_log_pos;\n"; } my $hires_ts = $tbl_struct->{type_for}->{ts} =~ m/char/i ? 1 : 0; diff --git a/t/pt-heartbeat/heartbeat_table.t b/t/pt-heartbeat/heartbeat_table.t new file mode 100644 index 00000000..c4e1e16b --- /dev/null +++ b/t/pt-heartbeat/heartbeat_table.t @@ -0,0 +1,130 @@ +#!/usr/bin/env perl + +BEGIN { + die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n" + unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH}; + unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib"; +}; + +use strict; +use warnings FATAL => 'all'; +use English qw(-no_match_vars); +use Test::More; +use Data::Dumper; + +use PerconaTest; +use Sandbox; +require "$trunk/bin/pt-heartbeat"; + +my $dp = new DSNParser(opts=>$dsn_opts); +my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp); +my $source_dbh = $sb->get_dbh_for('source'); +my $replica1_dbh = $sb->get_dbh_for('replica1'); + +if ( !$source_dbh ) { + plan skip_all => 'Cannot connect to sandbox source'; +} +elsif ( !$replica1_dbh ) { + plan skip_all => 'Cannot connect to sandbox replica1'; +} + + +$sb->create_dbs($source_dbh, ['test']); + +my $output; +my $cnf = '/tmp/12345/my.sandbox.cnf'; +my $cmd = "$trunk/bin/pt-heartbeat -F $cnf "; +my $pid_file = "/tmp/__pt-heartbeat-test.pid"; +my $sent_file = "/tmp/pt-heartbeat-sentinel"; +my $ps_grep_cmd = "ps x | grep pt-heartbeat | grep daemonize | grep -v grep"; + +diag(`rm $sent_file 2>/dev/null`); + +# Loading heartbeat table +$sb->load_file('source', 't/pt-heartbeat/samples/heartbeat-table.sql'); + +# Start one daemonized instance to update it +system("$cmd --daemonize -D test --update --run-time 3s --pid $pid_file 1>/dev/null 2>/dev/null"); +PerconaTest::wait_for_files($pid_file); +$output = `$ps_grep_cmd`; +like($output, qr/$cmd/, 'It is running'); +ok(-f $pid_file, 'PID file created'); +my ($pid) = $output =~ /^\s*(\d+)\s+/; +$output = `cat $pid_file` if -f $pid_file; +chomp($output); +is($output, $pid, 'PID file has correct PID'); + +$output = `$cmd -D test --monitor --run-time 1s --source-server-id 12345 2>&1`; +if ( $output ) { + chomp ($output); + $output =~ s/\d/0/g; +} +is( + $output, + '0.00s [ 0.00s, 0.00s, 0.00s ]', + 'It is being updated', +); +unlike( + $output, + qr/The current checksum table uses deprecated column names./, + 'Deprecation warning not printed' +); + +PerconaTest::wait_until(sub { !-f $pid_file }); + +$output = `$ps_grep_cmd`; +chomp $output; +unlike($output, qr/$cmd/, 'It is not running anymore'); +ok(! -f $pid_file, 'PID file removed'); + +# Run again, create table with legacy structure, and check that the tool can work with it + +# Loading legacy heartbeat table +$sb->load_file('source', 't/pt-heartbeat/samples/heartbeat-table-legacy.sql'); + +# Start one daemonized instance to update it +system("$cmd --daemonize -D test --update --run-time 3s --pid $pid_file 1>/dev/null 2>/dev/null"); +PerconaTest::wait_for_files($pid_file); +$output = `$ps_grep_cmd`; +like($output, qr/$cmd/, 'It is running'); +ok(-f $pid_file, 'PID file created'); +($pid) = $output =~ /^\s*(\d+)\s+/; +$output = `cat $pid_file` if -f $pid_file; +chomp($output); +is($output, $pid, 'PID file has correct PID'); + +$output = `$cmd -D test --monitor --run-time 1s --source-server-id 12345 2>&1`; +if ( $output ) { + chomp ($output); + $output =~ s/\d/0/g; +} + +like( + $output, + qr/0.00s \[ 0.00s, 0.00s, 0.00s \]/, + 'It is being updated', +) or diag($output); + +like( + $output, + qr/The current heartbeat table uses deprecated column names./, + 'Deprecation warning printed for legacy syntax' +); + +PerconaTest::wait_until(sub { !-f $pid_file }); + +$output = `$ps_grep_cmd`; +chomp $output; +unlike($output, qr/$cmd/, 'It is not running anymore'); +ok(! -f $pid_file, 'PID file removed'); + +# ############################################################################# +# Done. +# ############################################################################# +diag(`rm $pid_file $sent_file 2>/dev/null`); +$sb->wipe_clean($source_dbh); +# $sb->wipe_clean($replica1_dbh); +ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox"); + +done_testing; +exit; diff --git a/t/pt-heartbeat/samples/precision-time-table.sql b/t/pt-heartbeat/samples/heartbeat-table-legacy.sql similarity index 100% rename from t/pt-heartbeat/samples/precision-time-table.sql rename to t/pt-heartbeat/samples/heartbeat-table-legacy.sql diff --git a/t/pt-heartbeat/samples/heartbeat-table.sql b/t/pt-heartbeat/samples/heartbeat-table.sql new file mode 100644 index 00000000..fa0e3ea0 --- /dev/null +++ b/t/pt-heartbeat/samples/heartbeat-table.sql @@ -0,0 +1,11 @@ +DROP DATABASE IF EXISTS test; +CREATE DATABASE test; +USE test; +CREATE TABLE heartbeat ( + ts varchar(26) NOT NULL, + server_id int unsigned NOT NULL PRIMARY KEY, + file varchar(255) DEFAULT NULL, -- SHOW MASTER STATUS + position bigint unsigned DEFAULT NULL, -- SHOW MASTER STATUS + relay_source_log_file varchar(255) DEFAULT NULL, -- SHOW SLAVE STATUS + exec_source_log_pos bigint unsigned DEFAULT NULL -- SHOW SLAVE STATUS +) ENGINE=MEMORY; diff --git a/t/pt-table-checksum/privs.t b/t/pt-table-checksum/privs.t index 184b926e..5d853ccd 100644 --- a/t/pt-table-checksum/privs.t +++ b/t/pt-table-checksum/privs.t @@ -187,6 +187,49 @@ is( "test_user privs work (bug 916168)" ); +unlike( + $output, + qr/The current checksum table uses deprecated column names./, + 'Deprecation warning not printed' +); + +diag(`/tmp/12345/use -u root -e "drop user 'test_user'\@'%'"`); +wait_until( + sub { + my $rows=$replica2_dbh->selectall_arrayref("SELECT user FROM mysql.user"); + return !grep { ($_->[0] || '') eq 'test_user' } @$rows; + } +); + +# ############################################################################# +# Legacy checksum table +# ############################################################################# +diag(`/tmp/12345/use -u root < $trunk/t/pt-table-checksum/samples/privs-bug-916168-legacy.sql`); + +$output = output( + sub { $exit_status = pt_table_checksum::main(@args, + "$source_dsn,u=test_user,p=foo", qw(-t sakila.country)) }, + stderr => 1, +); + +is( + $exit_status, + 0, + "test_user privs work (bug 916168) returned no error" +) or diag($exit_status); + +is( + PerconaTest::count_checksum_results($output, 'rows'), + 109, + "test_user privs work (bug 916168)" +); + +like( + $output, + qr/The current checksum table uses deprecated column names./, + 'Deprecation warning printed for legacy table' +); + diag(`/tmp/12345/use -u root -e "drop user 'test_user'\@'%'"`); wait_until( sub { diff --git a/t/pt-table-checksum/samples/privs-bug-916168-legacy.sql b/t/pt-table-checksum/samples/privs-bug-916168-legacy.sql new file mode 100644 index 00000000..0fcb2af4 --- /dev/null +++ b/t/pt-table-checksum/samples/privs-bug-916168-legacy.sql @@ -0,0 +1,22 @@ +CREATE USER 'test_user'@'%' identified by 'foo'; +grant select, replication slave, replication client, super, process on *.* to 'test_user'@'%'; +grant all on percona.* to 'test_user'@'%'; +create database if not exists percona; +use percona; +drop table if exists checksums; +CREATE TABLE `checksums` ( + `db` char(64) NOT NULL, + `tbl` char(64) NOT NULL, + `chunk` int(11) NOT NULL, + `chunk_time` float DEFAULT NULL, + `chunk_index` varchar(200) DEFAULT NULL, + `lower_boundary` text, + `upper_boundary` text, + `this_crc` char(40) NOT NULL, + `this_cnt` int(11) NOT NULL, + `master_crc` char(40) DEFAULT NULL, + `master_cnt` int(11) DEFAULT NULL, + `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`db`,`tbl`,`chunk`), + KEY `ts_db_tbl` (`ts`,`db`,`tbl`) +) ENGINE=InnoDB;