From 2b350d908ea6ff4c6613acba0da35f4004b15f04 Mon Sep 17 00:00:00 2001 From: Sveta Smirnova Date: Tue, 25 Nov 2025 17:00:12 +0300 Subject: [PATCH] PT-2250 - pt-table-checksum reports error if recursion method is DSN - We are now setting parent to current source server in get_cxn_from_dsn_table --- bin/pt-archiver | 12 ++- bin/pt-heartbeat | 12 ++- bin/pt-kill | 12 ++- bin/pt-online-schema-change | 12 ++- bin/pt-query-digest | 12 ++- bin/pt-replica-find | 12 ++- bin/pt-replica-restart | 12 ++- bin/pt-table-checksum | 12 ++- bin/pt-table-sync | 12 ++- lib/MasterSlave.pm | 14 +++- .../samples/ssl_dsns.sql | 4 +- t/pt-table-checksum/pt-2250.t | 74 +++++++++++++++++++ t/pt-table-checksum/samples/pt-2250_dsns.sql | 13 ++++ 13 files changed, 181 insertions(+), 32 deletions(-) create mode 100644 t/pt-table-checksum/pt-2250.t create mode 100644 t/pt-table-checksum/samples/pt-2250_dsns.sql diff --git a/bin/pt-archiver b/bin/pt-archiver index a5b1a461..fb6831d9 100755 --- a/bin/pt-archiver +++ b/bin/pt-archiver @@ -3735,11 +3735,17 @@ sub get_replicas { } ); } elsif ( $methods->[0] =~ m/^dsn=/i ) { + my @required_args = qw(dsn); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my ($dsn) = @args{@required_args}; (my $dsn_table_dsn = join ",", @$methods) =~ s/^dsn=//i; $replicas = $self->get_cxn_from_dsn_table( %args, dsn_table_dsn => $dsn_table_dsn, wait_no_die => $args{'wait_no_die'}, + parent => $dsn, ); } elsif ( $methods->[0] =~ m/none/i ) { @@ -4506,11 +4512,11 @@ sub reset_known_replication_threads { sub get_cxn_from_dsn_table { my ($self, %args) = @_; - my @required_args = qw(dsn_table_dsn make_cxn); + my @required_args = qw(dsn_table_dsn make_cxn parent); foreach my $arg ( @required_args ) { die "I need a $arg argument" unless $args{$arg}; } - my ($dsn_table_dsn, $make_cxn) = @args{@required_args}; + my ($dsn_table_dsn, $make_cxn, $parent) = @args{@required_args}; PTDEBUG && _d('DSN table DSN:', $dsn_table_dsn); my $dp = $self->{DSNParser}; @@ -4556,7 +4562,7 @@ sub get_cxn_from_dsn_table { } push @cxn, $lcxn; } else { - push @cxn, $make_cxn->(dsn_string => $dsn_string); + push @cxn, $make_cxn->(dsn_string => $dsn_string, parent => $parent); } } } diff --git a/bin/pt-heartbeat b/bin/pt-heartbeat index 6733c000..b9766069 100755 --- a/bin/pt-heartbeat +++ b/bin/pt-heartbeat @@ -191,11 +191,17 @@ sub get_replicas { } ); } elsif ( $methods->[0] =~ m/^dsn=/i ) { + my @required_args = qw(dsn); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my ($dsn) = @args{@required_args}; (my $dsn_table_dsn = join ",", @$methods) =~ s/^dsn=//i; $replicas = $self->get_cxn_from_dsn_table( %args, dsn_table_dsn => $dsn_table_dsn, wait_no_die => $args{'wait_no_die'}, + parent => $dsn, ); } elsif ( $methods->[0] =~ m/none/i ) { @@ -962,11 +968,11 @@ sub reset_known_replication_threads { sub get_cxn_from_dsn_table { my ($self, %args) = @_; - my @required_args = qw(dsn_table_dsn make_cxn); + my @required_args = qw(dsn_table_dsn make_cxn parent); foreach my $arg ( @required_args ) { die "I need a $arg argument" unless $args{$arg}; } - my ($dsn_table_dsn, $make_cxn) = @args{@required_args}; + my ($dsn_table_dsn, $make_cxn, $parent) = @args{@required_args}; PTDEBUG && _d('DSN table DSN:', $dsn_table_dsn); my $dp = $self->{DSNParser}; @@ -1012,7 +1018,7 @@ sub get_cxn_from_dsn_table { } push @cxn, $lcxn; } else { - push @cxn, $make_cxn->(dsn_string => $dsn_string); + push @cxn, $make_cxn->(dsn_string => $dsn_string, parent => $parent); } } } diff --git a/bin/pt-kill b/bin/pt-kill index ee7a9149..a2225859 100755 --- a/bin/pt-kill +++ b/bin/pt-kill @@ -4009,11 +4009,17 @@ sub get_replicas { } ); } elsif ( $methods->[0] =~ m/^dsn=/i ) { + my @required_args = qw(dsn); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my ($dsn) = @args{@required_args}; (my $dsn_table_dsn = join ",", @$methods) =~ s/^dsn=//i; $replicas = $self->get_cxn_from_dsn_table( %args, dsn_table_dsn => $dsn_table_dsn, wait_no_die => $args{'wait_no_die'}, + parent => $dsn, ); } elsif ( $methods->[0] =~ m/none/i ) { @@ -4780,11 +4786,11 @@ sub reset_known_replication_threads { sub get_cxn_from_dsn_table { my ($self, %args) = @_; - my @required_args = qw(dsn_table_dsn make_cxn); + my @required_args = qw(dsn_table_dsn make_cxn parent); foreach my $arg ( @required_args ) { die "I need a $arg argument" unless $args{$arg}; } - my ($dsn_table_dsn, $make_cxn) = @args{@required_args}; + my ($dsn_table_dsn, $make_cxn, $parent) = @args{@required_args}; PTDEBUG && _d('DSN table DSN:', $dsn_table_dsn); my $dp = $self->{DSNParser}; @@ -4830,7 +4836,7 @@ sub get_cxn_from_dsn_table { } push @cxn, $lcxn; } else { - push @cxn, $make_cxn->(dsn_string => $dsn_string); + push @cxn, $make_cxn->(dsn_string => $dsn_string, parent => $parent); } } } diff --git a/bin/pt-online-schema-change b/bin/pt-online-schema-change index 35780d0e..5ba54bc7 100755 --- a/bin/pt-online-schema-change +++ b/bin/pt-online-schema-change @@ -4300,11 +4300,17 @@ sub get_replicas { } ); } elsif ( $methods->[0] =~ m/^dsn=/i ) { + my @required_args = qw(dsn); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my ($dsn) = @args{@required_args}; (my $dsn_table_dsn = join ",", @$methods) =~ s/^dsn=//i; $replicas = $self->get_cxn_from_dsn_table( %args, dsn_table_dsn => $dsn_table_dsn, wait_no_die => $args{'wait_no_die'}, + parent => $dsn, ); } elsif ( $methods->[0] =~ m/none/i ) { @@ -5071,11 +5077,11 @@ sub reset_known_replication_threads { sub get_cxn_from_dsn_table { my ($self, %args) = @_; - my @required_args = qw(dsn_table_dsn make_cxn); + my @required_args = qw(dsn_table_dsn make_cxn parent); foreach my $arg ( @required_args ) { die "I need a $arg argument" unless $args{$arg}; } - my ($dsn_table_dsn, $make_cxn) = @args{@required_args}; + my ($dsn_table_dsn, $make_cxn, $parent) = @args{@required_args}; PTDEBUG && _d('DSN table DSN:', $dsn_table_dsn); my $dp = $self->{DSNParser}; @@ -5121,7 +5127,7 @@ sub get_cxn_from_dsn_table { } push @cxn, $lcxn; } else { - push @cxn, $make_cxn->(dsn_string => $dsn_string); + push @cxn, $make_cxn->(dsn_string => $dsn_string, parent => $parent); } } } diff --git a/bin/pt-query-digest b/bin/pt-query-digest index 693f5430..df34e137 100755 --- a/bin/pt-query-digest +++ b/bin/pt-query-digest @@ -10606,11 +10606,17 @@ sub get_replicas { } ); } elsif ( $methods->[0] =~ m/^dsn=/i ) { + my @required_args = qw(dsn); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my ($dsn) = @args{@required_args}; (my $dsn_table_dsn = join ",", @$methods) =~ s/^dsn=//i; $replicas = $self->get_cxn_from_dsn_table( %args, dsn_table_dsn => $dsn_table_dsn, wait_no_die => $args{'wait_no_die'}, + parent => $dsn, ); } elsif ( $methods->[0] =~ m/none/i ) { @@ -11377,11 +11383,11 @@ sub reset_known_replication_threads { sub get_cxn_from_dsn_table { my ($self, %args) = @_; - my @required_args = qw(dsn_table_dsn make_cxn); + my @required_args = qw(dsn_table_dsn make_cxn parent); foreach my $arg ( @required_args ) { die "I need a $arg argument" unless $args{$arg}; } - my ($dsn_table_dsn, $make_cxn) = @args{@required_args}; + my ($dsn_table_dsn, $make_cxn, $parent) = @args{@required_args}; PTDEBUG && _d('DSN table DSN:', $dsn_table_dsn); my $dp = $self->{DSNParser}; @@ -11427,7 +11433,7 @@ sub get_cxn_from_dsn_table { } push @cxn, $lcxn; } else { - push @cxn, $make_cxn->(dsn_string => $dsn_string); + push @cxn, $make_cxn->(dsn_string => $dsn_string, parent => $parent); } } } diff --git a/bin/pt-replica-find b/bin/pt-replica-find index c9939652..5dd43db8 100755 --- a/bin/pt-replica-find +++ b/bin/pt-replica-find @@ -2338,11 +2338,17 @@ sub get_replicas { } ); } elsif ( $methods->[0] =~ m/^dsn=/i ) { + my @required_args = qw(dsn); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my ($dsn) = @args{@required_args}; (my $dsn_table_dsn = join ",", @$methods) =~ s/^dsn=//i; $replicas = $self->get_cxn_from_dsn_table( %args, dsn_table_dsn => $dsn_table_dsn, wait_no_die => $args{'wait_no_die'}, + parent => $dsn, ); } elsif ( $methods->[0] =~ m/none/i ) { @@ -3109,11 +3115,11 @@ sub reset_known_replication_threads { sub get_cxn_from_dsn_table { my ($self, %args) = @_; - my @required_args = qw(dsn_table_dsn make_cxn); + my @required_args = qw(dsn_table_dsn make_cxn parent); foreach my $arg ( @required_args ) { die "I need a $arg argument" unless $args{$arg}; } - my ($dsn_table_dsn, $make_cxn) = @args{@required_args}; + my ($dsn_table_dsn, $make_cxn, $parent) = @args{@required_args}; PTDEBUG && _d('DSN table DSN:', $dsn_table_dsn); my $dp = $self->{DSNParser}; @@ -3159,7 +3165,7 @@ sub get_cxn_from_dsn_table { } push @cxn, $lcxn; } else { - push @cxn, $make_cxn->(dsn_string => $dsn_string); + push @cxn, $make_cxn->(dsn_string => $dsn_string, parent => $parent); } } } diff --git a/bin/pt-replica-restart b/bin/pt-replica-restart index 1b404941..fc11e2f9 100755 --- a/bin/pt-replica-restart +++ b/bin/pt-replica-restart @@ -2752,11 +2752,17 @@ sub get_replicas { } ); } elsif ( $methods->[0] =~ m/^dsn=/i ) { + my @required_args = qw(dsn); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my ($dsn) = @args{@required_args}; (my $dsn_table_dsn = join ",", @$methods) =~ s/^dsn=//i; $replicas = $self->get_cxn_from_dsn_table( %args, dsn_table_dsn => $dsn_table_dsn, wait_no_die => $args{'wait_no_die'}, + parent => $dsn, ); } elsif ( $methods->[0] =~ m/none/i ) { @@ -3523,11 +3529,11 @@ sub reset_known_replication_threads { sub get_cxn_from_dsn_table { my ($self, %args) = @_; - my @required_args = qw(dsn_table_dsn make_cxn); + my @required_args = qw(dsn_table_dsn make_cxn parent); foreach my $arg ( @required_args ) { die "I need a $arg argument" unless $args{$arg}; } - my ($dsn_table_dsn, $make_cxn) = @args{@required_args}; + my ($dsn_table_dsn, $make_cxn, $parent) = @args{@required_args}; PTDEBUG && _d('DSN table DSN:', $dsn_table_dsn); my $dp = $self->{DSNParser}; @@ -3573,7 +3579,7 @@ sub get_cxn_from_dsn_table { } push @cxn, $lcxn; } else { - push @cxn, $make_cxn->(dsn_string => $dsn_string); + push @cxn, $make_cxn->(dsn_string => $dsn_string, parent => $parent); } } } diff --git a/bin/pt-table-checksum b/bin/pt-table-checksum index b824990f..6e950084 100755 --- a/bin/pt-table-checksum +++ b/bin/pt-table-checksum @@ -5255,11 +5255,17 @@ sub get_replicas { } ); } elsif ( $methods->[0] =~ m/^dsn=/i ) { + my @required_args = qw(dsn); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my ($dsn) = @args{@required_args}; (my $dsn_table_dsn = join ",", @$methods) =~ s/^dsn=//i; $replicas = $self->get_cxn_from_dsn_table( %args, dsn_table_dsn => $dsn_table_dsn, wait_no_die => $args{'wait_no_die'}, + parent => $dsn, ); } elsif ( $methods->[0] =~ m/none/i ) { @@ -6026,11 +6032,11 @@ sub reset_known_replication_threads { sub get_cxn_from_dsn_table { my ($self, %args) = @_; - my @required_args = qw(dsn_table_dsn make_cxn); + my @required_args = qw(dsn_table_dsn make_cxn parent); foreach my $arg ( @required_args ) { die "I need a $arg argument" unless $args{$arg}; } - my ($dsn_table_dsn, $make_cxn) = @args{@required_args}; + my ($dsn_table_dsn, $make_cxn, $parent) = @args{@required_args}; PTDEBUG && _d('DSN table DSN:', $dsn_table_dsn); my $dp = $self->{DSNParser}; @@ -6076,7 +6082,7 @@ sub get_cxn_from_dsn_table { } push @cxn, $lcxn; } else { - push @cxn, $make_cxn->(dsn_string => $dsn_string); + push @cxn, $make_cxn->(dsn_string => $dsn_string, parent => $parent); } } } diff --git a/bin/pt-table-sync b/bin/pt-table-sync index 392b948e..abc641e3 100755 --- a/bin/pt-table-sync +++ b/bin/pt-table-sync @@ -6785,11 +6785,17 @@ sub get_replicas { } ); } elsif ( $methods->[0] =~ m/^dsn=/i ) { + my @required_args = qw(dsn); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my ($dsn) = @args{@required_args}; (my $dsn_table_dsn = join ",", @$methods) =~ s/^dsn=//i; $replicas = $self->get_cxn_from_dsn_table( %args, dsn_table_dsn => $dsn_table_dsn, wait_no_die => $args{'wait_no_die'}, + parent => $dsn, ); } elsif ( $methods->[0] =~ m/none/i ) { @@ -7556,11 +7562,11 @@ sub reset_known_replication_threads { sub get_cxn_from_dsn_table { my ($self, %args) = @_; - my @required_args = qw(dsn_table_dsn make_cxn); + my @required_args = qw(dsn_table_dsn make_cxn parent); foreach my $arg ( @required_args ) { die "I need a $arg argument" unless $args{$arg}; } - my ($dsn_table_dsn, $make_cxn) = @args{@required_args}; + my ($dsn_table_dsn, $make_cxn, $parent) = @args{@required_args}; PTDEBUG && _d('DSN table DSN:', $dsn_table_dsn); my $dp = $self->{DSNParser}; @@ -7606,7 +7612,7 @@ sub get_cxn_from_dsn_table { } push @cxn, $lcxn; } else { - push @cxn, $make_cxn->(dsn_string => $dsn_string); + push @cxn, $make_cxn->(dsn_string => $dsn_string, parent => $parent); } } } diff --git a/lib/MasterSlave.pm b/lib/MasterSlave.pm index 3805b0f9..e9fadb90 100644 --- a/lib/MasterSlave.pm +++ b/lib/MasterSlave.pm @@ -108,11 +108,19 @@ sub get_replicas { } ); } elsif ( $methods->[0] =~ m/^dsn=/i ) { + my @required_args = qw(dsn); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my ($dsn) = @args{@required_args}; (my $dsn_table_dsn = join ",", @$methods) =~ s/^dsn=//i; $replicas = $self->get_cxn_from_dsn_table( %args, dsn_table_dsn => $dsn_table_dsn, wait_no_die => $args{'wait_no_die'}, + # We will set current source server as a parent + # until https://perconadev.atlassian.net/browse/PT-2496 is implemented + parent => $dsn, ); } elsif ( $methods->[0] =~ m/none/i ) { @@ -1061,11 +1069,11 @@ sub reset_known_replication_threads { sub get_cxn_from_dsn_table { my ($self, %args) = @_; - my @required_args = qw(dsn_table_dsn make_cxn); + my @required_args = qw(dsn_table_dsn make_cxn parent); foreach my $arg ( @required_args ) { die "I need a $arg argument" unless $args{$arg}; } - my ($dsn_table_dsn, $make_cxn) = @args{@required_args}; + my ($dsn_table_dsn, $make_cxn, $parent) = @args{@required_args}; PTDEBUG && _d('DSN table DSN:', $dsn_table_dsn); my $dp = $self->{DSNParser}; @@ -1111,7 +1119,7 @@ sub get_cxn_from_dsn_table { } push @cxn, $lcxn; } else { - push @cxn, $make_cxn->(dsn_string => $dsn_string); + push @cxn, $make_cxn->(dsn_string => $dsn_string, parent => $parent); } } } diff --git a/t/pt-online-schema-change/samples/ssl_dsns.sql b/t/pt-online-schema-change/samples/ssl_dsns.sql index b91cd071..5ddde925 100644 --- a/t/pt-online-schema-change/samples/ssl_dsns.sql +++ b/t/pt-online-schema-change/samples/ssl_dsns.sql @@ -8,6 +8,6 @@ CREATE TABLE `dsns` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1; -INSERT INTO `dsns` VALUES (1, NULL, "F=/home/sveta/src/percona/percona-toolkit/t/pt-archiver/samples/pt-191-replica1.cnf,P=12346,h=127.0.0.1,u=root,p=msandbox,s=1"); -INSERT INTO `dsns` VALUES (2, NULL, "F=/home/sveta/src/percona/percona-toolkit/t/pt-archiver/samples/pt-191-replica2.cnf,P=12347,h=127.0.0.1,u=root,p=msandbox,s=1"); +INSERT INTO `dsns` VALUES (1, NULL, "F=t/pt-archiver/samples/pt-191-replica1.cnf,P=12346,h=127.0.0.1,u=root,p=msandbox,s=1"); +INSERT INTO `dsns` VALUES (2, NULL, "F=t/pt-archiver/samples/pt-191-replica2.cnf,P=12347,h=127.0.0.1,u=root,p=msandbox,s=1"); diff --git a/t/pt-table-checksum/pt-2250.t b/t/pt-table-checksum/pt-2250.t new file mode 100644 index 00000000..16a264d6 --- /dev/null +++ b/t/pt-table-checksum/pt-2250.t @@ -0,0 +1,74 @@ +#!/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 PerconaTest; +use Sandbox; +require "$trunk/bin/pt-table-checksum"; + +my $dp = new DSNParser(opts=>$dsn_opts); +my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp); +my $dbh = $sb->get_dbh_for('source'); + +if ( !$dbh ) { + plan skip_all => 'Cannot connect to sandbox source'; +} +else { + plan tests => 3; +} + +# The sandbox servers run with lock_wait_timeout=3 and it's not dynamic +# so we need to specify --set-vars innodb_lock_wait_timeout=3 else the tool will die. +# And --max-load "" prevents waiting for status variables. +my @args = (qw(--set-vars innodb_lock_wait_timeout=3), '--max-load', ''); +my ($output, $exit_code); + +# ############################################################################# +# Issue 388: mk-table-checksum crashes when column with comma in the name +# is used in a key +# ############################################################################# + +$sb->create_dbs($dbh, [qw(test)]); +$sb->load_file('source', 't/lib/samples/tables/issue-388.sql', 'test'); + +$sb->load_file('source', "t/pt-table-checksum/samples/pt-2250_dsns.sql"); +$dbh->do("insert into test.foo values (null, 'john, smith')"); + +($output, $exit_code) = full_output( + sub { + pt_table_checksum::main( + @args, + 'h=127.1,P=12345,u=msandbox,p=msandbox', + qw(-d test), + "--recursion-method=dsn=F=t/pt-archiver/samples/pt-191.cnf,D=dsns,t=dsns,h=127.0.0.1,P=12345,u=msandbox,p=msandbox") + }, + stderr => 1, +); + +is( + $exit_code, + 0, + "No error for recursion method dsn" +) or diag($output); + +unlike( + $output, + qr/Can't connect to local MySQL server/, + 'No error message for recursion method dsn' +) or diag($output); + +# ############################################################################# +# Done. +# ############################################################################# +$sb->wipe_clean($dbh); +ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox"); +exit; diff --git a/t/pt-table-checksum/samples/pt-2250_dsns.sql b/t/pt-table-checksum/samples/pt-2250_dsns.sql new file mode 100644 index 00000000..a43b5ff6 --- /dev/null +++ b/t/pt-table-checksum/samples/pt-2250_dsns.sql @@ -0,0 +1,13 @@ +CREATE DATABASE IF NOT EXISTS dsns; +USE dsns; +DROP TABLE IF EXISTS `dsns`; +CREATE TABLE `dsns` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `parent_id` int(11) DEFAULT NULL, + `dsn` varchar(255) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1; + +INSERT INTO `dsns` VALUES (1, NULL, "P=12346,h=127.0.0.1,u=msandbox,p=msandbox"); +INSERT INTO `dsns` VALUES (2, NULL, "P=12347,h=127.0.0.1,u=msandbox,p=msandbox"); +