From 5d875e5f55485a5593acfe374c0d1c3e59321afc Mon Sep 17 00:00:00 2001 From: Frank Cizmich Date: Fri, 21 Nov 2014 12:12:05 -0200 Subject: [PATCH 01/23] fixed PTDEBUG error on Cxn - 1394934 --- bin/pt-config-diff | 1 - bin/pt-deadlock-logger | 1 - bin/pt-fk-error-logger | 1 - bin/pt-kill | 1 - bin/pt-online-schema-change | 1 - bin/pt-table-checksum | 1 - bin/pt-upgrade | 1 - lib/Cxn.pm | 1 - 8 files changed, 8 deletions(-) diff --git a/bin/pt-config-diff b/bin/pt-config-diff index 4de976fa..58b6310c 100755 --- a/bin/pt-config-diff +++ b/bin/pt-config-diff @@ -2399,7 +2399,6 @@ sub is_cluster_node { my $sql = "SHOW VARIABLES LIKE 'wsrep\_on'"; PTDEBUG && _d($cxn->name, $sql); my $row = $cxn->dbh->selectrow_arrayref($sql); - PTDEBUG && _d(Dumper($row)); return $row && $row->[1] && ($row->[1] eq 'ON' || $row->[1] eq '1') ? 1 : 0; } diff --git a/bin/pt-deadlock-logger b/bin/pt-deadlock-logger index e9140b02..f8b2089f 100755 --- a/bin/pt-deadlock-logger +++ b/bin/pt-deadlock-logger @@ -2743,7 +2743,6 @@ sub is_cluster_node { my $sql = "SHOW VARIABLES LIKE 'wsrep\_on'"; PTDEBUG && _d($cxn->name, $sql); my $row = $cxn->dbh->selectrow_arrayref($sql); - PTDEBUG && _d(Dumper($row)); return $row && $row->[1] && ($row->[1] eq 'ON' || $row->[1] eq '1') ? 1 : 0; } diff --git a/bin/pt-fk-error-logger b/bin/pt-fk-error-logger index 14b43289..92607545 100755 --- a/bin/pt-fk-error-logger +++ b/bin/pt-fk-error-logger @@ -1895,7 +1895,6 @@ sub is_cluster_node { my $sql = "SHOW VARIABLES LIKE 'wsrep\_on'"; PTDEBUG && _d($cxn->name, $sql); my $row = $cxn->dbh->selectrow_arrayref($sql); - PTDEBUG && _d(Dumper($row)); return $row && $row->[1] && ($row->[1] eq 'ON' || $row->[1] eq '1') ? 1 : 0; } diff --git a/bin/pt-kill b/bin/pt-kill index c7e5482b..8578d0f5 100755 --- a/bin/pt-kill +++ b/bin/pt-kill @@ -5262,7 +5262,6 @@ sub is_cluster_node { my $sql = "SHOW VARIABLES LIKE 'wsrep\_on'"; PTDEBUG && _d($cxn->name, $sql); my $row = $cxn->dbh->selectrow_arrayref($sql); - PTDEBUG && _d(Dumper($row)); return $row && $row->[1] && ($row->[1] eq 'ON' || $row->[1] eq '1') ? 1 : 0; } diff --git a/bin/pt-online-schema-change b/bin/pt-online-schema-change index 67aa5343..afb6bb97 100755 --- a/bin/pt-online-schema-change +++ b/bin/pt-online-schema-change @@ -3859,7 +3859,6 @@ sub is_cluster_node { my $sql = "SHOW VARIABLES LIKE 'wsrep\_on'"; PTDEBUG && _d($cxn->name, $sql); my $row = $cxn->dbh->selectrow_arrayref($sql); - PTDEBUG && _d(Dumper($row)); return $row && $row->[1] && ($row->[1] eq 'ON' || $row->[1] eq '1') ? 1 : 0; } diff --git a/bin/pt-table-checksum b/bin/pt-table-checksum index 3adee83e..bf65f843 100755 --- a/bin/pt-table-checksum +++ b/bin/pt-table-checksum @@ -3637,7 +3637,6 @@ sub is_cluster_node { my $sql = "SHOW VARIABLES LIKE 'wsrep\_on'"; PTDEBUG && _d($cxn->name, $sql); my $row = $cxn->dbh->selectrow_arrayref($sql); - PTDEBUG && _d(Dumper($row)); return $row && $row->[1] && ($row->[1] eq 'ON' || $row->[1] eq '1') ? 1 : 0; } diff --git a/bin/pt-upgrade b/bin/pt-upgrade index cf04c82b..f2329b5d 100755 --- a/bin/pt-upgrade +++ b/bin/pt-upgrade @@ -2568,7 +2568,6 @@ sub is_cluster_node { my $sql = "SHOW VARIABLES LIKE 'wsrep\_on'"; PTDEBUG && _d($cxn->name, $sql); my $row = $cxn->dbh->selectrow_arrayref($sql); - PTDEBUG && _d(Dumper($row)); return $row && $row->[1] && ($row->[1] eq 'ON' || $row->[1] eq '1') ? 1 : 0; } diff --git a/lib/Cxn.pm b/lib/Cxn.pm index b8dc7168..deb24ee8 100644 --- a/lib/Cxn.pm +++ b/lib/Cxn.pm @@ -234,7 +234,6 @@ sub is_cluster_node { my $sql = "SHOW VARIABLES LIKE 'wsrep\_on'"; PTDEBUG && _d($cxn->name, $sql); my $row = $cxn->dbh->selectrow_arrayref($sql); - PTDEBUG && _d(Dumper($row)); return $row && $row->[1] && ($row->[1] eq 'ON' || $row->[1] eq '1') ? 1 : 0; } From 01f8102623b6dcce25c15a257ce2efd357df0b59 Mon Sep 17 00:00:00 2001 From: Frank Cizmich Date: Fri, 28 Nov 2014 11:53:34 -0200 Subject: [PATCH 02/23] ask-pass-being-ignored-1396868 --- bin/pt-config-diff | 2 +- bin/pt-deadlock-logger | 2 +- bin/pt-fk-error-logger | 2 +- bin/pt-kill | 2 +- bin/pt-online-schema-change | 3 ++- bin/pt-table-checksum | 2 +- bin/pt-upgrade | 2 +- lib/Cxn.pm | 2 +- 8 files changed, 9 insertions(+), 8 deletions(-) diff --git a/bin/pt-config-diff b/bin/pt-config-diff index 4de976fa..f263b2de 100755 --- a/bin/pt-config-diff +++ b/bin/pt-config-diff @@ -2295,7 +2295,7 @@ sub new { set => $args{set}, NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, dbh_set => 0, - ask_pass => $args{ask_pass}, + ask_pass => $o->get('ask-pass') || $args{ask_pass}, DSNParser => $dp, is_cluster_node => undef, parent => $args{parent}, diff --git a/bin/pt-deadlock-logger b/bin/pt-deadlock-logger index e9140b02..cc8eca2d 100755 --- a/bin/pt-deadlock-logger +++ b/bin/pt-deadlock-logger @@ -2639,7 +2639,7 @@ sub new { set => $args{set}, NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, dbh_set => 0, - ask_pass => $args{ask_pass}, + ask_pass => $o->get('ask-pass') || $args{ask_pass}, DSNParser => $dp, is_cluster_node => undef, parent => $args{parent}, diff --git a/bin/pt-fk-error-logger b/bin/pt-fk-error-logger index 14b43289..96d4e09f 100755 --- a/bin/pt-fk-error-logger +++ b/bin/pt-fk-error-logger @@ -1791,7 +1791,7 @@ sub new { set => $args{set}, NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, dbh_set => 0, - ask_pass => $args{ask_pass}, + ask_pass => $o->get('ask-pass') || $args{ask_pass}, DSNParser => $dp, is_cluster_node => undef, parent => $args{parent}, diff --git a/bin/pt-kill b/bin/pt-kill index c7e5482b..db73976d 100755 --- a/bin/pt-kill +++ b/bin/pt-kill @@ -5158,7 +5158,7 @@ sub new { set => $args{set}, NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, dbh_set => 0, - ask_pass => $args{ask_pass}, + ask_pass => $o->get('ask-pass') || $args{ask_pass}, DSNParser => $dp, is_cluster_node => undef, parent => $args{parent}, diff --git a/bin/pt-online-schema-change b/bin/pt-online-schema-change index 67aa5343..fb4c3b23 100755 --- a/bin/pt-online-schema-change +++ b/bin/pt-online-schema-change @@ -3755,7 +3755,7 @@ sub new { set => $args{set}, NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, dbh_set => 0, - ask_pass => $args{ask_pass}, + ask_pass => $o->get('ask-pass') || $args{ask_pass}, DSNParser => $dp, is_cluster_node => undef, parent => $args{parent}, @@ -7963,6 +7963,7 @@ sub main { }; my $cxn = $make_cxn->(dsn => $dsn); + $o->set('ask-pass', 0); # so we don't ask twice (password is already stored in dsn) my $aux_cxn = $make_cxn->(dsn => $dsn, prev_dsn => $dsn); my $cluster = Percona::XtraDB::Cluster->new; diff --git a/bin/pt-table-checksum b/bin/pt-table-checksum index 3adee83e..4f376898 100755 --- a/bin/pt-table-checksum +++ b/bin/pt-table-checksum @@ -3533,7 +3533,7 @@ sub new { set => $args{set}, NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, dbh_set => 0, - ask_pass => $args{ask_pass}, + ask_pass => $o->get('ask-pass') || $args{ask_pass}, DSNParser => $dp, is_cluster_node => undef, parent => $args{parent}, diff --git a/bin/pt-upgrade b/bin/pt-upgrade index cf04c82b..57803988 100755 --- a/bin/pt-upgrade +++ b/bin/pt-upgrade @@ -2464,7 +2464,7 @@ sub new { set => $args{set}, NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, dbh_set => 0, - ask_pass => $args{ask_pass}, + ask_pass => $o->get('ask-pass') || $args{ask_pass}, DSNParser => $dp, is_cluster_node => undef, parent => $args{parent}, diff --git a/lib/Cxn.pm b/lib/Cxn.pm index b8dc7168..41c8f543 100644 --- a/lib/Cxn.pm +++ b/lib/Cxn.pm @@ -108,7 +108,7 @@ sub new { set => $args{set}, NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, dbh_set => 0, - ask_pass => $args{ask_pass}, + ask_pass => $o->get('ask-pass') || $args{ask_pass}, DSNParser => $dp, is_cluster_node => undef, parent => $args{parent}, From 2fb93db90902ce83cc6a2e0aaec52b874cbe422c Mon Sep 17 00:00:00 2001 From: Frank Cizmich Date: Fri, 28 Nov 2014 13:49:11 -0200 Subject: [PATCH 03/23] restore terminal to normal state if ctl-c pressed while asking for pass - 1396870 --- bin/pt-online-schema-change | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bin/pt-online-schema-change b/bin/pt-online-schema-change index fb4c3b23..8b8f4329 100755 --- a/bin/pt-online-schema-change +++ b/bin/pt-online-schema-change @@ -10485,6 +10485,10 @@ sub sig_int { my ( $signal ) = @_; $oktorun = 0; # flag for cleanup tasks print STDERR "# Exiting on SIG$signal.\n"; + # restore terminal to normal state in case CTL-C issued while asking for password + # https://bugs.launchpad.net/percona-toolkit/+bug/1396870 + use Term::ReadKey; + ReadMode 0; exit 1; } From 3aebac505af4e5fc9583484fe5ab7f3dd8f66647 Mon Sep 17 00:00:00 2001 From: Frank Cizmich Date: Mon, 1 Dec 2014 13:41:31 -0200 Subject: [PATCH 04/23] added result files for 5.7 tests --- .../samples/default-results-5.7.txt | 41 +++++++++++++++++++ .../samples/static-chunk-size-results-5.7.txt | 41 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 t/pt-table-checksum/samples/default-results-5.7.txt create mode 100644 t/pt-table-checksum/samples/static-chunk-size-results-5.7.txt diff --git a/t/pt-table-checksum/samples/default-results-5.7.txt b/t/pt-table-checksum/samples/default-results-5.7.txt new file mode 100644 index 00000000..55c0bddd --- /dev/null +++ b/t/pt-table-checksum/samples/default-results-5.7.txt @@ -0,0 +1,41 @@ +ERRORS DIFFS ROWS SKIPPED TABLE +0 0 0 0 mysql.columns_priv +0 0 0 0 mysql.db +0 0 0 0 mysql.event +0 0 0 0 mysql.func +0 0 0 0 mysql.help_category +0 0 0 0 mysql.help_keyword +0 0 0 0 mysql.help_relation +0 0 0 0 mysql.help_topic +0 0 0 0 mysql.ndb_binlog_index +0 0 0 0 mysql.plugin +0 0 0 0 mysql.proc +0 0 0 0 mysql.procs_priv +0 0 1 0 mysql.proxies_priv +0 0 0 0 mysql.servers +0 0 0 0 mysql.tables_priv +0 0 0 0 mysql.time_zone +0 0 0 0 mysql.time_zone_leap_second +0 0 0 0 mysql.time_zone_name +0 0 0 0 mysql.time_zone_transition +0 0 0 0 mysql.time_zone_transition_type +0 0 8 0 mysql.user +0 0 18 0 percona_test.checksums +0 0 1 0 percona_test.load_data +0 0 1 0 percona_test.sentinel +0 0 200 0 sakila.actor +0 0 603 0 sakila.address +0 0 16 0 sakila.category +0 0 600 0 sakila.city +0 0 109 0 sakila.country +0 0 599 0 sakila.customer +0 0 1000 0 sakila.film +0 0 5462 0 sakila.film_actor +0 0 1000 0 sakila.film_category +0 0 1000 0 sakila.film_text +0 0 4581 0 sakila.inventory +0 0 6 0 sakila.language +0 0 16049 0 sakila.payment +0 0 16044 0 sakila.rental +0 0 2 0 sakila.staff +0 0 2 0 sakila.store diff --git a/t/pt-table-checksum/samples/static-chunk-size-results-5.7.txt b/t/pt-table-checksum/samples/static-chunk-size-results-5.7.txt new file mode 100644 index 00000000..418b538f --- /dev/null +++ b/t/pt-table-checksum/samples/static-chunk-size-results-5.7.txt @@ -0,0 +1,41 @@ +ERRORS DIFFS ROWS CHUNKS SKIPPED TABLE +0 0 0 1 0 mysql.columns_priv +0 0 0 1 0 mysql.db +0 0 0 1 0 mysql.event +0 0 0 1 0 mysql.func +0 0 0 1 0 mysql.help_category +0 0 0 1 0 mysql.help_keyword +0 0 0 1 0 mysql.help_relation +0 0 0 1 0 mysql.help_topic +0 0 0 1 0 mysql.ndb_binlog_index +0 0 0 1 0 mysql.plugin +0 0 0 1 0 mysql.proc +0 0 0 1 0 mysql.procs_priv +0 0 1 1 0 mysql.proxies_priv +0 0 0 1 0 mysql.servers +0 0 0 1 0 mysql.tables_priv +0 0 0 1 0 mysql.time_zone +0 0 0 1 0 mysql.time_zone_leap_second +0 0 0 1 0 mysql.time_zone_name +0 0 0 1 0 mysql.time_zone_transition +0 0 0 1 0 mysql.time_zone_transition_type +0 0 8 1 0 mysql.user +0 0 18 1 0 percona_test.checksums +0 0 1 1 0 percona_test.load_data +0 0 1 1 0 percona_test.sentinel +0 0 200 1 0 sakila.actor +0 0 603 1 0 sakila.address +0 0 16 1 0 sakila.category +0 0 600 1 0 sakila.city +0 0 109 1 0 sakila.country +0 0 599 1 0 sakila.customer +0 0 1000 1 0 sakila.film +0 0 5462 8 0 sakila.film_actor +0 0 1000 1 0 sakila.film_category +0 0 1000 1 0 sakila.film_text +0 0 4581 7 0 sakila.inventory +0 0 6 1 0 sakila.language +0 0 16049 19 0 sakila.payment +0 0 16044 19 0 sakila.rental +0 0 2 1 0 sakila.staff +0 0 2 1 0 sakila.store From 535eeab38a6b4e6455b32c58ada248bee6eaa30b Mon Sep 17 00:00:00 2001 From: Frank Cizmich Date: Mon, 1 Dec 2014 14:07:37 -0200 Subject: [PATCH 05/23] added sandbox for 5.7 - fixed sakila for 5.7 compatibility --- sandbox/sakila.sql | 5 +- sandbox/servers/5.7/data.tar.gz | Bin 0 -> 36750 bytes sandbox/servers/5.7/my.sandbox.cnf | 29 +++++ sandbox/servers/5.7/system_idb_tables.sql | 149 ++++++++++++++++++++++ 4 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 sandbox/servers/5.7/data.tar.gz create mode 100644 sandbox/servers/5.7/my.sandbox.cnf create mode 100644 sandbox/servers/5.7/system_idb_tables.sql diff --git a/sandbox/sakila.sql b/sandbox/sakila.sql index 6dee8c2a..94b5216e 100644 --- a/sandbox/sakila.sql +++ b/sandbox/sakila.sql @@ -6,6 +6,7 @@ SET NAMES utf8; SET UNIQUE_CHECKS=0; SET FOREIGN_KEY_CHECKS=0; + CREATE TABLE `actor` ( `actor_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT, `first_name` varchar(45) NOT NULL, @@ -370,7 +371,7 @@ SELECT film.film_id AS FID, film.title AS title, film.description AS description FROM category LEFT JOIN film_category ON category.category_id = film_category.category_id LEFT JOIN film ON film_category.film_id = film.film_id JOIN film_actor ON film.film_id = film_actor.film_id JOIN actor ON film_actor.actor_id = actor.actor_id -GROUP BY film.film_id; +GROUP BY film.film_id, category.name; CREATE VIEW nicer_but_slower_film_list AS @@ -381,7 +382,7 @@ SELECT film.film_id AS FID, film.title AS title, film.description AS description FROM category LEFT JOIN film_category ON category.category_id = film_category.category_id LEFT JOIN film ON film_category.film_id = film.film_id JOIN film_actor ON film.film_id = film_actor.film_id JOIN actor ON film_actor.actor_id = actor.actor_id -GROUP BY film.film_id; +GROUP BY film.film_id, category.name; CREATE VIEW staff_list AS diff --git a/sandbox/servers/5.7/data.tar.gz b/sandbox/servers/5.7/data.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..fb36f6106704d6434c4ddc56af068981bda7557e GIT binary patch literal 36750 zcmY&;1zZ&0_ckplNGc$RfPkc=bV^C5bhmWp(w)+wfRsvicXvs5cP_EOvh%Lr`u*Se z%-r0anS1WJ=RD83Lm7pRKIX}#hJb8pO7aV3C}(i?=Z5i?6q{qW~)TL2grDiSX1NdiPFHrd|nV}oT5}=UlBZyi;en0gJ1)d@1_RP2v9`v{y8VP*+Ff>PuK~~SXpKGp?CU$ORvsa!uXrl7Zy?= zWAq;Gt0^Vu%R4#}VJ9?&L8jC0j>U^hpLtPjt$TxX?ug$azb@tWDg#BzjQC zKoK2H=Duo5Ser+wbtH~u4bGv{V79kaEBQWm+qh)d_H|=<7zrYP)qMU9@BBehs?$fu z-|Bx0!E7G@!hW;A^0Lc=x&fG zNtHZA`VhKLDew2Kv=PUnLbZ1Na`&tu>0D8VA}f%M36|34;-T0(r_Igwxb!2osoYbf?b#%w39cI zz)D0O=LljD4%*?8{^#6udDZ=>A9{ig(ESm=__=?gxM4#xGu7YyC_+b8Qb2*}@XQhQ z&LMmvesoJuAg_g$-y`lq+Yco49_Maz>x%>*HPKONL(P-8UCslV)aPs#xsrnKsID$k z^qZ|-V)|>B5$jiBV*aQ-yl&E%V?;yA9cS9-xg;xy)JGu_=v7A-1@Rj2)O=yEoRa;p z>NLZA6*%Nxe>dupiyL^II-HTa#+E~=wxumUPIBST%m`jD`w!A1Q~0ZDs z9-hw8Hu6Gumb0p)VJM?NsnL7PvZ_ys-GY2P)2I$?M#+;OW`r?)m`>aPs z{5Oyxe10g!0tl)B{6c&)zkrx%`Kdh+o#hzt>5ESw?Dk6{FgXdN&`bgN|E=kspW>Ui zS8oR@Y})cU!NQv#<>-n`QZwD%ayUa!93wmJH|^>J-mlcWnH898&6fJ>e*#r4vl_7e zs3@LlO=3y&Vy@O2{TGAUkqOVHd9NUg9$C_O!8+^L$Pg%p!tWVi6^U#98?3&cl!$RA zZ(QNY0nfB3+N*Faf)kqf&H|rSzgBI=%QujeUtGv)=%&RXsV>N3IRXa5_I8I{`-q@> zuaGkjZ{y}yOD9e45%u%8jd~5#D9|+g%a32k&`~VhjU?TWG0{xp$k6Xw^c%JUqMozW zHV544L6qK8=Z~Cp+3533Y$=|0m5k%C<@U=TP>qV@rD8V^l)&CKJC7W{Xf-{gfUl+o zud6B6MDZ(wt;EFA`|<$@|-1_3?J7JiCh!7E}oiLSB3yLpWJFvQp=G9Q&bOy_$h?)D)FuTD`iQ;(4w<nhLM0gAyx%BKb)hEsB@8z&V{*j=ldAm>T-k)(g-Z6g0N;J+W6l-=3^KL)z;S zI42P^#6w;qMiPG%I8PNb^ay`qhZO)05;!lzJHNT?@D}R`JAp7#t@m@Rk|2$qPIP5h zbOl;;SzC0eSak7OjJ>uv#k61^&TO>FY{beuY5t{k^u@gND4mPdyl!09+&lFh!5ob< z2@QcJHFAnE-DR8=>SK1St?*Nfb*lUJfvatoVwk;G;E*G$LyUdw!$$ESZvfBnx zKT`hZ`b4u{(<}@DbwT{EPCS?vvRlB26a^9vQfSm)wNsy2Y$$*Mnggb2 zv>U4CFQc@?%`0E3KZ4m`AH4bNPCX1e?Z_wl0JN}eC+Q3}fOW%VO zCSG?1`sE3YsJjO3&m1FXr*Dtqw#`^yyg?CRIJBW1*(?;1t|t=ryz)9_RmX0v`^stq zwfVSL?@Db$+p626>wu~n85}#_8Dm}9vt@(Nmk)6TJswV&LY0HOwNv6ibJ>l(zE;gfW)v7i~HbaUX6nQhaSgy{< zN13qERqMlSAcCr<$5SKL7@WFqI}8cMnsMTd8(nAqrFIp#@S5_9Sd(iHkCLCLUtx)T zR%qD1vI2`jc{Hr?OsIlxa>RE}l@P*=K_S(?pDl!pr?h+8b%uE6fYWYA;%c2sP0s7_T3%dZ@)D?p509F%(5)pe!Txgw=m4W{g zKPmL92aomJ;0_W0wVmQBhKxjcE`v3bxX!r}|9&+vs>Rx+uU=^XHk$`1+FEF&^Y)=? zDK$6#R~Ht=9ESg5VMM>Sq|#Jt+N<`s`3PI{ZFLHRjdos1rAT@! zUwSiVdNs>}U(}bA`mVHwmbB`+=M~8koZV$iQXGvEq0EJe_8nB?~2`J<_iCdw9!Zn9UMe zBCm@6={3<;E$MU2JCmlyM7?l*dDFy;;N4*VUXBCWx+ED>g7jhx{V|&FSlXP$qb&J( zymd*svZj>-N6{BfoXPUmnkmzb5-GHMDhJs1H!7SdhCf{tbjB`8r+54V6Zy&M?9PoA;5#xm3nUIpm^7O5gB=h3QaN3SL04yo{EW^TzhR&`84^FvT{ zMvSS1IL3(cvg5|rX~$_bYOe4#;(Lvs^1ntiPmBm@Ao!%aK_t;fJv-L(V*y!!xhd>C)-q|Ou3atH_Eb6kY`ZG&n^bY6hzS?Y4IziN>!s0VO28{sU z2opt8v+8)ciwBx5bE;wdbUD7f(aUm=OKbLFox%PAYlLmiO{Cp=kZw-Mfj- zVA5F5?D9{qze%Sfm(!{^52_)Bac6$qO&P7!i|nhN7cfX~!F1*(hG_XjoIc*o9Rhyj zFJ9qJf?^e<`n0dJ6ID&}fn$`?`|-46a(pQ0D>M%0agUA^aSHT*eC(jq;t{}@a14I_ z{`yjJ-wm0<^~O~0_~bP5&A&h_>0(@k|9%{tHf!61A4nvn#1^RiYr5n~atBt_IqHj7 zZ*Y-zLF8!ffUVb%7TaA=O$?}&Yvt;ZIfV*AXlu7HmKVc4(;4537UQLlxVdUoVbEFZ zRe*zJhx^5Ads6yI$xuPn`2HjFUiNP77ZrUH70`Pxd4qAXd*t@|XIH}4PH<>eR%Q@u zR!(v7e9ZtbnfeZ-hes=XffW&;gWI)=iA#QmOO+t;O8{KlLNBb+0hu-wOBg@gKic>s7(a40 zU-7hnW^}E@%gOFyM#G$HPQEUnf?IJuXKyjk*}J{4Qs+U>Bp@gREW?NQ*h56C)YD`Lf-KXw`#LWVD{e*B9a>_W=wRyF3# znP<)1#jm~6U6{h}gy(_8d+^t2FC+PQZKIu=@79dm)BpVg zuoMH0dj_*=rvtV)??CRsv(PwuOxRjN&|`bHHHtLw@n7a9ibqE|XtD$HA#z`a#$ArR z6o|ZEW0lE~pdCWLdq z$>|ip{k@HvjhACj0%Eq^1#1p)i}yR<{s)4+7pMb7O%arI0@z|uy%8=0>VKZ$h#2^) zvL?;ShJ+%#|1_pKTYq^(4|^$6WTLidc_$`XJ|`OD@Ux7_RlM9b>1{!i@>`Mcxm=Pu zYuc?sTGG>i3G=p;wTU4p%06mAA(>9C?92Pla~FPdu09>tc(_;;n@^hj&+M-Sef(W- z?}(31i$qfv$!au;?HgwfA7TX!Qf6*@qYT?ps+^6{?!PzhKb~aeq6CR@*qC=4^S{T7 z5Yere*XV{u2NRuVXsr2mceB}``aIvqV89$1#FG@i0KCz1G&cem*#%B(PbwcKoS>)+ zwd7|~?_6c@RB>}akS{r3pXPx)#CD%^5ItRR; zBU54qfGxKl^9{F8K2V>{-EdrThb+i{OyHWOve61IaYd~v-05Gg?LQ8g`%KW*|L7g} z_4e6&_p{>HQqz`(a8E!YUsy#-tZL<)C?m0DjY$>}m>Mv7|R;e0RgyLac8I=_f)LG+-~YI)a?$)8ZaKsb5n z!79APOhrQ^?YP5UA5O)RxKD3- z7$0V)Ww$)+jJ=jtleLF##jVTrR(VQU(c6tzyu(2_$l7^#v`}QkY@{ho?ea_MiSey+ zaV0PDs%=M#dD~^ZCewNp>a|Y2#sskh%2a(K9qX^Z=Q*Ez9XqbR2(-5K3dU)R>u=Tq zwHn$B%=Wd31d`C&Q0tJDyL$42rQz!}%Pj-kPU(3FO1uFBQj&D9uO1BO@OIl(bZ0a^ zCOf(6F{(%2$589woQwn8S16CLwP#Q7AF}g&p0)tcxR^5zV9R71n0z*}C#-c(3BEg9 zJ1_S&9mp65wa9pCmk`_!S0XFSJxiXZRT zg6o9$!8kYKPnD;}$LK>v2&=Y{>%73KSL~Im zvu2*&mV9)+#YwIk{WGowzZYKWn3s)uGP8oHxc>$s z0K$xF&ewkhHfnz+O0S1$Qqdzq(Z4JF9tE!6qCih}K$r(hUcD31Q=w0Vl-@~wNxmP% z{pDC%xEH1U6CF|MF2L3=nuKuwgJO?QfhDgu8dX|(seQVB*6KtE7DQ9G9_ps@hBAZy z@_KTLx=V#5QTKMVgp{MWY2+7UH<6h+bKD*{ zPYTf#P%lxR)hwQcuE9K!=DVS1gWK2(ARMIMz-U*gtQBPw2=_5t`i;qNAPC_al&8|n z8Y8?{73IrpG6z$X<9z_Vm4peSb&2mC`)z)ztOinH5QK%DhqW<4%E{|X8xSON4=5#N z%L0_b(~rVlSMPE^0&%U7r1=FP?NS!&8 zZr#iOsi+Bt7mQk7UJS6=k`t*${`56Ko5Pq<=Fveg9sH-2;Y03gF#-E;8Vxd z@%SYeUG@>=ia9cUdc2s%Z8vw|b9zgtLE{XN zYfv=|$+iT;=p@fTXh9cHVdj3|c1Ks58s=TU1*&(PL2VTTc&1M-8UYI9c1GbUV9=%; zqY|~(4@hukm5+Ob@vN)2)%RP#?g?No{9I+Uc|YkG?a@Jp;P?-2UZkQCyHNkCbuKk87_yen47EA#rAA3bounE$aJ0OpIR8{^>%I3(CKv(tpITd7ekV zxpO;RK})&Kn0e_4Bd$0~59w9geZzZ07cSn7$0YP=pfI{|0Txt>{cq4fD!QDp^}Pc+ zi_idUwU(o)K-vVb=6X-4v=QYXgPNx5o3a=QKt4?TUfmRKDn@;Ar>yhSfB11T#f*vp ziM6TLCUZzJzC*&gPKEc!6Xp{raJ7Wi0++t(;EPCr3ork%zHmEs97^dL3t*6FLix+} z5m)+jv;_wngeM$f;~cwCN?0oqhM?tC>=T$iOOo(u6)}qAbCIp~@P}sH+3e;;kV3yX z{@4Y`{L3cjX>eHNoH=mER0RmwFM!PDM{9tV&zPow%>O`S8080|o9wqxF(D*%ZuJX+ z>z7JAYcns^;;AgN4OiO4_=xHGr*wvgic;^abG6zuhsudaV;*YnheRn2acg3G_#B$Q z?#WRq2>)w}!-LC79>%A6NDI8S%#=%OyHN1^Pcolb;7j7rHd7v8qQ&(u+Jt1;ktnYI4hC z0)*AAQV#DI-=kE!+uVW~>#wdc&MoHVMoQO?8&BRun|v-S+cA4DCP>XAQ9cuCFq(%R z(qa^J5ToL_@;Sjs8C)ydrp&O+n2tl9tWv4MqF$;IOKP^vn0lHi|1w2tQU%Ipp8soZ zHgo6K%wgVr=hE+-I8;VA^Z`9MU*x z3UkEe(@)r|AG+di(=FCh3(o~Q97LvHmH10V_+MsLBT!ID#IF;H5n>2YMZfA~4OXT> z@zH%QE~b?KTuO|-Cj^5gI7s(>KydiLma264eWL?D2K6(REU~U1(vGAUCSo4g7+c?y z`V-iwR0IN0=1@q4Vo=waT++Nz@jC{orJjCOvJ>Op|k z5HHd7DISY~COQo2=OGiIdfC;X_%i~5Bqd=z(t#=p<@P;^zG&CP`3y6}x4>2Vsp7ec zLNVTB20g6}=LRnk*GA7iy}-{d9_~99WnBBNXZ2)b#cZ!plFzz&XhR~7FgRG>VC%^| zZ;EDf!7
    YA7d(n@_AT1GbFHfacn>?|2Zwb5ft+Y;;4*2I`?l3?@kH7t!nw&9=R z*kc<%e?Cr*EZ`h_I>KAS@z5}~h<*6^A$%;Wo7X002OD?0A;0OAxmMT$lRQzXU_zqt?)FMef4Ih zY~R`(|HVY3k+X#7Cq^XR*gR)?)(x z>GGPF-}Bu&VL@-@-?Z!B(0_Ih!t;h1N>lF);wUgt46)kEkaU%bQx-3Q zcGON0d$4)SoJ~v>TNkl&NAQLKfXJh!T}*V=#pW?IrPhu}ah|5?+_J8f5PFYu9#F2_ zqNC0HdzN%P%%N1jEpd;3nQ;cZL!__Xu6DH?xZb476m_6KGbPEwmQ83ERi(FD z`R?5dqZ@qT=W$XanVtz4%}?>f=BZo0fe9}w;}VSLx4;ov?}~zRJc9>99BDj4;44xn zHqFNv1I9)&_L^#auOLgj07Xxr*O~qUeUGZ#cS0kBjLr`Q>Z;~-C0TJDri^TPqUlzg z_MEiUiwO&43ANhs7rQ2PbtW3!FH`$|A02m4=m~q|lc(bzKhKn!`nw&|+OGl2IAJQ+^i~d5W(WZ6XPm zr<2{1IIs@MR_@3wg|c?=lEk*EE4eooz;JBs!@Z)9!=O zoe}iLSv+?-BA`Xev3q~(1b&bx0}(;3ZNnaVnAuJVF23efu?T;&El^&?r&Q-aiE9vK z9>m2AhA>Z+8$S25O}<22^IGz2Iopq7_I*}e`a(viqIA-i3RLyhhQQ~eA7_Yvgy z^&zf~0^QqnkoIZS2pTvpL>Ys$?{V2AW)PR}FZKh1CYakm!2fp5o(f0m!~qYy^3VzQ zK41mO7X0lsGl6cVJ)?@F{i?>!lS}kTEJ7glm0KsIY+g{G{OHc=pP1sLVum&A?c5}< z6}8iL9;{Bu@cF90@HE1h4eL1w6*CteuVhY8M<*)DW{i+um%)}ccNfD*UFpeP#JVQq7e ziJ#v~bjaYeA<{+rCk8amK`w%%VgfIhs?9qF?{vII1~q10{Nky8JE|1(;&}o?Oiq%d zfGi=?7YdS>Z;rtL_YkcOnjx^+aY76*3vry(0FnKJK(~nD?B|n5pR#F-o~!eqvTh@B z-hE8$aNXB;Cqb|&0kND5;Ku9vya!YOu@6GL2Fai_uHrsX@;(PRIbP(!C{aQIy80{t zaDFW6)AF_UP6Y#BPjlVAH{SufZk+7~jwSA52c-&S*#{uD%TWEYw6$>%VZfV55vv?8 zkp;KLXMQ;iu%dP4)f)3v`v{yWOv_UtXwPy1ZS67z>Qyc774~wZZo^fdrmhn!Ne!_; zgp`5ARqqR*fyi$t{2EoWEC*3@tOrr@zEpm%FJ*tsze9rShNB!@S8WRJPqck&m6%g5 zo7R5sJ!pkC41VluY6cX0HoJi78u$oS#${bL)7AjjL(rW`PJ;bqo*iLi7mpqF+9v}& z=HHat_JRXZPb7^Q5(oP``A43wn87T3tgZW2fs1XIFMa?H9H*XD&O*o0eJFe3+oKol z;~5zZU_!94g+SgC+kKdn$mZuluPhlBDZrYPn%=|8%~7ZzSb+ zud;L(Yau|^oGLXGA-euj(hILohxU~q%2ugUJjL!o=~O&L0Qy^J&x1wzRezJ%*98Jd zCb9Sh0+=STNCg6Ys!PL(Ra}58LG)cY>`s11k1a4T8}&JUKribL$$1AB?65`$3=9e? z-4B79=yM6{1YO0_=TeR5eE3LPx(!jmIe4@2c=%mt_+4W25@Ix6Av_5kSTBO?sf{Gi z*F?L1;I%~szoUY3;itV{`gEjbQVNbFTctDUC@U+I!TdjDQz= zmp!|Bq|t1&qSZ5ROFg;<&%Y5Iyj1eEZjSe8*|OCbxeO zCi)iq+GyuwS(LrE$@C~!x~?BPo`vTO$yyP< z{!ynw8if9Ltp-PR7b|ql52>N>!XUC}>szdk z3oepZA~nhNxp%J?hn6Rxc(yxsmWbcRhE^v6&0#!c<3;(1Z-&+;y557tqt>A~%#mQ8 znr9rq-BoSPF+oy$Zp;Q0$CiB0-jV?R3+D*S*PBsQ7)^+U{7H*}Ad#+k=?ks`T5K$W z(VFSk&XZONp50anccgU#gkl&vrjc@*l^+VFD`T12L(Zkjh11f{ zi5UDy;3!<0+DI2YN;(a%3x|e{bAWvbeR$%05oGcyEaF!;-;7b(VTFvD<&|k{ZX$1= z{O)tkbdw%a%Ldcf$~ay$q21@#X(j_E9xWzgow2-9e7oekY0l9m9{wg{lQFzu+`Hs+ zY0gR}9ug*F8_~S|?7QRxY0iXs_2h5(mw;7fHO;pLl8Uo!OAEa)cc-@-H9$;nAp>k& z#9o*3k_8HI*gHW^*#!PD9t#-D8L0=u=R34LBq z&;3s6Eiyn?v}Dfx=-pap+ewbod0g7@S-#_QzoKHbTVCShoV8W02FU+Wh&Zx$(X001 z$2hZF6hNNovP=6#zN%@ zp6I;$kDGUQ7RCBP_g?8L36l^zv865SXyQT3qG5+1*Ufnz@NA=^p@o>tf=_{dJJlU~GJKq@Y?-g)-}Nz4GaP*m>=a=4I$y z>1QtrBsM;G>cnR|ues0@im^1yj2TeqddtQ>@6@pg*qKkcd7~%{9xvLtG@88gUN?U> z$Qv6>^=$Ai)gOBtDfam=MLTt0)ol_yIm?G9E(DN5Oy@$p=QAcuI$~_!`#;qMPsj-N zRnZ1h&i!eUAbhBoHvAsNFQK2Z(yP5P#CK!0#Oy@kZC`bwH%R_Cz~}mU>E{!z{!{Aa z#w{_rhjuTkQWX~Bj2&$*gGG9xxlA9`>IvPoAdZF=XnXG)x|cVg3)8GkVcfsNCnVOk zDuPg?nNHZ5mFla9{{kK8f$vG@j{(Amx-oP00L0n&e~lVEQmq(xJO2Qh&UvbMp-2UJ z*|>|k0#gLxsXR%Y&3rVV&m3!Mc}0=3Eg_)KBf);q`@3tZYl`TZFS{#2=z5J^Q}S?r zO4ZNC<*rK=?rfPocB})Y1~L8eiY##c>l~=0WZ3nc1m~e@W{XgU!-CsAu)yCuFIjdJ zOQ`~VLo56G=XDu#-cg7AVP8PLo|RsYLMmg7Mh%0LsLBIkO|BJlE29J>FMe$u8O=PW z&249F6sN1+D>nn|TUvQa(teSI2E88Fs99H?SGAOz4Ivc3ZZX|{o}WnSmKvFq@MZ09dBm|uQ`9=^|?iY?-!luH=eQ}gqq2rU;XNCa%0 zeebYlGDd(|lPR7~Zdf@rL825FF!xL~7_i})0JqDZFab-g@`x~2gntf0(E5iNMTeIz zH|Vg%Z+)o$G>tdfsPYJP?@hxN^D^)gF#AMWGo}&%=n1SX+Cl(z&6J!t@U4XJZ@JUt)UVyw;eK{Vp^_%|tP{cvoZY7Qfq5}VI z5?&w^{PQX*V)!Rj#o>ohV&M)&Yd4mS$8C(k&#~4>x?W+GV;F^p@C4)SZMzBMcd^ke zcuS#EXW^a|i9I*lXb*`u+yI5dn{K3vNjnC%ASQ&`M~~CKMWK9>f)|(_qSLyF=hsz? zvtf_f`PC-w?CnlVK@!+cWh_&M_l(ADO>)Q+mthYlKg&JNX_e2G;7$u?vru{QWnRtF z2dmr2DZ8Y)CqL`w>%*PK+;_5$hj^!xoinz0*8TDm0q{oh%r6&ES&8jzL+kA^Xz4+i z&cX%Q`<-9~5q3vi0X*%0%)qx??ivdb0J?uCv_jY)Aox?E{5EEfv|L#qfC#UMC>?nN zd!kLlnK%S1WcSu&z#iq*F%UgsQ6)JHV;IRnBpuFfSW9D0=4dn?^b+GU${N|G-*<=z z)n%Ei7^Wq4Y?R1jNwpl=z<=q|C=mv4Z5XEIJ9dhQb#aV{<rN49dMuOi@cXzmOHfN77JYO%jkI`Wh!s$2`sEusW)$@j zO*_SJ-S6XQT&eq5V&N6%DoV}~@XwRponCp1j?&&+!>es9!SAu`F^$qf>Vw(3gr?ks z+%UG4ZxUdd@J^V(k4A|#60yh-0}P{RRFHIo#DWyx^Qt)G7q+TYqqKY!Q@Y>XLu;s7 z`15f#YVg#K(2`@P>gwP46rQKAF1uWUX5ZqLY77@24I9u4Yis?qm1X@gGaK}*rWpVa zY>)IL?E(UPT)fD@p4}^GcK^a^`gLta)19zp1`;&;U+H(iI+OuV+${uzWjU9dAm&qB z!@s+(Xxp>*&p>UrljN=BOsEl6ZOusX$&cB{vqh}e@QL8cGA(c}nzw%c8?p%5qMNX; z7s!1WzCWmNk8L{nic#OnaZu-8xO_AAjjV8?mrjhvg-Sg9_qw z@65D?I1cGs?jRSXp5}PoMkOKjf$dRIVT-XqM`jHR@2tMs_g_!CIm>$YKU2QDb?@8z zOj(e$^}YIbiau#X%Vom#Wu~nR-+oilXdU587rjyQrL@LuKhaEEgG0}6v>%rH7QQGC zXjLB*GaqZH`rA!@x8p)RAZFgzP#stve&JlqAXgu*Q<*hp4z?hzR|&S8w)-gMoCMF5 zrJSSTnWhvtr?DP9>&l5cdBR?@;A7|ZQ^_#O*5t>QOBh9#cb-v`IPPTYB>GD3lfzZZ z-^VgobFIqXJ)?f}tXEsfPv*CLSga}9W}Yham0NvnyQt`GJh@u9+TbS^3xg)b?@ej% zKHayN)ZTl#e^F1|gzU8)lTy(bM=YL4JJphVWNlL?xr0+$+q(@W!4viJ-JbS8H68uY z2*3`J(B(3F`mTLkH%HyJSRSH{fXhb>1{GH`0{} zFJsvc`iwHQForo~89a*@_elGb4s<;@p=&{s$;F7F$j0b*AA&`xurHKV#KNoDSb~j+ zPYJuwvD~qYID5;{(WyG68WquHh_R{iKYb$XdXDu`?3~uq54{tFHI7S#@~MF)_!X9p z7<%Qo8C9^BhZuUol7}BU)lgTpSa{`mAp9BnU&KB5$8mXs-Or(a9$pN8xQE_TDlGd$ zaYzce7{#^w4xTnx9Nr?F`uEEb2ncWEQLNu>5Wwp>cw$WX!Fc9yX#1?~-W`)_D0ht+ zZj7hJD$F;0#hzE~hT$ba7)5wtC`y}m0GfCEcAig6&$U4LqEJ?Go#O7V6O%^k2f4B) z!T6&muJ#oxc?}e@nG|)N=$c=@bzHA!#jJd5z0Ro-Y!+}Wc8gm+{W$%3|El7oO{7$i zPr$sGdwk^HQO7H+$n5dQ&CN-6qIy`Esjn0NVv_*HQQ~T&!QK;-nd_hPL^0k`w%K8N z3AG0%&2&aH2k+*Ia`GydkSiFO_P*&+m?b~(&Ju;%pgInmP#WkxabO>!_j>ZBd7>6{uDAHFY&>RMF8gVAP~6X0e|cDby~gs~xoWXD%%Mr$s_j2$DS3dz%Kyd5(g9FJpveLSIAkW z^ZGp$TM{Z*c#JX?eAGoU7bocfhs<*LJo^mAqir4b8vA-a{x7E%@o#5sN>AQf46_h_H+;Il}UqNYl0M%x_)Zu(J*}B0h&`;%r1FlCmjS;Kk*712sxIS z5{_14k6298MO`nOA=4b*h00UC4erQcppkH^HiSF=Jq`TE;XtgpeN^Qp{t?tl;j>!z zh;wBMVzHznhjI)m;&6%ms??{I9jgtZEO;<){pRW1v=_q`Pd-yod~KGz4Y4&!`xp*- z75uDj`_Wb+NrK{C2q=6$OrGW`Wg#d=X}>r|&UP^T;?<*0j}UJ$+pTGmd1iC8V}3hP zEj3a4Vut32LC=C?nSw(O*@%ODZD*N?!_HZzLzVpbZvrR3NNqI4e8=c-gOy7czSsQx zUgG(Eq?#$;x%aB1HYPd3ZgM$Y_$y};5xBpa^osH;6r__m6LYyU)F-=>JM&8&Tnd8%@D2w$p6mw&6CG?pcLFb(s#qn z_HUyh2_&Lu?Gc20_3E()dR3?QTVWgI9q)rYrwV{wn&M@$2S{Dd^!zuOH(dCdP3Lz6 z;#8}%Ebd8D!Jj?5kS>(MS6}gYaLHT^uep8dAa7-~nB#w-ElLC|s+$@ctJ*Zmm{`m0 zOJ|0Lk8EsacC;H+ifym7v7MIg;}V;Iy@AO=>T}>2tqHK0f$_>gK#}q|*OdR7AAet2 zVF>7-SM|n;%s{S4?NI^}+N4uWB#J9dn3Erc^^c}Wyvu;+!s-L#q`k)6s!TKTA_*=( z)htQEIN283$p+da*;k(H1 zmd_+|8?xf)v1!dEJ^QnaF?vZHC^LL*Rk&qW)LW_9ex{lCahbJ4A=bqRrk<|8Ct_zW za_YdKQ8|ifu<*;wZ-4QhM}u(>9r=|@VR`QV-;5jz2a+X^0b*&3OCA4=$uRpO4EgaC zh@2d!=MuS!zU7sA?5~)Cagau@R9sVTSzLxZ8LGbPRn^Kf9ho!~--z^%veF1$By^0f zXWsPa{%sze*=0tBU3E@Gh3%-|7lV<=T-Dn3-$q#=qldN)A&Nm+)HOEmM--+t`EW}ep%u$W{;LM$A<-=lTP6?@K zUq5C7rgvuxJ|@TX5912zw>7kBZ2|S%^yTU->h-lxY*PWNA$7ohcR+a?v`FLvD0*7l zWecsqHU3}qLAZGm3svNQEI5)hJ_~(%C2QfVVE{bE`A7JaJc_rzkL|An6+wrzZ@tHB z)ouWf62);<`uRM-g35rY5|GMw$5e9RZa4MYLJ{A6w$)qETP3|i_#I;WhAx?{ce+SX zme$xVQHYT!8-S%Ys^zGop9j5ej@&Kt(5G55CtN?4z4bUDR}fVwbkT+LLt;20*+{~B z&6GtHxJi)2kaVo7ItEr5OH>)-P#K$Uj93+2l7f>2yC>!?Pa^gl}pxlz_kOH+)PD5e+{tg#%)9QYiiz;T5ZpLHk3yG3UwM zOV-IaL1EjUZm=S&an~8ZIithawMdOGb9CGZvEzR3F0d070k_iqZGDYL7kv^KyhE@j zD_L1-mG-pGrp7H=Ngz{LwamR%jk7`4&=?Ml*S9daB)hTF6R}iC^MhK7S4(HOCALNt z7VG*C;%D@hB#TpWq-OC=O-M=9Ogq^N9gRAQ1iI4t6l(1;saysK+h~K&MO8f}^IlB1 zo#ZYQ;>o9VxrgA9afh5?8O1+%$fJvI6`qIUZTiepVsxs1RQj}9Qk-{O{DV)wtB!e= zWh|;_SyRC(Ro=D9{MQny>dSIszlS3WzB|A=IZUH?C;1xg8Iv=p5toM+?+#6NN=Ju6 zUM>Q4VBqD~Z&OFY3W^HkA%Hzxj-ahJ4OJe%pboD2PyUe{T=U8A)^6CIB6Q%$TVNfO zK|lTDHybE0H()ma&IBEU@Hw*ZWCQEcFW-Jxd(*S;yE1RQz(DUM-6@ax$DOH0Rb4cv z9~ZS3^(r|tcAiKQjXEH5?WfTPZBmV45Y*x+EZzb$uG-k1?L{pcmzBo zt=u}vouA3-VGbxAswjo3q>8a8H4zqedd;QlPST$fJ+FMQvs5OnkLP1F!E>0}~3R z`#ljA#4`$R-3&KgP@!l+2&jTTK{$AWg9^|0oY1A@HduG?s?HP^aZyEQ#lw=)MI~x_Epy4eR7-iTi-#od#|6{#y_u;RSt&pr{<&!SmR~OVr30TliOI{`YNm4W7e<1 z9^tVU_iF7Wul$y(I<2Mork;Wv_x)?zes0)WM7qgz2H@`G z6%C%q-@JK0obKYbr7{&@l*N5#=AP9WjY_Whz|vxg-PI=)4>DkU`**%R;J!OB$p8WU z!PDTeF{p619p*Xk@2Wz0K$e2Fe}zrW-1lM~lkqJ@-rw^W{?ohvR_y$-xWvGgE0<~CKiBir%S&C zeH8O&YTBB#f0mY%YdPJCxt2C5YcaEyOWg2zIIOsg1LkAl*D*&jkLH!OuzIT%z{(B* z*eg2^pgTSX6_Ufo@h;o{^HMw*Pl3I!t)wFM2wpLbb0-P$|9Yqnp*_}kAcmO!fJ)X= zQv26ez&7_5YL9hi90A3lwDgCD_{^>^+q3HE%b)(fw65|56T!)~ha!3;|F2ADAiK3X zCZ?om90J7dJwA@=-=JdRyk?GkyL40=@oF^IqU>bh<@o2lSgmrEcki2@HZwPWv`u9C zpw2_25-+W$@(VqL6K6*}ZwmL>2TrTEy|x+Lz6p_we$vzQk=mrW+>}#o~hkhttuqCVk(0|xsH8BUawTf10_pi>NUGQ$VPgY-rie3de8c4Z53Xj8YM{LXV zdsOVF7R!kox-Mt7=C|C1t?i!b1uBPM;RX17R1S*!@aureVH}>1|H;944P!+T_{;j{ z{(y~%?atKwkXACRc2xjm|?BIOnYv zhX7Z1o&U?8$UH8yQQCarFMiHqh%J;a4x&C9*G;YbYhI7V^)Zg&q3yW7{qmR@yve*y zer(}_{k&~RdzD+W*|zgp2SDUFqI~HZk8fW4`?v+yv&F~=Q#(eiJ0CrS^xDi-Bnb(O z^Z&T|3b-cU^=}K6P&!qR?k)iV>F(|ZY3XKyfHX*VcSv`P?(Xhx7|q!8&U22x^FQxC z+}pGJ*&eq0zT$i3?pQ@(CU>N=zqSP@xu^t)i))n`lVWn}H9pt;E1M#BM-Ph*^NNlvqdNy`FeAtHC(Zs0pCTw8PGbtOUnsgT zD$;vnI(%oZB5Rvxp&4fH)Y_lNwL48muAE!nF|r4f+}Uk|+ieECVc?Kr+}P;|1Tb%NYa@s9k=9RvJ6l%P=p^8D z?zZa%6vX3m0=zqSN~*m8WU3Kv{}H6$TYP$fy5%wx9=%cDoA-}ipR${H{xRxi2a-u2 z76CK)l%6nJzAW_B8=j&IfD70hsQ(p+ssW7uekc$Fcc*@>7R*(or8!N9IRCbxIb9{j zj@wxXF&$--E_V9r_x9SNS}s(vNRemRu`xAm)NO978T@&j`fxYAjs?LBXqYQVKHLxDHEc@xsB@?icyjrfSWpEleFc zU&dXo+-v9ZU1wz+8I#6Tr7yJ@DyB7qT9Kz=J+|K-N5iH=MxOFaj@*ly|*3{lB z1Ybq?m)NiK0y7C-Hl8ns-w51+MUT`*QQ#uT#oNU>RPQNL>;NQhS{{dKSEb5;fm0hf zK?j9xNd<*%0zMYtV+KBCC8p(a^D2vTq!ELu+e>CGokF5w;VW3lnTLj6QXSwNTO{>4fY)i73lmBxf@PvzNs+ zrVW}b@r$}G&*|-2RcX)TK6UR5I5jBIO_mIhhpHkSbHZHhl;#h)$8CJZIvy`&C|+!? zGcDVU$wX`ic`ww?h8<4po=z0E5Y8SuAxj5RuVZ0uNKn(U5@-Il=f{kqkw5*6si;By zxy!HmU=s(xcVb%b#I0l^<3GCfC z#IG%_2{tu}jB07Qo?5Oq6#DOmSCH^|Z$Y;@%gv~-MrVDAyow3POXq0X#&@ECt`In6F&ku|e{H@amh zje7Yw@nrjY$m;ld=-SC+=f0j7qSeSN=26evd*8?j7FZwqCN;HvjdJPW@e+O&;^kxf zndP)!x;CR<_3CyxFffhW4Gksbq^0+Rf(rS9f<6$(IbvY)2!7rnqj2^U?vRi^dfi_V zoiK;4C_%|wL7Fp-?oCwXNb|}p1yRG~#}F%V{`(ZMgh;iwBa4YlMekFH^g9v`jDiup zx7V6~B0k+-qhls6;PduJBxb)1kgIZpv0#!MRHYaRD(hSeP+a!^^dp9dau~mb{Osh* zNCzA?p$i8C4OiA?o;KZW_oI`Ty1;JN<&XkAIQaq|oHWartd0dBU;lSuU7_i>zHmma z?U@^>_0)Ii{kPxt3lYq0brvK$A<&70wv2y^d}kxc~$`lm&cC@<@r9 zRk)da`A1h?T*O3#)(dJkJm=>X>~_u%I{L}6?=p|xFa1ec%9|6NHCI;SylGSXm8{hS z0@y>60zHU|R=PftV$;dw>QFkcJk{HR%io3Gzco@&Ph?$3aNOw8uhlina@()fN>GnA z6G!@N8iQ;kA+BJiv2}UT8@76feE2SYmayTa*xVCfcB-P#NE5cYb@?y<`Lkt!{lf{H z^)^sc`+xmjEk3gV!gIVo1Yau#V%*yLkA&4J5xuShEd9LG_�mpl9u$)sJR;|G-rS z)#GY<+#0(B5dvym60f4me#9^p=bG+%^8494wpPERsJNL&Gp_T_t~L`xPHvJR?_t$FP_Ymuq}zUCcXc zUiULGzhXvfo1qdY;=?+M-+9KR-A#+@siH5tpRs^xh22e5p)}BL(`t zMW+`Ic#-DMEmuCBuM(@ek&e93tswy^zXxTcKRhR;L5f5ah-FNmoDINLZ2u|N$Bq&p zgq(aSa)KH4205~l@Z3eNSoIM$MBY!z zI`SU~N9?9VK8WZ}(_p>ZPI@1ov?{{mT}5oBK35E$UgdXAhO-MC+%cB%c7%ARgPU8K zg~x4s+MvDoEwCGS=Q+DukPDn;9tw}AfwZs4XTY;R9P;Pp@xw(Kco5aU$$P8Kc>iud z)Wt>rUnibCDd%)^Sl#9CF<){W6uYGU1M9Q^k0tT0pCy3xD~^LJ@TRQw+P^Vf*}pN} zDRGnP@x(@nhV9HwQk5A&-ZVFx;42UI1xitBmBLgTZk>4sITHix#J&WA{7XSMZyzZ{ z?gH8ArkcelM~9~9v}0;+W0%>gaiUM>hA!-f@qyifG?Z&P%~(||un)Vr38)eVKJkWp zRQ^ivDak19YlRB>xwP(wL^L(>%u%?0zjqBp>`%`9=8s72G+!)@=KR%2&CATgz_00h z*6G2ORfXL7@8msQw#?Fmy*h2f;u;Ju+@i;@)$h<=xf1P2fbZdKA<5IDwEO$3TQCKs zS@k_Q8nZV%6LuO7_gbF>{Q<|I6z%-55tahrRm;W}A?%a!RjS)ZIs392vnroOVb1&b8JwdZ}YE5CR+_uV@ zMK>mEGWsYp)nfJM(P(NoZBT6ZVSl^eVO=!V(wbxkhm}x?^ihB4!~T_cewE8O4!Xn1 z&VH;!KKZCMrC4c|mS3%kUyIzed)|Vs;dj9H--hmd7;-#gDTJv$3}RVKyIYI@in9-J zQEt74y9UA|h?0E(TS~YiwDou!EK~PCX2#PS;OQ6uHY8g32ckTwH`QIffq_wYO|9+& zJzH<^tyS)T_k^sKi7smZB%rNEaWw`zL@-8iUw>#6H*ddGM5Vzx~+LYX8 zXA!Lt1>L3$`rYmEmBaZ;>vwGR*7AwZNV{0JV>(X}f0zsuey`6@KvV5tl@6p@=Mox> z@km2t-d=scr05dMJ#(TUi#d~_Ad5Y_krt<3Pfv_geG3K|`8JEE!G0iWkV82!?ImyZ zD7IqHlqeh%pJ`~OE?9LmP5QYcBc2jsuDqeRTqbw7rXRP|3(`%7r_Ct{F3R4sTb1^T zPL!>^pKb9!do<<0zXN7e;l1NJ=CMtnmcMm1cpuJsEFeeQQbbK>ZJn02+`@QkPk`0i z%X(eF$>L&;3~uDLFN$_;0?73;t>sYC!U*6ry!Ht|^dF{&bN$&Cz{P*B)t1%7^yTmD zlV(!y!MRfy{|_V@-|%NvB-((Uk7v&}7}&VKdcdh_iY_s>1OI~3h*<^g>del9yxwiW zWihe3^gf;L_7J*#6=vPz?Su!fyh%t&n1J$6MsLEsG4Rq6H3yG7J)%D%>7Re)@jL=B zYg%<&7C%~<@-f&yrCXd`75b0MrtNBHvi0%NBVK^`{u%Evsm1+>qw+Rj*U{Gc1&%gh z>1~3;7DwWj@%-O5L`>*eeh>JxTG!ZD=#tRm9x|lIg*YwcZyVCzR%@3i@zLX2CL#)Y zwH>0d)nE?3VS9NCp5avGP-Wz1)WMt^n6HW_YOS^=`U5}43nfZnn_ELeWKcaGU$~bB z5YIQK1!m9TYlr*yqnC5eL11MD^DTuhPqFVG=4@8~A>%K$6Pb_4z{R-1J+@xI+$HQ+ zna2S?x4@@#_KODMM?I-Hjr=czuW&AJ+XM-T)a&7g`xibUO`iG{3`FWFQAO#JrLGfk z)B?=p30Ll=HVRP~2h00{EtR%8iiyu@|w)DNk9`9pS{XrDL7o$^52*-=vXj_X5NT43r822u%fr5zQ%tr_CCI5Sg9kwGuy0k*>MVlkwIyemiw& zx3wR4`iVSxOy787UC|x3Jl$jb7{;{K%b-A@SWK(Hq97vg_pa&3x9HxeZ|F zW6hlgr6#0tBLTDFXSL|(x8T-oj=PSFUsJunmBasfEXsEwKqJ2*NJ`n$YzOP_N38$l z+6@;7W$4^utI=hxSHMxKwblDxx88IQ(4q%8+gc*FupVgwkNTG6*YD+zx`b*|61`g2 z&eXqNuhEJq;TQx-O3+l&vc-*eFv|-$Pds5jnmds~q7>xEDqUoAQb4mt$Fk=C*WcKa z!toAkz8V2#Hk&-wCYQP@50}qrWKrB_z;okcn3=Pg^Yy%sFmUzxvM}yo3gi{%>(f*W zXi^Q&T6Ey6Ocbk>8pmA~2^b6{HWsRC8+v@070mns5?6LlA}}8m9;o1teZkY9{u5n& z@wm=K>8cN?ZfLEpt*CBpaCfrK_BMAif*jn3cs2RD--3D;p!`Og*_4!Pz&vvEUAm2* zmdxTd$h`<2&-=%%jPjBJKq0M82iNOfmB_`IMUy<9=0DGsq`+`fi@uyTQB2reL?4t3{jr z4b4P(_Uxski6nN-Yo~lvy(Usc+|sPV019^7OY1^{iTsg3!|&TPAn9|pAJo=)+S`N4 zr4|7izelEWO-7p79qeSQqKy%@$uyW5sG`tt*y)kA>*vu(NWx~&?I*s9boPdiFY*Pq zrVy`w_(ewB!RXeztBrx0I-lior{`+J!65Nsv~{Ox%jE^RvqgwE+BZMrtxFs)(!JNz zB3MT#T%0l?g{v`sq2jw&MP$aY*<$-)k?hRi1a$^TBK^H$UxPUxdWZtOv;w=356|#I zlIUE6m|X&LdaNI@Lb`(nhHsYr4kQWWZwt3!x3Gt`wD5#^?fU2KPV8AI<R*!i%{ zWUmLnSWB-U*~!|)LVzO41zVO_ajQvFQn9r-H|NiRCj7v758aNa7sgie)goXyj=Y<2 zypkMIE%WkYTugrGC0U$uM(8C~obpynidjVtG53_Ydeb>J($9NO`s>eTgQ7uT9CH&o za=Nn6T;Z+QikO0CmN*P7LIHF(xoGQZWW?wtMoAMEm)vVp!KKR^ashPSm3Y4#G?+Gq zqTsEiggEm0DLFCZH7-m8qp~CDwk#@g@Y^~+IWeOj5a;KM=1qktLi_?6&g2+~j41Is z*sNblP+a<`oXpSvEMc|EFXDk$>JtNEWkq=v>nR^LjZ-Vf4s0snfyd}1BD4X_G;<6w zoT%&mOoRjRR2hOuFpu6$*`YOc-?1b-ROz4C`Zn;t-hmOEv2F?Eq(dX3@Glp71{!ad z4^;KE8Y@%jtJPq==jVtKfWyVs79KR+1MYvgyB&e1W6C^*$^G3IeWv>S`?3d4>+)4c zPEW#x)u6w7b9TYl{^J<9REX2P@LH6+tOp7P0rT|ctwEEA5`f$GD?3tyXGW9B%@Fs? z>HucN%&f(rnXzbPN3970_uya~TTLN32#g_GQ)pCPlt3vbcN1Ct48^>ki^f&7dh0Xx z=jWRCJ~z%0X8rABeSuAEzst45e;GAYzmGe0`w$1(a8if)&l=ou>i*p3?|UotYw>Kc zvQv>v8v4aq9ckSIe*Ahh{zIJLtvLKStFe3~wW&y=o(P7$AeFeF?rSl!%#VIV@ulG; z3&!A0FBgv5c~tTWCGiT`^Db@#Oo(ul3yRbsn$QaRk@xZVb1_3(_gmmMW2p^y4|tbB zuch44t+y3S!3zatXU$bD0-WtmaPoczC+}LNG9x&7Z^D=HA3dqh^aa-2p40Tm&;rK% zD{If%Dt7qyU|=RMkxxx~wWC&rvasGVc`{GNJ0g=+z53xBTyw~y$f75xf@4+BW1-!T z^H~3WW%BKbZ=n^VF4bO$4XiArI9_eb&(;gS_48#Bz%v04EN^VVk=~!}WUsA)+VcO& z^!dkVe);?s+}1L-{F9@(4Dxq&E#v*|Js4GC3=sbQbqG8KHyJH&)BzVxsGgl#;;OJ# zqF!$4kZmP=6v2mkG7A{rC2`ftBXLz5K0M(=5I#1XO}u|CpyVv;-foVW@tJ9_6!1zsS7xkP*)tr=zwg%)uA+QcbUgCYcD8 z6_{$2&Cq&MU=Jt>rgC0I@$n2k;1=xF52IYAaOB4q=Lv`qIA12|7D^Z9RyirT+@IC( zkT{LgBw2h_guFy}{z$(c$>$_Wdu~#E(TfFQPna+rP-$(RFEUNoK9JVY+-cTg#oc8? z>Ji!3i8}hptl+MO(IKJW9*@lVPEa_3FCx$D^Eu|{(5}#rUOIJ z&k?KfCMe@)&Uf)-zGiw5oeLgc44xVh{@0%bS?t|ITG1W-V$RH3(d=!KaFoE*i1_QJ zo+=oX1LN73qJ2pTK=}3=bO^_bdTWU-J+Qj~C$AtW^ZT9xT1`+`xkJPT6D}VuqL5g9 zIUQm# zXJ`5f_d)LQ>v%Ejv}-S?7vSXP;(H0K>aJY@%L^K?-f=kH5&adFaJqX0J$yoc^4YQO z1@?`L;eSpr={FO8nuGBZQC|{cKNqfp+Fn$l@ru?0jHWdpaS0PSC`d+3Z|Hb0WH7wd zZ*V+c9^U_(M+**Z9I%I{O4uUeNVG+(isThP(An>w;52-nC5b=N+`7;WSu%*Cv+o$b zjx+uqg2=hZ>fKL5DcV4Vh`4U575##?e|?v{UDEy*K|&mHbDlOT5~rt1%eyymHvZh| z=LpMDa!Lt!k-GW-@RH*AMqSI`=KjmuH}`>TS@w)K7MXFJNUYYhtYlgFr5~ z42)_uuJIPkH~zmOB_6QM=ij$_?5YYoiThw;oAyt3*b^JRvk#7d+V`|v1n-=Qe9fXW z(0oux`Z14&#@CfG3#=?b^Hx>No%AT(Qj56#-VCN~>1AbF24*}0d}99eK^eZa2$U@O zO!*9E`-8#&2W?kHj08MCCp@2;Wmwt;f5QR4jdqj0iTPvqy+7`u)Zn06S*dlfP_dbp z_5Oe)XOn!{eZ*!oAuxK|Hzxtlf5e32-qxxrs9ZE$JpZ$Ga4km(jDD;HNxivFJ~^rG zeBfdJ&+g6X@F5YxlP1Gk_dH0yTz&wIN;S7T0Hb%rt$TyJCnEqRcj-F{e;xBQk{GIe z2vnMkAd4zD>~6j>W`bIDf8Jh2bt6V~bhuB__eKHt;J2{62D}gZ1ZnY?_vD3pOIj03 z%8sIumu%Rnc4WMr4|Sr^mvkmM%pz{wt&s?$k#Q;czGlKw4D#))8RWQbwl}VEOE$ld zQr+a#b2J6j$+GV`?V}V#giQ;jyeUB{%4AXZDP&!KXTD@z{@;`^Fa%vyFtC1k9K4Yb z50(rD(;!k4LmSC*{Lk1W`d+WQkP|1bcMwSk%HD!&$>7KY90NxtFjb6T!CNtj@(+e2 zFSo7KWG|Ur_LyCkm|e!0UAmZU>nmg{dbkk?4zWy1lmeOMJl%TBtKa_G{?L9hOQnnfG;9cUwY^Rj8mG%AFZCB60NK#6bUeru=rgn11w4N5 z;j;xKV_vu3MARk0Qx9d>5Y_Gm0|HMfY{v^NV?gs z^x6R`E?|CCZ27aoFd`lzc|UuV;m>8WBQt|4(Ezm$y*XBH47csU71uIVh^7t}X*Uy% zQ;p*IsO6+5%Z#~1X*!J>n`E`@t}=v;I;KLlCP{-&g`rS&Cf$!bc2^d{tb~PaW>zC2 zIjLahDq9>YM?Z7tcl+yb0EN7i))L#Jq{PAIOR{qdvln^yT|BHjq}gVkw5GNzoS5S6HO8zvEK2yq9f&tK^T?6V!-R@%^&^k z?Twv`X1|zB!_Di}QBJ!2Q{DNas7+LABYmWjx)+ z`hNezc-45uH;ixeG&M9=o69S!xjenDF1FW^X`5FUcFyEZV1z7vmj!@}m$?(<1Q}r8 zQvht0u^t?D;eNXWJTX{$OPdyOdX+j2SjG+rKmK22_Q-$MHnBVzv-}UZZPT|~1i}5h z3im}+rJ`jI>E?y9kKi&zy88@xOGEkK&0~xHhGkU$=Mt#EY|qYw1MQ8)lfzYjor{Iz zB`~Y|e;jMynBcikpUeN7D}DnH`mF)Jz~S1&B2d#{-_5PvTH88;>b`YTv^>=*!-LPRTdN9#X>Oz(L!%|4#ARbO` zVCLwoWD?a=c(C8kNb(lEaZL?Qz=(;o(nIQ|b>A;BiOM4D4oxqdlCf^j!4kWYa4SQg{av9E{46OC6VN?%YV}0kGmNQaBbMrOuW~2m}@>amAkA8xihG z3(^geB8sNC-7l&&ON$`WgVSsdt*X;`huYgZGGX4Cr@7K276F+fU$2jZu-08>Enn&l z&big7(yN)Fw1yWZd9M@{=gXeEnNNCBZ^r4L^==iL*I6JRST$J0Dtpy;>7kygbDHfQ zOq%>)gy-LkqqH`8T|-H0geUzc+j8 z?iOou53c^0kPnN}+-4*;+hea9S*1H=$tQS8#3_a-Rec(rU+>jJ6aYqe=xVGNFDx3- z>#eSpPv^YFyy)BR2>mTLcrdEKG`6~7R{YuK7K4ZQ-G+;^x$2N#;hHKfvL!bU(J}W& zoR4odZYfIlWGT4!%b@}oL=Qi+dMvjtM<*B`QWYkUPS1G@#V8&xaULV4NQ+}?_mZEA z_2o{{-`{1BZiz(X3x><%Z9s0Rwxml6$S|-_CJl%KE6ar%9FwvPcBAy|5Ase8BwmZ$ z@_N&g&}XVo!u=HD!N_&w#59D!4H+?oJG6qVi)g1KT|$s#)E^x6f_%^)9PO7wrT-uo z6^T)H(F8{tH@Bz~eSw@edQp+XcIzN=V#<{i{)5+U%vbefSbmYwep#+@LQza)0gnk} zFS@7r@tst8WB8pzd$O>+8WcD_X|I(Td_HJ?IkN!PV7*9eb{Jey^%yms2pHCEVvimw zF7--c=QKAx9h6>3OZ2cco#+|TZeoe9HJ-8KH=QsYT5vX`uq_^1QPOY_GWoq6Q&X$B zvmmAsFB4O9nlaSmRXO588OaHHM2miVVP|Fn>VV)Hgc$GvEsTk z+-YtXF9MgZC^POzaLCZhtlR#alrQ$xN@H^sG{WWd5&Logpc-nm0Z#X}s1AS=L|x#t zG<6&F-Ws0G`;UV9;j;)dMPNQ{6LQhhume&4t&V%%bLa!Np|5@k5-Bo&aU29F`eCaH z(=cN4*jF<^GT$E!Bz1qJErK~SYb=D$k*i_QnWg;dompdc*yM%f%VzIkzuB_Hn|pTD z=-#rsxY@G1(AhG#@xxi|=*J|I;;mhBVroA|aY0Gfd);4t)n}K>7d&aL%jIVc@ktG{ zZek}DuO_Hx;015n3p)eISJO3NGMP3@xsbuUpMa(D#TMK>V7axmNA+)e@`|=qb?nkCTbaIv;;GO#bD#SF7JSX44j6 zGxy!5^Sf1N`NzJv-`>}sT|C`xBgKNfGo=q7o}z@T?z)aH|N7iE)w|k@;DSg~TlXi7 z`LCP4{H=>M_(4y%QCx34P;a#Nks9v!Pszt9PrkQj^aJBdbq=%g0VikZ{}9KT zs`}ZH3(za3wucCtB))$Q!a^hPI|f{j&uO=Au66)r+N2_!u>#1~6*fXff`%!U^p7XP zc?R26BI5|c0t9xIQ2b79rc1WFtW!5sw?IMnnu$LCgDKYB-wG&MNst^0izwCa1S1gatyUv7HPc|M*reJ z(@So(H!T2mj@dqhFpKhY!17CWX?tL@3Jd9a4o@ATCtDh?4vu?xdX=K8>s_`)=f zN*b2i+yd2W)1?acG%Rfyd6Y-bC8EI#65SUGdmBREZ0N>kd(G{oV0lD(w5vtuL7*l4 z%*aUaX`!Xrg{0eYavs5>;+2DbA~{9)ipFL*`e07gOU%QSROYkCiDmy}K*hVUS!161 zSXq@J=1wo3lS8$(ERLbXHdRl9F%_&?*(;Sy`)>QhR9y`?oGaM?4a>@81I3I5uvs;i zI@oG<%@f!^aWf`7SADNHWG5`seJh0jO5TBg@$XIH!(OK#ggudav#`Bl&CE0;U~nDY zgTba72+q3@f%VbsQKXx9(J;iN6qQ!F=Y0$YMot|$UDhK}zQd|N{BtxZB9)!!Q>#hi z!`=o+M?<5S?XnD_cIdC)a_Qp)0f*P#>ai-ZvYvtOeGWigMlLYid+^`Q`~LJfY*zn= zBK_Zq<=chU8?f&s&0~b<<(p%ptLk-7i+lb(*qE7ajwHZev#b1D2p-P7KORSBu)(+% zZYK$e>wGtsr5?sh(2-4U2%s{rJHMo%QCebcz2b?ijtd;_U2f%UfIg)21zZt5_#S{- zns|Uib^7oBEu%wuc?SO8woJ-X|6dMXi)%PpJcZ3t>5S{1qqP)&C}~1{0~`k95Vb7c zgGsPlt}V)%U1x@{P=Y61jaC&2v(I}_6#0ZV!`yN_6KwU;Wd_8)Dkrg~4>CZItplj+*s87Jdrp!j7ir9{FJ_DIon~HP)9Hy_o@_lf+dBNmSJB zOo)0dBKne)Ixu9dSCNUrmoxVxv2Wdp6@KzPj^XhNf5~$4&l->2a%bCjdCg{1Tt_9t zO(Lo7^S`gWd{60Zu{i--Cre27Rb^eO?!t=Z{su5_Gz?D(8=u#>1wDSb0@4;!ftyy% zC;zQd!$VmEmQ(8=T*q5@|4CSW-aA_ZFN1X3vvXGePE%mM0w!dNCf9R49>xcX?)z-*B}{LqMyJdsxn|UqC|AC1wcLF zTkzK>`2@ZNptj?#Wi9uwwy1woe6N{7ALdqJ5kKEfFuJE*Vhp=^m&pLLv(?5MCx-w5 z&O`r>QvPv578bUTL6X~K7T%j6F*7IDczAL0*T9}GBUX4fk9`P4v`9b4d~W{d2TiD} zx$wfkr+i4~hE~|bBZ+ikz(~3>4IM-51b)b9(WuFrkPXK#AAX02ayc2t{ldnW^khz^ zPaQC`kICq?usLXm4q#2nsb{l59jj;knG&mrEPB8O3KGplr_J5n!-jV|@u;CV(%Bjo z4ARqWJtSYQygh$NjUOQV7EZdR%|yA58w7R^YfJmQrQNRG8q=Q}=8&7!U8X zeK>O`X!rZ78Y1ZkI9q=0zJU^SLscQw)V()dYDUIe41 zr*k5--Gn|}bLR3F{6TGIy>o$uqWhq?n%v4$H1XcR3Nb~FQi(6A0)E~|>;g?E%MPPUH_OXVbRsUEJB1$=PaKB_WhIuT3DkpMzhycVxR}AQN^!*NO5Cd_5u|pd1(}2WQtI zdj+HbKRkB{qyT@KJ49+c^oM#1glxkQv)qpiU1OtC?Fr?yU@8Pe;s97J7MVZZJvMy5 z4EJVDP?e81QH@cR12g{|2WEn3JTf*e0m-W`fNHBB$t~p_MzF&jC;Z+Vkirq_ru^Vc zbu{+0XBb#w(9_h@(kX;Xw>Z^04$i^i>xhn5ElY>?Z934=!uiC_V1SF4)e8k?#xMUk z%Gh-vlnNb1oql$k{#V4d>6e?q%&ZklmlggKQ@N%+0eH=<;QR6Y>5fYaJg0t&O4@cZ znK_HGOLslOGbSeqxWfbXt%LnMqLGbMTfbg-C|4v%M5mMZBTSA>lEc0zixcc5hSvLF zU;2JSMCBStFwY4c!Y9?yWOA%xGTTE~$0i&)P|ZZ2=f(qVY+&&3{J6@;lIAtrFBGIm zr_~5J6Yf3QogY!BR?|*ll@3-EM7pz~d(1f#>CLUK@X({Hv7rs3EGQxqjgnX(OKK9W z(d~Xkl#_oqdQWA3`a1mtZFK`_)wf8??=1z!r9{^5{u71Imw5iD0fLt(<6o2X)&Weu zWpy^mbW(0Q({m(pW&x}R8H>P(3cJ<_TtiPHvTK2^9LvE2+&Fd}l^u79#KkLP8{Fs` zZHXCoe2pf{zQAnX-$(Bo>?@kxa_lQSjg2hx?Twq7HCIaB zH>m5*|4v~nQw~2W(V5fM;I}t1=_SQOl%NF`N(6Yqr zXr*9)+}jtJhRa7wFPBG<=>O^`8Q3f#;j1~@dO-E`(ZfUkKb!e&^t^Bkb`AdQ=(lnS z&5r-N3=xPBefpr676t>a?ll06ap^qd?xjeBQif0W)(<-2e#_@qc1?IpbIK@q7Su0M z>ad=RY6d^ertkjF96WoY$%GT8El~ZG;<%^8eZz`dT7ub!AVOYoD61#i(~>Wipm&<2 zqau%_!%tB-!Aec|({CJf*=kx6sEM^}L0x>dkzM9$O+C|^qBh=(~G#hU(6pe+NS;|IV~n`y!6R+N z4T17gAHoMk{IX8Yp2DA`z&xfA3i+wvXB#_>?BlZwc%Xqx+f=^`iCwsYh4f;Y-iye? z@46d4|Cul!v|rA2G%}KLVW(K0uu((Ia(`}QeWF`3TpCi-U|Ye#NncI3G9D+Aj}twN z>rg8_7&qiOAdV~ZV}5rC$#iE+qO+^)-8CL3aHBReGniX5oErSvgWgklZv&7eOixmQ zuJ&hFv7Uh*d=3DcrTYmnmB)#VOwTYMnb*B6wR&2|UP|E(0gkBRit|Eq%D=U6V;h$>#vS}S$B_|w67 z78}^;z`?=H_V55b2k^=99F%vPZVH$k++qR9Fgc?7O#ftPdfhvrG&KJuX!`vH%Kz9$ z=8vPx-jnQo)w<7IOuiQIm;GJVC*LT~U9X#f&1|P&b79-bad#RhQN-gU_njB-J-^5x zQ@Y3AvKUB$hRAp(lgcTydrbR!)UrYlc~}U^>WNQMy=X6LYmZ5DHUT#Sl|L zeP*c92_lzF%{VylF`RA%VxCc$ni*QmnCi~3?DJmogWF`*c0krKoV9TKz?s3;s^kpJ z_>Y-D!>_Ya62qa!G0>#i*?6bdn{O5a%TF}wjpzgpURl5qR`tDnJ}m!U>iK_L$>5=! z6vC|}-=?LwrN!reLDv{3Y^7=Sv5bm0i{3TRJL6G@*ZPv5H>*1f{%cPcQMTT}^R!j5 zmsT9<7_@C%sJk+q86Q7X28ZNo+u4mUN!{H|EZMi07bOSm={E^H1Q`(Y?~HO=w#Ej> z{mOeyPEf1H8#b{gxU=Q^zI!jjwWv|c!zz%l;5g^_mgz&K%dGPlrD~ZaO+zqw^kt~1 z1Ig?8!TIwwH|p1f8|}!7Xxx227$pQ;{a!JeziFb6T5BIvMEkJa4u`-L*XKIac<$d{ zl}WXiCtSawj>Mge)}^0uElfB(oO15+mW0rDY3dQ?HFFFd`x~U{V(;8X9i8y--dq9B z&NH8P2P@F(#N;G%*45m(`@$Y@?>hRZM=E8?XQHmkVT3K2$aY7ag^QF& z>W4sO!T%}SETrQ}$nLNsMZTGolp8H6QbQjnMp$qIYWiB0hX|s2munP%1RHv2AVxVA zXr4h?t6dl^6p~-ky?0h~prj5VF29GCFmoxH^>Fe(pmPG2O`hgn)=s%3@5?VJ2a4lq zJqs!o8=6Ta+kRVF^Q)|^l)i=gSd!9`RH0=?(Mn4HF~Pv4!1M%g%hg6%8N zvcCCdw*{u+12uzow##Z)v1H2;y?n*{B3J6*c?Lnll&~{xq0E3b8tQ!9}j-jV|o^t(4$JK&OFs zbWS9nIVn$^O*_*U1Y2sryhL@i|d<^~> zsQ$R5@z|v?sZmv%KcqPlUz0{>>5>FNaEG-nqsH)xmNTz#?f*Y~J z(xWtRdN@z)m$=n~TS;KP<6^kP1@Blqh5ol?CR5~N8L-^B32*X8vY<=UR=No*UQD0= z%U=3zZnV|lM@CfMFZieF4?%p#9^<5NhmZ%9PmX0g8Q31C`;`twb}Rn!lmHzR(o-s} z$%to;q$o&-pD?g%FIr^5s)3ayG$Q!@dd6Yi^Pu|I?>7Pafvi*n%`6Rf%|@~&T~Xhs zWk~3g&p-m_AU=s?VQLMXF?ncb5n->z=+vZn)#J!dO%C(J#Pf6W zD{Fid8o}<(cTu`@bTM(2-O-8K)}Lfw6|>fchmHFj@Lg#yXpYIftNHa}c{h|U@y=n; z@QrX4M@-2uQD_kaS)(Lf`8&KRu+-0k-}hL{b9M zR_A$GC_!uV)Oa{@cR^U8(r0almM^kzARlQE>?#hv3L^EqJzFcsB0Je^?^KM$dT>>S zCp9q9BVgJQda5INqMm;wM}UdBebYpGhI-K!^~@t|S})2svOcd^5sh%ST}crwhytT} zGkdrDSWY~3{59%taRK-**6VGz*H|#I4g8Rkd^$+Se4c1F?7~0eerWXjhIeK=FF(AP zlYC~!xwmoYaLTUEYrutT<{GD$ducUcaX737T*Vx}sA;*v0$O}Wpmb_la#&h8i8J68 zfJj;V&+47;n`G#bs9-ZCTFmJ^-!5%Q^ihC2XeR1ZO{7nz2v%ga`KZN!U6vrm( z+|-HI!Fmg`qa}gOt*J}qTQHo`L7rvLE)%;~w{adReb^Xdoa z8L+xC-`!)UYH)i591X!v7lJmHs((dlYW|uF5|W^;yq49@zg{@{ohsZOa?~?vhY9g-@k#PNyUpxyEWLzMb&Wc5oN1VDYYWYHgA&!8kY$LCAWi&E$GL)F8 z15}5lhOO?BoVTt*Jt4zG5>{Y$Ib(WMV;c|3zoCBpkBO`2cM*u1nR@E0cKkT_`Bb^) zF~+b>By!ATh@0sSMR-+lp_9c*_1m;V&m&LdbjRLf?>6d*A$KRko|0dp60+Z?59;0!#(}q9~!f;Hb^o${r>JB6DK>#Npj7gup%O**T!JNlw0# z%^j_9EsaGDv8h^7?8P~dmCjyPtFIknQVFS3D($(Pikbi3V4=Ui3p9SS+wa)u&V4w_ z15543jp%8b^M6~p*SD_H;Gc89i+F|l0qGXp^EN!Z1E|4%@u)YQz*8Lu9FF|{KOsFP zypnl%=6pH+z1EG*{L0^qIA@N!JeOL4R`OvlZVqCXWno24kV&>I91aYc``s<~nL>zu z@^}~RyH}ZjUVSo&PTx_G{ds9&kchlrae}Uc@mPu9B~@`SwQrn2gms zCI#_!5Zq;7+wt|B`bDl8K^0z0tZZNt=X~P4a3cPi!h4s8b`;oK=a&(o-mxgi^vUAl z1F`Wf-gp9~v0Jwz@z$+rykF$*yBe|A2x<3Wf>f2?9O%mZvIVIi=KSO@rmGTYG$dld zp+z=tRD7NlL8q1cCG!syI8_S1(&%+7``8zH)+qWT$n)23o&E z-3)v5Flk9Bt*{2n2isV05_DRTr_F)WALE=~9p5AiBW633cihE_6=Gub2Xw9q`)NeV zxP!5Mdpe{9%OB$ykp;}w*@>xIzijKIUNFeql}X((O5T-;-!bksR;%eiN;UzE{fHa> za(nZ;jqU6CZHO5M?vn;x*kql44i^ubNq@vc@e20;q*$f{QtP|l{ z_Jb|)eMJ^N6dkex8&&hgl3@}v>g$mPU3Wb@($UpZ!Si?kS*~T^spZV2nps4+-HU@o zps?HP>w#e9N`T`XzD7lr{b@1By_e3XkZ883Z5KvkEo5wscnR2Vc@3tG`iM11g?ZbvYD@t-D)o`-&n_bER6V`f=YqDpHm7y|krF9Rg-FO|Z z0!d$!vA@@;{!*srxQe*guSTi~_d#^r4K;j!7AmnGapw$>&=lchB8k=wX8wkpI`oDG zt7o>dGz_G^QJ)SuIUiVJke?HxGTYRA6@r1{Gbz&*$kfip8G20iC4_Y zttxSR{Bm4v;D&YKH&^o5X3(C=BL8!OsVV&r>1*WEPp&xM21#jeyimr zYqV_gx+rGJ!B?)L@?u*}j?L;vPdQ2*bA0(^IEHZ{?NU+=-%U5U_vLG{7Oj__av&C} z1|xarCsj3T9o;+>lxuD6i&W)m5kQgEBLSFk(hYM};Sp>67R-ok9wXqOC#Disjv%4N zSZ<_-TVVw}(aAB{1==vu|D z|K&0Q$D=`pmd#(Kz=tsfo&3=Z_ID-=(3hN>OUcoCU@!L@!-aUkPQxUA@69?y z+uCr9tTU?K@++1(VHH-s8UeT)*_H}##bw~hAB6cL0Gz~DT(sc|?;-Hv^aGa%z_V5x zK~o<=ezi6uooVg(Zg^(RawTOC6U}nlkn($aFJ#S2%=dy}S>ekKUU< zz&UpE)*I;>5;7s#P<*`24Rl8B!SAW>2at)^_GREKs#^QRK*-bxut(3wG9UKof;klX@ zZqEZXUPerc(6-Tvj0OiL$su3-_U;ZA~93#lvs()Vg-Rr6P zS};K@%!S@$O#W~hS#>tNjfeleZ;+Y#_WjHUY%3NK<*eS3r>Rx4ar&I+UJf|l#07~jX z!0|DmEgXsF#Pt>21Nm3x&PC%ef`=VI?^n`)Yv*_Fx1Xo2a#T~v`FSRZRI|*x#6wrL z{olM4D(~LpcDjIk1hO8k+R49=qChmb%U9iB`1~e5c|uOQtoLRUk={y5{R$df!9)l? kUM?%OQEh(=A(|0BnkV)>9{+p13gZakV+5i9m literal 0 HcmV?d00001 diff --git a/sandbox/servers/5.7/my.sandbox.cnf b/sandbox/servers/5.7/my.sandbox.cnf new file mode 100644 index 00000000..5cbe3f5d --- /dev/null +++ b/sandbox/servers/5.7/my.sandbox.cnf @@ -0,0 +1,29 @@ +[client] +user = msandbox +password = msandbox +port = PORT +socket = /tmp/PORT/mysql_sandboxPORT.sock + +[mysqld] +port = PORT +socket = /tmp/PORT/mysql_sandboxPORT.sock +pid-file = /tmp/PORT/data/mysql_sandboxPORT.pid +basedir = PERCONA_TOOLKIT_SANDBOX +datadir = /tmp/PORT/data +key_buffer_size = 16M +innodb_buffer_pool_size = 16M +innodb_data_home_dir = /tmp/PORT/data +innodb_log_group_home_dir = /tmp/PORT/data +innodb_data_file_path = ibdata1:10M:autoextend +innodb_log_file_size = 5M +log-bin = mysql-bin +relay_log = mysql-relay-bin +log_slave_updates +server-id = PORT +report-host = 127.0.0.1 +report-port = PORT +log-error = /tmp/PORT/data/mysqld.log +innodb_lock_wait_timeout = 3 +general_log +general_log_file = genlog +lower_case_table_names = 0 diff --git a/sandbox/servers/5.7/system_idb_tables.sql b/sandbox/servers/5.7/system_idb_tables.sql new file mode 100644 index 00000000..c97f5e6f --- /dev/null +++ b/sandbox/servers/5.7/system_idb_tables.sql @@ -0,0 +1,149 @@ +USE `mysql`; + +CREATE TABLE IF NOT EXISTS `innodb_index_stats` ( + `database_name` varchar(64) COLLATE utf8_bin NOT NULL, + `table_name` varchar(64) COLLATE utf8_bin NOT NULL, + `index_name` varchar(64) COLLATE utf8_bin NOT NULL, + `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `stat_name` varchar(64) COLLATE utf8_bin NOT NULL, + `stat_value` bigint(20) unsigned NOT NULL, + `sample_size` bigint(20) unsigned DEFAULT NULL, + `stat_description` varchar(1024) COLLATE utf8_bin NOT NULL, + PRIMARY KEY (`database_name`,`table_name`,`index_name`,`stat_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0; + +CREATE TABLE IF NOT EXISTS `innodb_table_stats` ( + `database_name` varchar(64) COLLATE utf8_bin NOT NULL, + `table_name` varchar(64) COLLATE utf8_bin NOT NULL, + `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `n_rows` bigint(20) unsigned NOT NULL, + `clustered_index_size` bigint(20) unsigned NOT NULL, + `sum_of_other_index_sizes` bigint(20) unsigned NOT NULL, + PRIMARY KEY (`database_name`,`table_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0; + +CREATE TABLE IF NOT EXISTS `slave_master_info` ( + `Number_of_lines` int(10) unsigned NOT NULL COMMENT 'Number of lines in the file.', + `Master_log_name` text CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'The name of the master binary log currently being read from the master.', + `Master_log_pos` bigint(20) unsigned NOT NULL COMMENT 'The master log position of the last read event.', + `Host` char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'The host name of the master.', + `User_name` text CHARACTER SET utf8 COLLATE utf8_bin COMMENT 'The user name used to connect to the master.', + `User_password` text CHARACTER SET utf8 COLLATE utf8_bin COMMENT 'The password used to connect to the master.', + `Port` int(10) unsigned NOT NULL COMMENT 'The network port used to connect to the master.', + `Connect_retry` int(10) unsigned NOT NULL COMMENT 'The period (in seconds) that the slave will wait before trying to reconnect to the master.', + `Enabled_ssl` tinyint(1) NOT NULL COMMENT 'Indicates whether the server supports SSL connections.', + `Ssl_ca` text CHARACTER SET utf8 COLLATE utf8_bin COMMENT 'The file used for the Certificate Authority (CA) certificate.', + `Ssl_capath` text CHARACTER SET utf8 COLLATE utf8_bin COMMENT 'The path to the Certificate Authority (CA) certificates.', + `Ssl_cert` text CHARACTER SET utf8 COLLATE utf8_bin COMMENT 'The name of the SSL certificate file.', + `Ssl_cipher` text CHARACTER SET utf8 COLLATE utf8_bin COMMENT 'The name of the cipher in use for the SSL connection.', + `Ssl_key` text CHARACTER SET utf8 COLLATE utf8_bin COMMENT 'The name of the SSL key file.', + `Ssl_verify_server_cert` tinyint(1) NOT NULL COMMENT 'Whether to verify the server certificate.', + `Heartbeat` float NOT NULL, + `Bind` text CHARACTER SET utf8 COLLATE utf8_bin COMMENT 'Displays which interface is employed when connecting to the MySQL server', + `Ignored_server_ids` text CHARACTER SET utf8 COLLATE utf8_bin COMMENT 'The number of server IDs to be ignored, followed by the actual server IDs', + `Uuid` text CHARACTER SET utf8 COLLATE utf8_bin COMMENT 'The master server uuid.', + `Retry_count` bigint(20) unsigned NOT NULL COMMENT 'Number of reconnect attempts, to the master, before giving up.', + `Ssl_crl` text CHARACTER SET utf8 COLLATE utf8_bin COMMENT 'The file used for the Certificate Revocation List (CRL)', + `Ssl_crlpath` text CHARACTER SET utf8 COLLATE utf8_bin COMMENT 'The path used for Certificate Revocation List (CRL) files', + `Enabled_auto_position` tinyint(1) NOT NULL COMMENT 'Indicates whether GTIDs will be used to retrieve events from the master.', + PRIMARY KEY (`Host`,`Port`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 STATS_PERSISTENT=0 COMMENT='Master Information'; + +CREATE TABLE IF NOT EXISTS `slave_relay_log_info` ( + `Number_of_lines` int(10) unsigned NOT NULL COMMENT 'Number of lines in the file or rows in the table. Used to version table definitions.', + `Relay_log_name` text CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'The name of the current relay log file.', + `Relay_log_pos` bigint(20) unsigned NOT NULL COMMENT 'The relay log position of the last executed event.', + `Master_log_name` text CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'The name of the master binary log file from which the events in the relay log file were read.', + `Master_log_pos` bigint(20) unsigned NOT NULL COMMENT 'The master log position of the last executed event.', + `Sql_delay` int(11) NOT NULL COMMENT 'The number of seconds that the slave must lag behind the master.', + `Number_of_workers` int(10) unsigned NOT NULL, + `Id` int(10) unsigned NOT NULL COMMENT 'Internal Id that uniquely identifies this record.', + PRIMARY KEY (`Id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 STATS_PERSISTENT=0 COMMENT='Relay Log Information'; + + +CREATE TABLE IF NOT EXISTS `slave_worker_info` ( + `Id` int(10) unsigned NOT NULL, + `Relay_log_name` text CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `Relay_log_pos` bigint(20) unsigned NOT NULL, + `Master_log_name` text CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `Master_log_pos` bigint(20) unsigned NOT NULL, + `Checkpoint_relay_log_name` text CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `Checkpoint_relay_log_pos` bigint(20) unsigned NOT NULL, + `Checkpoint_master_log_name` text CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `Checkpoint_master_log_pos` bigint(20) unsigned NOT NULL, + `Checkpoint_seqno` int(10) unsigned NOT NULL, + `Checkpoint_group_size` int(10) unsigned NOT NULL, + `Checkpoint_group_bitmap` blob NOT NULL, + PRIMARY KEY (`Id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 STATS_PERSISTENT=0 COMMENT='Worker Information'; + + +CREATE TABLE IF NOT EXISTS `help_category` ( + `help_category_id` smallint(5) unsigned NOT NULL, + `name` char(64) NOT NULL, + `parent_category_id` smallint(5) unsigned DEFAULT NULL, + `url` text NOT NULL, + PRIMARY KEY (`help_category_id`), + UNIQUE KEY `name` (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 STATS_PERSISTENT=0 COMMENT='help categories'; + +CREATE TABLE IF NOT EXISTS `help_keyword` ( + `help_keyword_id` int(10) unsigned NOT NULL, + `name` char(64) NOT NULL, + PRIMARY KEY (`help_keyword_id`), + UNIQUE KEY `name` (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 STATS_PERSISTENT=0 COMMENT='help keywords'; + +CREATE TABLE IF NOT EXISTS `help_relation` ( + `help_topic_id` int(10) unsigned NOT NULL, + `help_keyword_id` int(10) unsigned NOT NULL, + PRIMARY KEY (`help_keyword_id`,`help_topic_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 STATS_PERSISTENT=0 COMMENT='keyword-topic relation'; + +CREATE TABLE IF NOT EXISTS `help_topic` ( + `help_topic_id` int(10) unsigned NOT NULL, + `name` char(64) NOT NULL, + `help_category_id` smallint(5) unsigned NOT NULL, + `description` text NOT NULL, + `example` text NOT NULL, + `url` text NOT NULL, + PRIMARY KEY (`help_topic_id`), + UNIQUE KEY `name` (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 STATS_PERSISTENT=0 COMMENT='help topics'; + +CREATE TABLE IF NOT EXISTS `time_zone` ( + `Time_zone_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `Use_leap_seconds` enum('Y','N') NOT NULL DEFAULT 'N', + PRIMARY KEY (`Time_zone_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 STATS_PERSISTENT=0 COMMENT='Time zones'; + +CREATE TABLE IF NOT EXISTS `time_zone_leap_second` ( + `Transition_time` bigint(20) NOT NULL, + `Correction` int(11) NOT NULL, + PRIMARY KEY (`Transition_time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 STATS_PERSISTENT=0 COMMENT='Leap seconds information for time zones'; + +CREATE TABLE IF NOT EXISTS `time_zone_name` ( + `Name` char(64) NOT NULL, + `Time_zone_id` int(10) unsigned NOT NULL, + PRIMARY KEY (`Name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 STATS_PERSISTENT=0 COMMENT='Time zone names'; + +CREATE TABLE IF NOT EXISTS `time_zone_transition` ( + `Time_zone_id` int(10) unsigned NOT NULL, + `Transition_time` bigint(20) NOT NULL, + `Transition_type_id` int(10) unsigned NOT NULL, + PRIMARY KEY (`Time_zone_id`,`Transition_time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 STATS_PERSISTENT=0 COMMENT='Time zone transitions'; + +CREATE TABLE IF NOT EXISTS `time_zone_transition_type` ( + `Time_zone_id` int(10) unsigned NOT NULL, + `Transition_type_id` int(10) unsigned NOT NULL, + `Offset` int(11) NOT NULL DEFAULT '0', + `Is_DST` tinyint(3) unsigned NOT NULL DEFAULT '0', + `Abbreviation` char(8) NOT NULL DEFAULT '', + PRIMARY KEY (`Time_zone_id`,`Transition_type_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 STATS_PERSISTENT=0 COMMENT='Time zone transition types'; + + From 62d84e5dba1669c0435225640c200f686be87d67 Mon Sep 17 00:00:00 2001 From: Frank Cizmich Date: Mon, 1 Dec 2014 15:50:19 -0200 Subject: [PATCH 06/23] normalize timestamp data on servers with different tz - 1388870 --- bin/pt-table-checksum | 6 +++--- lib/RowChecksum.pm | 6 +++--- t/lib/RowChecksum.t | 8 ++++---- t/pt-table-checksum/samples/chunkidx004.txt | 2 +- t/pt-table-checksum/samples/chunkidx005.txt | 2 +- t/pt-table-checksum/samples/n-chunk-index-cols.txt | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/bin/pt-table-checksum b/bin/pt-table-checksum index 3adee83e..755df4ad 100755 --- a/bin/pt-table-checksum +++ b/bin/pt-table-checksum @@ -5714,8 +5714,8 @@ sub make_row_checksum { $query = join(', ', map { my $col = $_; - if ( $col =~ m/\+ 0/ ) { - my ($real_col) = /^(\S+)/; + if ( $col =~ m/UNIX_TIMESTAMP/ ) { + my ($real_col) = /^UNIX_TIMESTAMP\((.+?)\)/; $col .= " AS $real_col"; } elsif ( $col =~ m/TRIM/ ) { @@ -5815,7 +5815,7 @@ sub get_checksum_columns { my $type = $tbl_struct->{type_for}->{$_}; my $result = $q->quote($_); if ( $type eq 'timestamp' ) { - $result .= ' + 0'; + $result = "UNIX_TIMESTAMP($result)"; } elsif ( $float_precision && $type =~ m/float|double/ ) { $result = "ROUND($result, $float_precision)"; diff --git a/lib/RowChecksum.pm b/lib/RowChecksum.pm index a8e584dc..3d6e814a 100644 --- a/lib/RowChecksum.pm +++ b/lib/RowChecksum.pm @@ -82,10 +82,10 @@ sub make_row_checksum { $query = join(', ', map { my $col = $_; - if ( $col =~ m/\+ 0/ ) { + if ( $col =~ m/UNIX_TIMESTAMP/ ) { # Alias col name back to itself else its name becomes # "col + 0" instead of just "col". - my ($real_col) = /^(\S+)/; + my ($real_col) = /^UNIX_TIMESTAMP\((.+?)\)/; $col .= " AS $real_col"; } elsif ( $col =~ m/TRIM/ ) { @@ -216,7 +216,7 @@ sub get_checksum_columns { my $type = $tbl_struct->{type_for}->{$_}; my $result = $q->quote($_); if ( $type eq 'timestamp' ) { - $result .= ' + 0'; + $result = "UNIX_TIMESTAMP($result)"; } elsif ( $float_precision && $type =~ m/float|double/ ) { $result = "ROUND($result, $float_precision)"; diff --git a/t/lib/RowChecksum.t b/t/lib/RowChecksum.t index 3ef193ea..88403d33 100644 --- a/t/lib/RowChecksum.t +++ b/t/lib/RowChecksum.t @@ -126,11 +126,11 @@ is( tbl => $tbl, func => 'SHA1', ), - q{`film_id`, `title`, `description`, `release_year`, `language_id`, `original_language_id`, `rental_duration`, `rental_rate`, `length`, `replacement_cost`, `rating`, `special_features`, `last_update` + 0 AS `last_update`, } + q{`film_id`, `title`, `description`, `release_year`, `language_id`, `original_language_id`, `rental_duration`, `rental_rate`, `length`, `replacement_cost`, `rating`, `special_features`, UNIX_TIMESTAMP(`last_update`) AS `last_update`, } . q{SHA1(CONCAT_WS('#', } . q{`film_id`, `title`, `description`, `release_year`, `language_id`, } . q{`original_language_id`, `rental_duration`, `rental_rate`, `length`, } - . q{`replacement_cost`, `rating`, `special_features`, `last_update` + 0, } + . q{`replacement_cost`, `rating`, `special_features`, UNIX_TIMESTAMP(`last_update`), } . q{CONCAT(ISNULL(`description`), ISNULL(`release_year`), } . q{ISNULL(`original_language_id`), ISNULL(`length`), } . q{ISNULL(`rating`), ISNULL(`special_features`))))}, @@ -142,11 +142,11 @@ is( tbl => $tbl, func => 'FNV_64', ), - q{`film_id`, `title`, `description`, `release_year`, `language_id`, `original_language_id`, `rental_duration`, `rental_rate`, `length`, `replacement_cost`, `rating`, `special_features`, `last_update` + 0 AS `last_update`, } + q{`film_id`, `title`, `description`, `release_year`, `language_id`, `original_language_id`, `rental_duration`, `rental_rate`, `length`, `replacement_cost`, `rating`, `special_features`, UNIX_TIMESTAMP(`last_update`) AS `last_update`, } . q{FNV_64(} . q{`film_id`, `title`, `description`, `release_year`, `language_id`, } . q{`original_language_id`, `rental_duration`, `rental_rate`, `length`, } - . q{`replacement_cost`, `rating`, `special_features`, `last_update` + 0)}, + . q{`replacement_cost`, `rating`, `special_features`, UNIX_TIMESTAMP(`last_update`))}, 'FNV_64 query for sakila.film', ); diff --git a/t/pt-table-checksum/samples/chunkidx004.txt b/t/pt-table-checksum/samples/chunkidx004.txt index b3ceb684..31b89632 100644 --- a/t/pt-table-checksum/samples/chunkidx004.txt +++ b/t/pt-table-checksum/samples/chunkidx004.txt @@ -2,7 +2,7 @@ -- sakila.city -- -REPLACE INTO `percona`.`checksums` (db, tbl, chunk, chunk_index, lower_boundary, upper_boundary, this_cnt, this_crc) SELECT ?, ?, ?, ?, ?, ?, COUNT(*) AS cnt, COALESCE(LOWER(CONV(BIT_XOR(CAST(CRC32(CONCAT_WS('#', `city_id`, `city`, `country_id`, `last_update` + 0)) AS UNSIGNED)), 10, 16)), 0) AS crc FROM `sakila`.`city` FORCE INDEX(`idx_fk_country_id`) WHERE ((`country_id` >= ?)) AND ((`country_id` <= ?)) AND (country_id > 100) /*checksum chunk*/ +REPLACE INTO `percona`.`checksums` (db, tbl, chunk, chunk_index, lower_boundary, upper_boundary, this_cnt, this_crc) SELECT ?, ?, ?, ?, ?, ?, COUNT(*) AS cnt, COALESCE(LOWER(CONV(BIT_XOR(CAST(CRC32(CONCAT_WS('#', `city_id`, `city`, `country_id`, UNIX_TIMESTAMP(`last_update`))) AS UNSIGNED)), 10, 16)), 0) AS crc FROM `sakila`.`city` FORCE INDEX(`idx_fk_country_id`) WHERE ((`country_id` >= ?)) AND ((`country_id` <= ?)) AND (country_id > 100) /*checksum chunk*/ REPLACE INTO `percona`.`checksums` (db, tbl, chunk, chunk_index, lower_boundary, upper_boundary, this_cnt, this_crc) SELECT ?, ?, ?, ?, ?, ?, COUNT(*), '0' FROM `sakila`.`city` FORCE INDEX(`idx_fk_country_id`) WHERE ((`country_id` < ?)) AND (country_id > 100) ORDER BY `country_id` /*past lower chunk*/ diff --git a/t/pt-table-checksum/samples/chunkidx005.txt b/t/pt-table-checksum/samples/chunkidx005.txt index ae55d193..a6177f19 100644 --- a/t/pt-table-checksum/samples/chunkidx005.txt +++ b/t/pt-table-checksum/samples/chunkidx005.txt @@ -2,7 +2,7 @@ -- sakila.city -- -REPLACE INTO `percona`.`checksums` (db, tbl, chunk, chunk_index, lower_boundary, upper_boundary, this_cnt, this_crc) SELECT ?, ?, ?, ?, ?, ?, COUNT(*) AS cnt, COALESCE(LOWER(CONV(BIT_XOR(CAST(CRC32(CONCAT_WS('#', `city_id`, `city`, `country_id`, `last_update` + 0)) AS UNSIGNED)), 10, 16)), 0) AS crc FROM `sakila`.`city` FORCE INDEX(`PRIMARY`) WHERE ((`city_id` >= ?)) AND ((`city_id` <= ?)) AND (country_id > 100) /*checksum chunk*/ +REPLACE INTO `percona`.`checksums` (db, tbl, chunk, chunk_index, lower_boundary, upper_boundary, this_cnt, this_crc) SELECT ?, ?, ?, ?, ?, ?, COUNT(*) AS cnt, COALESCE(LOWER(CONV(BIT_XOR(CAST(CRC32(CONCAT_WS('#', `city_id`, `city`, `country_id`, UNIX_TIMESTAMP(`last_update`))) AS UNSIGNED)), 10, 16)), 0) AS crc FROM `sakila`.`city` FORCE INDEX(`PRIMARY`) WHERE ((`city_id` >= ?)) AND ((`city_id` <= ?)) AND (country_id > 100) /*checksum chunk*/ REPLACE INTO `percona`.`checksums` (db, tbl, chunk, chunk_index, lower_boundary, upper_boundary, this_cnt, this_crc) SELECT ?, ?, ?, ?, ?, ?, COUNT(*), '0' FROM `sakila`.`city` FORCE INDEX(`PRIMARY`) WHERE ((`city_id` < ?)) AND (country_id > 100) ORDER BY `city_id` /*past lower chunk*/ diff --git a/t/pt-table-checksum/samples/n-chunk-index-cols.txt b/t/pt-table-checksum/samples/n-chunk-index-cols.txt index f08f80ea..b8d9e17e 100644 --- a/t/pt-table-checksum/samples/n-chunk-index-cols.txt +++ b/t/pt-table-checksum/samples/n-chunk-index-cols.txt @@ -2,7 +2,7 @@ -- sakila.rental -- -REPLACE INTO `percona`.`checksums` (db, tbl, chunk, chunk_index, lower_boundary, upper_boundary, this_cnt, this_crc) SELECT ?, ?, ?, ?, ?, ?, COUNT(*) AS cnt, COALESCE(LOWER(CONV(BIT_XOR(CAST(CRC32(CONCAT_WS('#', `rental_id`, `rental_date`, `inventory_id`, `customer_id`, `return_date`, `staff_id`, `last_update` + 0, CONCAT(ISNULL(`return_date`)))) AS UNSIGNED)), 10, 16)), 0) AS crc FROM `sakila`.`rental` FORCE INDEX(`rental_date`) WHERE ((`rental_date` > ?) OR (`rental_date` = ? AND `inventory_id` >= ?)) AND ((`rental_date` < ?) OR (`rental_date` = ? AND `inventory_id` <= ?)) /*checksum chunk*/ +REPLACE INTO `percona`.`checksums` (db, tbl, chunk, chunk_index, lower_boundary, upper_boundary, this_cnt, this_crc) SELECT ?, ?, ?, ?, ?, ?, COUNT(*) AS cnt, COALESCE(LOWER(CONV(BIT_XOR(CAST(CRC32(CONCAT_WS('#', `rental_id`, `rental_date`, `inventory_id`, `customer_id`, `return_date`, `staff_id`, UNIX_TIMESTAMP(`last_update`), CONCAT(ISNULL(`return_date`)))) AS UNSIGNED)), 10, 16)), 0) AS crc FROM `sakila`.`rental` FORCE INDEX(`rental_date`) WHERE ((`rental_date` > ?) OR (`rental_date` = ? AND `inventory_id` >= ?)) AND ((`rental_date` < ?) OR (`rental_date` = ? AND `inventory_id` <= ?)) /*checksum chunk*/ REPLACE INTO `percona`.`checksums` (db, tbl, chunk, chunk_index, lower_boundary, upper_boundary, this_cnt, this_crc) SELECT ?, ?, ?, ?, ?, ?, COUNT(*), '0' FROM `sakila`.`rental` FORCE INDEX(`rental_date`) WHERE ((`rental_date` < ?) OR (`rental_date` = ? AND `inventory_id` < ?)) ORDER BY `rental_date`, `inventory_id`, `customer_id` /*past lower chunk*/ From 324a086d6a0f7c292b309ba489faeba7500e03ac Mon Sep 17 00:00:00 2001 From: Frank Cizmich Date: Tue, 2 Dec 2014 16:57:25 -0200 Subject: [PATCH 07/23] adds --fingerprint option for pt-kill - 1391240 --- bin/pt-kill | 14 +++++++++++++- t/pt-kill/match.t | 12 +++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/bin/pt-kill b/bin/pt-kill index c7e5482b..04f72b01 100755 --- a/bin/pt-kill +++ b/bin/pt-kill @@ -4007,7 +4007,7 @@ sub get_connected_slaves { die "You do not have the PROCESS privilege"; } - $sql = 'SHOW PROCESSLIST'; + $sql = 'SHOW FULL PROCESSLIST'; PTDEBUG && _d($dbh, $sql); grep { $_->{command} =~ m/Binlog Dump/i } map { # Lowercase the column names @@ -6567,6 +6567,7 @@ use warnings FATAL => 'all'; use English qw(-no_match_vars); use POSIX qw(setsid); use List::Util qw(max); +use Digest::MD5 qw(md5_hex); use Data::Dumper; $Data::Dumper::Indent = 1; @@ -7101,6 +7102,11 @@ sub main { $query->{Id}, ($query->{Command} || 'NULL'), $query->{Time}, ($query->{Info} || 'NULL'); } + if ( $o->get('fingerprint') ) { + my $fp = $qr->fingerprint($query->{'Info'}); + my $chksm = uc substr(md5_hex($fp), -16); + print "Fingerprint: 0x$chksm\n"; + } if ( $o->get('execute-command') ) { exec_cmd($o->get('execute-command')); msg('Executed ' . $o->get('execute-command')); @@ -7487,6 +7493,12 @@ pt-kill does not provide any safeguards so code carefully! It is permissible for the code to have side effects (to alter C<$event>). +=item --fingerprint + +Prints a fingerprint (checksum) of the query that was just killed. This is +equivalent to the fingerprint output of pt-query-digest. This allows +cross-referencing the output of both tools. + =item --group-by type: string diff --git a/t/pt-kill/match.t b/t/pt-kill/match.t index 9fbadf51..597b7fa3 100644 --- a/t/pt-kill/match.t +++ b/t/pt-kill/match.t @@ -9,7 +9,7 @@ BEGIN { use strict; use warnings FATAL => 'all'; use English qw(-no_match_vars); -use Test::More tests => 15; +use Test::More tests => 16; use PerconaTest; use Sandbox; @@ -137,6 +137,16 @@ like( "--match-all" ); +# --fingerprint option +$output = output( + sub { pt_kill::main(@args, "$trunk/t/lib/samples/pl/recset011.txt", qw(--match-all --print --fingerprint)); } +); +like( + $output, + qr/0x69962191E64980E6/, + '--fingerprint' +); + # ############################################################################# # Live tests. # ############################################################################# From e5a0dd1ace11930ee257d8b136532dd3af013cb0 Mon Sep 17 00:00:00 2001 From: Frank Cizmich Date: Mon, 5 Jan 2015 13:28:47 -0200 Subject: [PATCH 08/23] changed test query from sleect-1 to show-status --- bin/pt-mysql-summary | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/pt-mysql-summary b/bin/pt-mysql-summary index df639463..4734cad3 100755 --- a/bin/pt-mysql-summary +++ b/bin/pt-mysql-summary @@ -2397,7 +2397,7 @@ check_mysql () { # Now that we have the cmd line opts, check that we can actually # connect to MySQL. - [ -n "$(mysql $EXT_ARGV -e 'SELECT 1')" ] \ + [ -n "$(mysql $EXT_ARGV -e 'SHOW STATUS')" ] \ || die "Cannot connect to MySQL. Check that MySQL is running and that the options after -- are correct." } From ee5e46e08c9e3fd2561800ecdc8d8b91b8131e3e Mon Sep 17 00:00:00 2001 From: Frank Cizmich Date: Mon, 5 Jan 2015 20:15:27 -0200 Subject: [PATCH 09/23] disables only_full_group_by --- bin/pt-table-checksum | 20 ++++++++++++++++++++ t/pt-table-checksum/basics.t | 19 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/bin/pt-table-checksum b/bin/pt-table-checksum index 3adee83e..344187be 100755 --- a/bin/pt-table-checksum +++ b/bin/pt-table-checksum @@ -9131,6 +9131,26 @@ sub main { return if $o->get('explain'); my $sql; + # https://bugs.launchpad.net/percona-toolkit/+bug/1019479 + # sql_mode ONLY_FULL_GROUP_BY often raises error even when query is + # safe and deterministic. It's best to turn it off for the session + # at this point. + $sql = 'SELECT @@SQL_MODE'; + PTDEBUG && _d($dbh, $sql); + my ($sql_mode) = eval { $dbh->selectrow_array($sql) }; + if ( $EVAL_ERROR ) { + die "Error getting the current SQL_MODE: $EVAL_ERROR"; + } + $sql_mode =~ s/ONLY_FULL_GROUP_BY//i; + $sql = qq[SET SQL_MODE='$sql_mode']; + PTDEBUG && _d($dbh, $sql); + eval { $dbh->do($sql) }; + if ( $EVAL_ERROR ) { + die "Error setting SQL_MODE" + . ": $EVAL_ERROR"; + } + + # https://bugs.launchpad.net/percona-toolkit/+bug/919352 # The tool shouldn't blindly attempt to change binlog_format; # instead, it should check if it's already set to STATEMENT. diff --git a/t/pt-table-checksum/basics.t b/t/pt-table-checksum/basics.t index 056fbd1b..de2eb369 100644 --- a/t/pt-table-checksum/basics.t +++ b/t/pt-table-checksum/basics.t @@ -56,6 +56,7 @@ sub reset_repl_db { $master_dbh->do("use $repl_db"); } + # ############################################################################ # Default checksum and results. The tool does not technically require any # options on well-configured systems (which the test env cannot be). With @@ -508,6 +509,24 @@ is( "Bug 821675 (dot): 0 errors" ); +# ############################################################################# +# Bug 1019479: does not work with sql_mode ONLY_FULL_GROUP_BY +# ############################################################################# + +# add a couple more modes to test that commas don't affect setting +$master_dbh->do("SET sql_mode = 'NO_ZERO_DATE,ONLY_FULL_GROUP_BY,STRICT_ALL_TABLES'"); + +# force chunk-size because bug doesn't show up if table done in one chunk +$exit_status = pt_table_checksum::main(@args, + qw(--quiet --quiet -t sakila.actor --chunk-size=50)); + +is( + $exit_status, + 0, + "sql_mode ONLY_FULL_GROUP_BY is overidden" +); + + # ############################################################################# # Done. # ############################################################################# From 5251b00a9af778d99392cd0b98589c99fbe7960e Mon Sep 17 00:00:00 2001 From: Frank Cizmich Date: Mon, 12 Jan 2015 15:22:23 -0200 Subject: [PATCH 10/23] used Transformers::make_checksum. Changed option to --query-id --- bin/pt-kill | 25 +++++++++++++++++-------- t/pt-kill/match.t | 6 +++--- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/bin/pt-kill b/bin/pt-kill index 04f72b01..6cf4097c 100755 --- a/bin/pt-kill +++ b/bin/pt-kill @@ -7102,10 +7102,10 @@ sub main { $query->{Id}, ($query->{Command} || 'NULL'), $query->{Time}, ($query->{Info} || 'NULL'); } - if ( $o->get('fingerprint') ) { + if ( $o->get('query-id') ) { my $fp = $qr->fingerprint($query->{'Info'}); - my $chksm = uc substr(md5_hex($fp), -16); - print "Fingerprint: 0x$chksm\n"; + my $chksm = Transformers::make_checksum($fp); + print "Query ID: 0x$chksm\n"; } if ( $o->get('execute-command') ) { exec_cmd($o->get('execute-command')); @@ -7493,11 +7493,6 @@ pt-kill does not provide any safeguards so code carefully! It is permissible for the code to have side effects (to alter C<$event>). -=item --fingerprint - -Prints a fingerprint (checksum) of the query that was just killed. This is -equivalent to the fingerprint output of pt-query-digest. This allows -cross-referencing the output of both tools. =item --group-by @@ -7602,6 +7597,20 @@ short form: -P; type: int Port number to use for connection. +=item --query-id + +Prints an ID of the query that was just killed. This is +equivalent to the "ID" output of pt-query-digest. This allows +cross-referencing the output of both tools. + +Example: + + Query ID 0xE9800998ECF8427E + +Note that this is a digest (or hash) of the query's "fingerprint", +so queries of the same form but with different values will have the same ID. +See pt-query-digest for more information. + =item --run-time type: time diff --git a/t/pt-kill/match.t b/t/pt-kill/match.t index 597b7fa3..47be0382 100644 --- a/t/pt-kill/match.t +++ b/t/pt-kill/match.t @@ -137,14 +137,14 @@ like( "--match-all" ); -# --fingerprint option +# --query-id option $output = output( - sub { pt_kill::main(@args, "$trunk/t/lib/samples/pl/recset011.txt", qw(--match-all --print --fingerprint)); } + sub { pt_kill::main(@args, "$trunk/t/lib/samples/pl/recset011.txt", qw(--match-all --print --query-id)); } ); like( $output, qr/0x69962191E64980E6/, - '--fingerprint' + '--query-id' ); # ############################################################################# From b025c97fd742556592776eed3032d31ccfe8e64c Mon Sep 17 00:00:00 2001 From: Frank Cizmich Date: Mon, 12 Jan 2015 19:20:15 -0200 Subject: [PATCH 11/23] used ReadKeyMini. Moved double password logic to Cxn. Removed {ask_pass} from Cxn --- bin/pt-config-diff | 4 +- bin/pt-deadlock-logger | 4 +- bin/pt-fk-error-logger | 4 +- bin/pt-kill | 4 +- bin/pt-online-schema-change | 170 ++++++++++++++++++++++++++++++++++-- bin/pt-table-checksum | 4 +- bin/pt-upgrade | 4 +- lib/Cxn.pm | 4 +- 8 files changed, 178 insertions(+), 20 deletions(-) diff --git a/bin/pt-config-diff b/bin/pt-config-diff index f263b2de..1da10d34 100755 --- a/bin/pt-config-diff +++ b/bin/pt-config-diff @@ -2295,7 +2295,7 @@ sub new { set => $args{set}, NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, dbh_set => 0, - ask_pass => $o->get('ask-pass') || $args{ask_pass}, + ask_pass => $o->get('ask-pass'), DSNParser => $dp, is_cluster_node => undef, parent => $args{parent}, @@ -2311,7 +2311,7 @@ sub connect { my $dbh = $self->{dbh}; if ( !$dbh || !$dbh->ping() ) { - if ( $self->{ask_pass} && !$self->{asked_for_pass} ) { + if ( $self->{ask_pass} && !$self->{asked_for_pass} && !defined $dsn->{p} ) { $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: "); $self->{asked_for_pass} = 1; } diff --git a/bin/pt-deadlock-logger b/bin/pt-deadlock-logger index cc8eca2d..3a27239b 100755 --- a/bin/pt-deadlock-logger +++ b/bin/pt-deadlock-logger @@ -2639,7 +2639,7 @@ sub new { set => $args{set}, NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, dbh_set => 0, - ask_pass => $o->get('ask-pass') || $args{ask_pass}, + ask_pass => $o->get('ask-pass'), DSNParser => $dp, is_cluster_node => undef, parent => $args{parent}, @@ -2655,7 +2655,7 @@ sub connect { my $dbh = $self->{dbh}; if ( !$dbh || !$dbh->ping() ) { - if ( $self->{ask_pass} && !$self->{asked_for_pass} ) { + if ( $self->{ask_pass} && !$self->{asked_for_pass} && !defined $dsn->{p} ) { $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: "); $self->{asked_for_pass} = 1; } diff --git a/bin/pt-fk-error-logger b/bin/pt-fk-error-logger index 96d4e09f..c9de88e6 100755 --- a/bin/pt-fk-error-logger +++ b/bin/pt-fk-error-logger @@ -1791,7 +1791,7 @@ sub new { set => $args{set}, NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, dbh_set => 0, - ask_pass => $o->get('ask-pass') || $args{ask_pass}, + ask_pass => $o->get('ask-pass'), DSNParser => $dp, is_cluster_node => undef, parent => $args{parent}, @@ -1807,7 +1807,7 @@ sub connect { my $dbh = $self->{dbh}; if ( !$dbh || !$dbh->ping() ) { - if ( $self->{ask_pass} && !$self->{asked_for_pass} ) { + if ( $self->{ask_pass} && !$self->{asked_for_pass} && !defined $dsn->{p} ) { $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: "); $self->{asked_for_pass} = 1; } diff --git a/bin/pt-kill b/bin/pt-kill index db73976d..4ae40a9b 100755 --- a/bin/pt-kill +++ b/bin/pt-kill @@ -5158,7 +5158,7 @@ sub new { set => $args{set}, NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, dbh_set => 0, - ask_pass => $o->get('ask-pass') || $args{ask_pass}, + ask_pass => $o->get('ask-pass'), DSNParser => $dp, is_cluster_node => undef, parent => $args{parent}, @@ -5174,7 +5174,7 @@ sub connect { my $dbh = $self->{dbh}; if ( !$dbh || !$dbh->ping() ) { - if ( $self->{ask_pass} && !$self->{asked_for_pass} ) { + if ( $self->{ask_pass} && !$self->{asked_for_pass} && !defined $dsn->{p} ) { $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: "); $self->{asked_for_pass} = 1; } diff --git a/bin/pt-online-schema-change b/bin/pt-online-schema-change index 8b8f4329..09933113 100755 --- a/bin/pt-online-schema-change +++ b/bin/pt-online-schema-change @@ -40,6 +40,7 @@ BEGIN { HTTP::Micro VersionCheck Percona::XtraDB::Cluster + ReadKeyMini )); } @@ -3755,7 +3756,7 @@ sub new { set => $args{set}, NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, dbh_set => 0, - ask_pass => $o->get('ask-pass') || $args{ask_pass}, + ask_pass => $o->get('ask-pass'), DSNParser => $dp, is_cluster_node => undef, parent => $args{parent}, @@ -3771,7 +3772,7 @@ sub connect { my $dbh = $self->{dbh}; if ( !$dbh || !$dbh->ping() ) { - if ( $self->{ask_pass} && !$self->{asked_for_pass} ) { + if ( $self->{ask_pass} && !$self->{asked_for_pass} && !defined $dsn->{p} ) { $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: "); $self->{asked_for_pass} = 1; } @@ -7757,6 +7758,162 @@ sub _d { # End Percona::XtraDB::Cluster package # ########################################################################### +# ########################################################################### +# ReadKeyMini package +# This package is a copy without comments from the original. The original +# with comments and its test file can be found in the Bazaar repository at, +# lib/ReadKeyMini.pm +# t/lib/ReadKeyMini.t +# See https://launchpad.net/percona-toolkit for more information. +# ########################################################################### +{ + +BEGIN { + +package ReadKeyMini; +BEGIN { $INC{"ReadKeyMini.pm"} ||= 1 } + +use warnings; +use strict; +use English qw(-no_match_vars); +use constant PTDEBUG => $ENV{PTDEBUG} || 0; + +use POSIX qw( :termios_h ); +use Fcntl qw( F_SETFL F_GETFL ); + +use base qw( Exporter ); + +BEGIN { + our @EXPORT_OK = qw( GetTerminalSize ReadMode ); + *ReadMode = *Term::ReadKey::ReadMode = \&_ReadMode; + *GetTerminalSize = *Term::ReadKey::GetTerminalSize = \&_GetTerminalSize; +} + +my %modes = ( + original => 0, + restore => 0, + normal => 1, + noecho => 2, + cbreak => 3, + raw => 4, + 'ultra-raw' => 5, +); + +{ + my $fd_stdin = fileno(STDIN); + my $flags; + unless ( $PerconaTest::DONT_RESTORE_STDIN ) { + $flags = fcntl(STDIN, F_GETFL, 0) + or warn "Error getting STDIN flags with fcntl: $OS_ERROR"; + } + my $term = POSIX::Termios->new(); + $term->getattr($fd_stdin); + my $oterm = $term->getlflag(); + my $echo = ECHO | ECHOK | ICANON; + my $noecho = $oterm & ~$echo; + + sub _ReadMode { + my $mode = $modes{ $_[0] }; + if ( $mode == $modes{normal} ) { + cooked(); + } + elsif ( $mode == $modes{cbreak} || $mode == $modes{noecho} ) { + cbreak( $mode == $modes{noecho} ? $noecho : $oterm ); + } + else { + die("ReadMore('$_[0]') not supported"); + } + } + + sub cbreak { + my ($lflag) = $_[0] || $noecho; + $term->setlflag($lflag); + $term->setcc( VTIME, 1 ); + $term->setattr( $fd_stdin, TCSANOW ); + } + + sub cooked { + $term->setlflag($oterm); + $term->setcc( VTIME, 0 ); + $term->setattr( $fd_stdin, TCSANOW ); + if ( !$PerconaTest::DONT_RESTORE_STDIN ) { + fcntl(STDIN, F_SETFL, int($flags)) + or warn "Error restoring STDIN flags with fcntl: $OS_ERROR"; + } + } + + END { cooked() } +} + +sub readkey { + my $key = ''; + cbreak(); + sysread(STDIN, $key, 1); + my $timeout = 0.1; + if ( $key eq "\033" ) { + my $x = ''; + STDIN->blocking(0); + sysread(STDIN, $x, 2); + STDIN->blocking(1); + $key .= $x; + redo if $key =~ /\[[0-2](?:[0-9];)?$/ + } + cooked(); + return $key; +} + + +BEGIN { + eval { no warnings; local $^W; require 'sys/ioctl.ph' }; + if ( !defined &TIOCGWINSZ ) { + *TIOCGWINSZ = sub () { + $^O eq 'linux' ? 0x005413 + : $^O eq 'solaris' ? 0x005468 + : 0x40087468; + }; + } +} + +sub _GetTerminalSize { + if ( @_ ) { + die "My::Term::ReadKey doesn't implement GetTerminalSize with arguments"; + } + + my $cols = $ENV{COLUMNS} || 80; + my $rows = $ENV{LINES} || 24; + + if ( open( TTY, "+<", "/dev/tty" ) ) { # Got a tty + my $winsize = ''; + if ( ioctl( TTY, &TIOCGWINSZ, $winsize ) ) { + ( $rows, $cols, my ( $xpixel, $ypixel ) ) = unpack( 'S4', $winsize ); + return ( $cols, $rows, $xpixel, $ypixel ); + } + } + + if ( $rows = `tput lines 2>/dev/null` ) { + chomp($rows); + chomp($cols = `tput cols`); + } + elsif ( my $stty = `stty -a 2>/dev/null` ) { + ($rows, $cols) = $stty =~ /([0-9]+) rows; ([0-9]+) columns;/; + } + else { + ($cols, $rows) = @ENV{qw( COLUMNS LINES )}; + $cols ||= 80; + $rows ||= 24; + } + + return ( $cols, $rows ); +} + +} + +1; +} +# ########################################################################### +# End ReadKeyMini package +# ########################################################################### + # ########################################################################### # This is a combination of modules and programs in one -- a runnable module. # http://www.perl.com/pub/a/2006/07/13/lightning-articles.html?page=last @@ -7963,7 +8120,6 @@ sub main { }; my $cxn = $make_cxn->(dsn => $dsn); - $o->set('ask-pass', 0); # so we don't ask twice (password is already stored in dsn) my $aux_cxn = $make_cxn->(dsn => $dsn, prev_dsn => $dsn); my $cluster = Percona::XtraDB::Cluster->new; @@ -10485,10 +10641,12 @@ sub sig_int { my ( $signal ) = @_; $oktorun = 0; # flag for cleanup tasks print STDERR "# Exiting on SIG$signal.\n"; - # restore terminal to normal state in case CTL-C issued while asking for password + # restore terminal to normal state in case CTL+C issued while + # asking for password # https://bugs.launchpad.net/percona-toolkit/+bug/1396870 - use Term::ReadKey; - ReadMode 0; + # note: just including ReadKeyMini seems to solve the bug, + # but lets use it explicitly so we don't forget why we need it + ReadKeyMini::ReadMode 0; exit 1; } diff --git a/bin/pt-table-checksum b/bin/pt-table-checksum index 4f376898..ff1681b2 100755 --- a/bin/pt-table-checksum +++ b/bin/pt-table-checksum @@ -3533,7 +3533,7 @@ sub new { set => $args{set}, NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, dbh_set => 0, - ask_pass => $o->get('ask-pass') || $args{ask_pass}, + ask_pass => $o->get('ask-pass'), DSNParser => $dp, is_cluster_node => undef, parent => $args{parent}, @@ -3549,7 +3549,7 @@ sub connect { my $dbh = $self->{dbh}; if ( !$dbh || !$dbh->ping() ) { - if ( $self->{ask_pass} && !$self->{asked_for_pass} ) { + if ( $self->{ask_pass} && !$self->{asked_for_pass} && !defined $dsn->{p} ) { $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: "); $self->{asked_for_pass} = 1; } diff --git a/bin/pt-upgrade b/bin/pt-upgrade index 57803988..b130c212 100755 --- a/bin/pt-upgrade +++ b/bin/pt-upgrade @@ -2464,7 +2464,7 @@ sub new { set => $args{set}, NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, dbh_set => 0, - ask_pass => $o->get('ask-pass') || $args{ask_pass}, + ask_pass => $o->get('ask-pass'), DSNParser => $dp, is_cluster_node => undef, parent => $args{parent}, @@ -2480,7 +2480,7 @@ sub connect { my $dbh = $self->{dbh}; if ( !$dbh || !$dbh->ping() ) { - if ( $self->{ask_pass} && !$self->{asked_for_pass} ) { + if ( $self->{ask_pass} && !$self->{asked_for_pass} && !defined $dsn->{p} ) { $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: "); $self->{asked_for_pass} = 1; } diff --git a/lib/Cxn.pm b/lib/Cxn.pm index 41c8f543..f8515427 100644 --- a/lib/Cxn.pm +++ b/lib/Cxn.pm @@ -108,7 +108,7 @@ sub new { set => $args{set}, NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, dbh_set => 0, - ask_pass => $o->get('ask-pass') || $args{ask_pass}, + ask_pass => $o->get('ask-pass'), DSNParser => $dp, is_cluster_node => undef, parent => $args{parent}, @@ -125,7 +125,7 @@ sub connect { my $dbh = $self->{dbh}; if ( !$dbh || !$dbh->ping() ) { # Ask for password once. - if ( $self->{ask_pass} && !$self->{asked_for_pass} ) { + if ( $self->{ask_pass} && !$self->{asked_for_pass} && !defined $dsn->{p} ) { $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: "); $self->{asked_for_pass} = 1; } From a7e1975eeac32bec5a33d6c00277ce2b81c8bc9b Mon Sep 17 00:00:00 2001 From: Frank Cizmich Date: Tue, 13 Jan 2015 17:36:26 -0200 Subject: [PATCH 12/23] parse_options checks if HOME is set --- bin/pt-ioprofile | 5 ++++- bin/pt-mext | 5 ++++- bin/pt-mysql-summary | 5 ++++- bin/pt-pmp | 5 ++++- bin/pt-sift | 5 ++++- bin/pt-stalk | 5 ++++- bin/pt-summary | 5 ++++- lib/bash/parse_options.sh | 6 +++++- 8 files changed, 33 insertions(+), 8 deletions(-) diff --git a/bin/pt-ioprofile b/bin/pt-ioprofile index 41e3f3b7..5f73678e 100755 --- a/bin/pt-ioprofile +++ b/bin/pt-ioprofile @@ -201,7 +201,10 @@ parse_options() { _parse_config_files "$user_config_file" done else - _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" + _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" + if [ ! -z "${HOME-}" ]; then + _parse_config_files "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" + fi fi _parse_command_line "${@:-""}" diff --git a/bin/pt-mext b/bin/pt-mext index 088ca107..9c170d79 100755 --- a/bin/pt-mext +++ b/bin/pt-mext @@ -242,7 +242,10 @@ parse_options() { _parse_config_files "$user_config_file" done else - _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" + _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" + if [ ! -z "${HOME-}" ]; then + _parse_config_files "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" + fi fi _parse_command_line "${@:-""}" diff --git a/bin/pt-mysql-summary b/bin/pt-mysql-summary index df639463..59e1903f 100755 --- a/bin/pt-mysql-summary +++ b/bin/pt-mysql-summary @@ -203,7 +203,10 @@ parse_options() { _parse_config_files "$user_config_file" done else - _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" + _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" + if [ ! -z "${HOME-}" ]; then + _parse_config_files "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" + fi fi _parse_command_line "${@:-""}" diff --git a/bin/pt-pmp b/bin/pt-pmp index 63504fbe..a8814cc7 100755 --- a/bin/pt-pmp +++ b/bin/pt-pmp @@ -244,7 +244,10 @@ parse_options() { _parse_config_files "$user_config_file" done else - _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" + _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" + if [ ! -z "${HOME-}" ]; then + _parse_config_files "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" + fi fi _parse_command_line "${@:-""}" diff --git a/bin/pt-sift b/bin/pt-sift index e21a4a2e..0c307606 100755 --- a/bin/pt-sift +++ b/bin/pt-sift @@ -242,7 +242,10 @@ parse_options() { _parse_config_files "$user_config_file" done else - _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" + _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" + if [ ! -z "${HOME-}" ]; then + _parse_config_files "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" + fi fi _parse_command_line "${@:-""}" diff --git a/bin/pt-stalk b/bin/pt-stalk index 653614fc..db058c6d 100755 --- a/bin/pt-stalk +++ b/bin/pt-stalk @@ -255,7 +255,10 @@ parse_options() { _parse_config_files "$user_config_file" done else - _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" + _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" + if [ ! -z "${HOME-}" ]; then + _parse_config_files "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" + fi fi _parse_command_line "${@:-""}" diff --git a/bin/pt-summary b/bin/pt-summary index 0582e253..9acef883 100755 --- a/bin/pt-summary +++ b/bin/pt-summary @@ -210,7 +210,10 @@ parse_options() { _parse_config_files "$user_config_file" done else - _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" + _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" + if [ ! -z "${HOME-}" ]; then + _parse_config_files "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" + fi fi _parse_command_line "${@:-""}" diff --git a/lib/bash/parse_options.sh b/lib/bash/parse_options.sh index b07074ec..0bafca3f 100644 --- a/lib/bash/parse_options.sh +++ b/lib/bash/parse_options.sh @@ -213,7 +213,11 @@ parse_options() { _parse_config_files "$user_config_file" done else - _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" + _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" + # conditional in case $HOME isn't set; e.g. tool launched from init + if [ ! -z "${HOME-}" ]; then + _parse_config_files "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" + fi fi # Finally, parse the command line. From 18f85786ba8dbf3fa6a1ed99252846e9fe03a2b5 Mon Sep 17 00:00:00 2001 From: Frank Cizmich Date: Wed, 14 Jan 2015 14:36:44 -0200 Subject: [PATCH 13/23] added test. removed space --- bin/pt-ioprofile | 2 +- bin/pt-mext | 2 +- bin/pt-mysql-summary | 2 +- bin/pt-pmp | 2 +- bin/pt-sift | 2 +- bin/pt-stalk | 2 +- bin/pt-summary | 2 +- lib/bash/parse_options.sh | 2 +- t/lib/bash/parse_options.sh | 15 ++++++++++++++- 9 files changed, 22 insertions(+), 9 deletions(-) diff --git a/bin/pt-ioprofile b/bin/pt-ioprofile index 5f73678e..83951b18 100755 --- a/bin/pt-ioprofile +++ b/bin/pt-ioprofile @@ -201,7 +201,7 @@ parse_options() { _parse_config_files "$user_config_file" done else - _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" + _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" if [ ! -z "${HOME-}" ]; then _parse_config_files "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" fi diff --git a/bin/pt-mext b/bin/pt-mext index 9c170d79..60310a99 100755 --- a/bin/pt-mext +++ b/bin/pt-mext @@ -242,7 +242,7 @@ parse_options() { _parse_config_files "$user_config_file" done else - _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" + _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" if [ ! -z "${HOME-}" ]; then _parse_config_files "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" fi diff --git a/bin/pt-mysql-summary b/bin/pt-mysql-summary index 59e1903f..fab7fd91 100755 --- a/bin/pt-mysql-summary +++ b/bin/pt-mysql-summary @@ -203,7 +203,7 @@ parse_options() { _parse_config_files "$user_config_file" done else - _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" + _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" if [ ! -z "${HOME-}" ]; then _parse_config_files "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" fi diff --git a/bin/pt-pmp b/bin/pt-pmp index a8814cc7..2fed95fa 100755 --- a/bin/pt-pmp +++ b/bin/pt-pmp @@ -244,7 +244,7 @@ parse_options() { _parse_config_files "$user_config_file" done else - _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" + _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" if [ ! -z "${HOME-}" ]; then _parse_config_files "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" fi diff --git a/bin/pt-sift b/bin/pt-sift index 0c307606..4660fe0d 100755 --- a/bin/pt-sift +++ b/bin/pt-sift @@ -242,7 +242,7 @@ parse_options() { _parse_config_files "$user_config_file" done else - _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" + _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" if [ ! -z "${HOME-}" ]; then _parse_config_files "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" fi diff --git a/bin/pt-stalk b/bin/pt-stalk index db058c6d..ece14424 100755 --- a/bin/pt-stalk +++ b/bin/pt-stalk @@ -255,7 +255,7 @@ parse_options() { _parse_config_files "$user_config_file" done else - _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" + _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" if [ ! -z "${HOME-}" ]; then _parse_config_files "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" fi diff --git a/bin/pt-summary b/bin/pt-summary index 9acef883..1e045113 100755 --- a/bin/pt-summary +++ b/bin/pt-summary @@ -210,7 +210,7 @@ parse_options() { _parse_config_files "$user_config_file" done else - _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" + _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" if [ ! -z "${HOME-}" ]; then _parse_config_files "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" fi diff --git a/lib/bash/parse_options.sh b/lib/bash/parse_options.sh index 0bafca3f..d5a3fed0 100644 --- a/lib/bash/parse_options.sh +++ b/lib/bash/parse_options.sh @@ -213,7 +213,7 @@ parse_options() { _parse_config_files "$user_config_file" done else - _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" + _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" # conditional in case $HOME isn't set; e.g. tool launched from init if [ ! -z "${HOME-}" ]; then _parse_config_files "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" diff --git a/t/lib/bash/parse_options.sh b/t/lib/bash/parse_options.sh index ca6326c8..4beba5a0 100644 --- a/t/lib/bash/parse_options.sh +++ b/t/lib/bash/parse_options.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -plan 83 +plan 84 TMPFILE="$TEST_PT_TMPDIR/parse-opts-output" TOOL="pt-stalk" @@ -258,6 +258,19 @@ is "$OPT_NOTIFY_BY_EMAIL" "" "Bug 1038995: --notify-by-email is empty by default parse_options "$T_LIB_DIR/samples/bash/po005.sh" --notify-by-email foo@bar.com is "$OPT_NOTIFY_BY_EMAIL" "foo@bar.com" "Bug 1038995: ...but gets set without errors if specified" +# ############################################################################ +# Bug 1266869: fails when $HOME unset +# https://bugs.launchpad.net/percona-toolkit/+bug/1266869 +# ############################################################################ + +TMP_HOME="$HOME" +unset HOME +OUTPUT=`parse_options $T_LIB_DIR/samples/bash/po001.sh 2>&1` +echo "$OUTPUT" > "$TMPFILE" +cmd_ok "grep -q -v unbound $TMPFILE" "No error when \$HOME is not set" +HOME="$TMP_HOME" # just in case further tests below need it + + # ############################################################################ # Done # ############################################################################ From 3b1aca82935881c9d264788fa342959d625684e3 Mon Sep 17 00:00:00 2001 From: Frank Cizmich Date: Wed, 14 Jan 2015 18:08:07 -0200 Subject: [PATCH 14/23] unique-id function for cluster nodes. added pxc5.6 config. modified pxc test --- bin/pt-config-diff | 33 ++++++++++++++++--- bin/pt-deadlock-logger | 33 ++++++++++++++++--- bin/pt-fk-error-logger | 33 ++++++++++++++++--- bin/pt-kill | 33 ++++++++++++++++--- bin/pt-online-schema-change | 38 +++++++++++++++++----- bin/pt-table-checksum | 44 +++++++++++++++++++------- bin/pt-upgrade | 33 ++++++++++++++++--- lib/Cxn.pm | 39 +++++++++++++++++++---- lib/Percona/XtraDB/Cluster.pm | 8 +---- sandbox/servers/pxc/5.6/my.sandbox.cnf | 42 ++++++++++++++++++++++++ t/pt-table-checksum/pxc.t | 22 +++++++++++-- 11 files changed, 302 insertions(+), 56 deletions(-) create mode 100644 sandbox/servers/pxc/5.6/my.sandbox.cnf diff --git a/bin/pt-config-diff b/bin/pt-config-diff index 4de976fa..4d03b1d3 100755 --- a/bin/pt-config-diff +++ b/bin/pt-config-diff @@ -2393,9 +2393,37 @@ sub name { return $self->{hostname} || $self->{dsn_name} || 'unknown host'; } +sub get_id { + my ($self, $cxn) = @_; + + $cxn ||= $self; + + my $unique_id; + if ($cxn->is_cluster_node()) { # for cluster we concatenate various variables to maximize id 'uniqueness' across versions + my $sql = q{SHOW STATUS LIKE 'wsrep\_local\_index'}; + my (undef, $wsrep_local_index) = $cxn->dbh->selectrow_array($sql); + PTDEBUG && _d("Got cluster wsrep_local_index: ",$wsrep_local_index); + $unique_id = $wsrep_local_index."|"; + foreach my $val ('server\_id', 'wsrep\_sst\_receive\_address', 'wsrep\_node\_name', 'wsrep\_node\_address') { + my $sql = "SHOW VARIABLES LIKE '$val'"; + PTDEBUG && _d($cxn->name, $sql); + my (undef, $val) = $cxn->dbh->selectrow_array($sql); + $unique_id .= "|$val"; + } + } else { + my $sql = 'SELECT @@SERVER_ID'; + PTDEBUG && _d($sql); + $unique_id = $cxn->dbh->selectrow_array($sql); + } + PTDEBUG && _d("Generated unique id for cluster:", $unique_id); + return $unique_id; +} + + sub is_cluster_node { my ($self, $cxn) = @_; + $cxn ||= $self; my $sql = "SHOW VARIABLES LIKE 'wsrep\_on'"; PTDEBUG && _d($cxn->name, $sql); my $row = $cxn->dbh->selectrow_arrayref($sql); @@ -2412,11 +2440,8 @@ sub remove_duplicate_cxns { my @trimmed_cxns; for my $cxn ( @cxns ) { - my $dbh = $cxn->dbh(); - my $sql = $self->is_cluster_node($cxn) ? q{SELECT @@wsrep_node_incoming_address} : q{SELECT @@server_id}; - PTDEBUG && _d($sql); - my ($id) = $dbh->selectrow_array($sql); + my $id = $cxn->get_id(); PTDEBUG && _d('Server ID for ', $cxn->name, ': ', $id); if ( ! $seen_ids->{$id}++ ) { diff --git a/bin/pt-deadlock-logger b/bin/pt-deadlock-logger index e9140b02..0866a7a5 100755 --- a/bin/pt-deadlock-logger +++ b/bin/pt-deadlock-logger @@ -2737,9 +2737,37 @@ sub name { return $self->{hostname} || $self->{dsn_name} || 'unknown host'; } +sub get_id { + my ($self, $cxn) = @_; + + $cxn ||= $self; + + my $unique_id; + if ($cxn->is_cluster_node()) { # for cluster we concatenate various variables to maximize id 'uniqueness' across versions + my $sql = q{SHOW STATUS LIKE 'wsrep\_local\_index'}; + my (undef, $wsrep_local_index) = $cxn->dbh->selectrow_array($sql); + PTDEBUG && _d("Got cluster wsrep_local_index: ",$wsrep_local_index); + $unique_id = $wsrep_local_index."|"; + foreach my $val ('server\_id', 'wsrep\_sst\_receive\_address', 'wsrep\_node\_name', 'wsrep\_node\_address') { + my $sql = "SHOW VARIABLES LIKE '$val'"; + PTDEBUG && _d($cxn->name, $sql); + my (undef, $val) = $cxn->dbh->selectrow_array($sql); + $unique_id .= "|$val"; + } + } else { + my $sql = 'SELECT @@SERVER_ID'; + PTDEBUG && _d($sql); + $unique_id = $cxn->dbh->selectrow_array($sql); + } + PTDEBUG && _d("Generated unique id for cluster:", $unique_id); + return $unique_id; +} + + sub is_cluster_node { my ($self, $cxn) = @_; + $cxn ||= $self; my $sql = "SHOW VARIABLES LIKE 'wsrep\_on'"; PTDEBUG && _d($cxn->name, $sql); my $row = $cxn->dbh->selectrow_arrayref($sql); @@ -2756,11 +2784,8 @@ sub remove_duplicate_cxns { my @trimmed_cxns; for my $cxn ( @cxns ) { - my $dbh = $cxn->dbh(); - my $sql = $self->is_cluster_node($cxn) ? q{SELECT @@wsrep_node_incoming_address} : q{SELECT @@server_id}; - PTDEBUG && _d($sql); - my ($id) = $dbh->selectrow_array($sql); + my $id = $cxn->get_id(); PTDEBUG && _d('Server ID for ', $cxn->name, ': ', $id); if ( ! $seen_ids->{$id}++ ) { diff --git a/bin/pt-fk-error-logger b/bin/pt-fk-error-logger index 14b43289..1535fb5e 100755 --- a/bin/pt-fk-error-logger +++ b/bin/pt-fk-error-logger @@ -1889,9 +1889,37 @@ sub name { return $self->{hostname} || $self->{dsn_name} || 'unknown host'; } +sub get_id { + my ($self, $cxn) = @_; + + $cxn ||= $self; + + my $unique_id; + if ($cxn->is_cluster_node()) { # for cluster we concatenate various variables to maximize id 'uniqueness' across versions + my $sql = q{SHOW STATUS LIKE 'wsrep\_local\_index'}; + my (undef, $wsrep_local_index) = $cxn->dbh->selectrow_array($sql); + PTDEBUG && _d("Got cluster wsrep_local_index: ",$wsrep_local_index); + $unique_id = $wsrep_local_index."|"; + foreach my $val ('server\_id', 'wsrep\_sst\_receive\_address', 'wsrep\_node\_name', 'wsrep\_node\_address') { + my $sql = "SHOW VARIABLES LIKE '$val'"; + PTDEBUG && _d($cxn->name, $sql); + my (undef, $val) = $cxn->dbh->selectrow_array($sql); + $unique_id .= "|$val"; + } + } else { + my $sql = 'SELECT @@SERVER_ID'; + PTDEBUG && _d($sql); + $unique_id = $cxn->dbh->selectrow_array($sql); + } + PTDEBUG && _d("Generated unique id for cluster:", $unique_id); + return $unique_id; +} + + sub is_cluster_node { my ($self, $cxn) = @_; + $cxn ||= $self; my $sql = "SHOW VARIABLES LIKE 'wsrep\_on'"; PTDEBUG && _d($cxn->name, $sql); my $row = $cxn->dbh->selectrow_arrayref($sql); @@ -1908,11 +1936,8 @@ sub remove_duplicate_cxns { my @trimmed_cxns; for my $cxn ( @cxns ) { - my $dbh = $cxn->dbh(); - my $sql = $self->is_cluster_node($cxn) ? q{SELECT @@wsrep_node_incoming_address} : q{SELECT @@server_id}; - PTDEBUG && _d($sql); - my ($id) = $dbh->selectrow_array($sql); + my $id = $cxn->get_id(); PTDEBUG && _d('Server ID for ', $cxn->name, ': ', $id); if ( ! $seen_ids->{$id}++ ) { diff --git a/bin/pt-kill b/bin/pt-kill index c7e5482b..a8faa731 100755 --- a/bin/pt-kill +++ b/bin/pt-kill @@ -5256,9 +5256,37 @@ sub name { return $self->{hostname} || $self->{dsn_name} || 'unknown host'; } +sub get_id { + my ($self, $cxn) = @_; + + $cxn ||= $self; + + my $unique_id; + if ($cxn->is_cluster_node()) { # for cluster we concatenate various variables to maximize id 'uniqueness' across versions + my $sql = q{SHOW STATUS LIKE 'wsrep\_local\_index'}; + my (undef, $wsrep_local_index) = $cxn->dbh->selectrow_array($sql); + PTDEBUG && _d("Got cluster wsrep_local_index: ",$wsrep_local_index); + $unique_id = $wsrep_local_index."|"; + foreach my $val ('server\_id', 'wsrep\_sst\_receive\_address', 'wsrep\_node\_name', 'wsrep\_node\_address') { + my $sql = "SHOW VARIABLES LIKE '$val'"; + PTDEBUG && _d($cxn->name, $sql); + my (undef, $val) = $cxn->dbh->selectrow_array($sql); + $unique_id .= "|$val"; + } + } else { + my $sql = 'SELECT @@SERVER_ID'; + PTDEBUG && _d($sql); + $unique_id = $cxn->dbh->selectrow_array($sql); + } + PTDEBUG && _d("Generated unique id for cluster:", $unique_id); + return $unique_id; +} + + sub is_cluster_node { my ($self, $cxn) = @_; + $cxn ||= $self; my $sql = "SHOW VARIABLES LIKE 'wsrep\_on'"; PTDEBUG && _d($cxn->name, $sql); my $row = $cxn->dbh->selectrow_arrayref($sql); @@ -5275,11 +5303,8 @@ sub remove_duplicate_cxns { my @trimmed_cxns; for my $cxn ( @cxns ) { - my $dbh = $cxn->dbh(); - my $sql = $self->is_cluster_node($cxn) ? q{SELECT @@wsrep_node_incoming_address} : q{SELECT @@server_id}; - PTDEBUG && _d($sql); - my ($id) = $dbh->selectrow_array($sql); + my $id = $cxn->get_id(); PTDEBUG && _d('Server ID for ', $cxn->name, ': ', $id); if ( ! $seen_ids->{$id}++ ) { diff --git a/bin/pt-online-schema-change b/bin/pt-online-schema-change index 67aa5343..40cd2538 100755 --- a/bin/pt-online-schema-change +++ b/bin/pt-online-schema-change @@ -3853,9 +3853,37 @@ sub name { return $self->{hostname} || $self->{dsn_name} || 'unknown host'; } +sub get_id { + my ($self, $cxn) = @_; + + $cxn ||= $self; + + my $unique_id; + if ($cxn->is_cluster_node()) { # for cluster we concatenate various variables to maximize id 'uniqueness' across versions + my $sql = q{SHOW STATUS LIKE 'wsrep\_local\_index'}; + my (undef, $wsrep_local_index) = $cxn->dbh->selectrow_array($sql); + PTDEBUG && _d("Got cluster wsrep_local_index: ",$wsrep_local_index); + $unique_id = $wsrep_local_index."|"; + foreach my $val ('server\_id', 'wsrep\_sst\_receive\_address', 'wsrep\_node\_name', 'wsrep\_node\_address') { + my $sql = "SHOW VARIABLES LIKE '$val'"; + PTDEBUG && _d($cxn->name, $sql); + my (undef, $val) = $cxn->dbh->selectrow_array($sql); + $unique_id .= "|$val"; + } + } else { + my $sql = 'SELECT @@SERVER_ID'; + PTDEBUG && _d($sql); + $unique_id = $cxn->dbh->selectrow_array($sql); + } + PTDEBUG && _d("Generated unique id for cluster:", $unique_id); + return $unique_id; +} + + sub is_cluster_node { my ($self, $cxn) = @_; + $cxn ||= $self; my $sql = "SHOW VARIABLES LIKE 'wsrep\_on'"; PTDEBUG && _d($cxn->name, $sql); my $row = $cxn->dbh->selectrow_arrayref($sql); @@ -3872,11 +3900,8 @@ sub remove_duplicate_cxns { my @trimmed_cxns; for my $cxn ( @cxns ) { - my $dbh = $cxn->dbh(); - my $sql = $self->is_cluster_node($cxn) ? q{SELECT @@wsrep_node_incoming_address} : q{SELECT @@server_id}; - PTDEBUG && _d($sql); - my ($id) = $dbh->selectrow_array($sql); + my $id = $cxn->get_id(); PTDEBUG && _d('Server ID for ', $cxn->name, ': ', $id); if ( ! $seen_ids->{$id}++ ) { @@ -7662,10 +7687,7 @@ sub remove_duplicate_cxns { my @trimmed_cxns; for my $cxn ( @cxns ) { - my $dbh = $cxn->dbh(); - my $sql = $self->is_cluster_node($cxn) ? q{SELECT @@wsrep_node_incoming_address} : q{SELECT @@server_id}; - PTDEBUG && _d($sql); - my ($id) = $dbh->selectrow_array($sql); + my $id = $cxn->get_id(); PTDEBUG && _d('Server ID for ', $cxn->name, ': ', $id); if ( ! $seen_ids->{$id}++ ) { diff --git a/bin/pt-table-checksum b/bin/pt-table-checksum index 3adee83e..7a15bd55 100755 --- a/bin/pt-table-checksum +++ b/bin/pt-table-checksum @@ -3631,9 +3631,37 @@ sub name { return $self->{hostname} || $self->{dsn_name} || 'unknown host'; } +sub get_id { + my ($self, $cxn) = @_; + + $cxn ||= $self; + + my $unique_id; + if ($cxn->is_cluster_node()) { # for cluster we concatenate various variables to maximize id 'uniqueness' across versions + my $sql = q{SHOW STATUS LIKE 'wsrep\_local\_index'}; + my (undef, $wsrep_local_index) = $cxn->dbh->selectrow_array($sql); + PTDEBUG && _d("Got cluster wsrep_local_index: ",$wsrep_local_index); + $unique_id = $wsrep_local_index."|"; + foreach my $val ('server\_id', 'wsrep\_sst\_receive\_address', 'wsrep\_node\_name', 'wsrep\_node\_address') { + my $sql = "SHOW VARIABLES LIKE '$val'"; + PTDEBUG && _d($cxn->name, $sql); + my (undef, $val) = $cxn->dbh->selectrow_array($sql); + $unique_id .= "|$val"; + } + } else { + my $sql = 'SELECT @@SERVER_ID'; + PTDEBUG && _d($sql); + $unique_id = $cxn->dbh->selectrow_array($sql); + } + PTDEBUG && _d("Generated unique id for cluster:", $unique_id); + return $unique_id; +} + + sub is_cluster_node { my ($self, $cxn) = @_; + $cxn ||= $self; my $sql = "SHOW VARIABLES LIKE 'wsrep\_on'"; PTDEBUG && _d($cxn->name, $sql); my $row = $cxn->dbh->selectrow_arrayref($sql); @@ -3650,11 +3678,8 @@ sub remove_duplicate_cxns { my @trimmed_cxns; for my $cxn ( @cxns ) { - my $dbh = $cxn->dbh(); - my $sql = $self->is_cluster_node($cxn) ? q{SELECT @@wsrep_node_incoming_address} : q{SELECT @@server_id}; - PTDEBUG && _d($sql); - my ($id) = $dbh->selectrow_array($sql); + my $id = $cxn->get_id(); PTDEBUG && _d('Server ID for ', $cxn->name, ': ', $id); if ( ! $seen_ids->{$id}++ ) { @@ -3812,10 +3837,7 @@ sub remove_duplicate_cxns { my @trimmed_cxns; for my $cxn ( @cxns ) { - my $dbh = $cxn->dbh(); - my $sql = $self->is_cluster_node($cxn) ? q{SELECT @@wsrep_node_incoming_address} : q{SELECT @@server_id}; - PTDEBUG && _d($sql); - my ($id) = $dbh->selectrow_array($sql); + my $id = $cxn->get_id(); PTDEBUG && _d('Server ID for ', $cxn->name, ': ', $id); if ( ! $seen_ids->{$id}++ ) { @@ -9323,10 +9345,8 @@ sub main { my %seen_ids; for my $cxn ($master_cxn, @$slaves) { my $dbh = $cxn->dbh(); - # if it's a cluster node we use its incoming address as id ( see https://bugs.launchpad.net/percona-toolkit/+bug/1217466 ) - my $sql = $cluster->is_cluster_node($cxn) ? q{SELECT @@wsrep_node_incoming_address} : q{SELECT @@server_id}; - PTDEBUG && _d($cxn, $dbh, $sql); - my ($id) = $dbh->selectrow_array($sql); + # get server/node unique id ( https://bugs.launchpad.net/percona-toolkit/+bug/1217466 ) + my $id = $cxn->get_id(); $seen_ids{$id}++; } diff --git a/bin/pt-upgrade b/bin/pt-upgrade index cf04c82b..675af05b 100755 --- a/bin/pt-upgrade +++ b/bin/pt-upgrade @@ -2562,9 +2562,37 @@ sub name { return $self->{hostname} || $self->{dsn_name} || 'unknown host'; } +sub get_id { + my ($self, $cxn) = @_; + + $cxn ||= $self; + + my $unique_id; + if ($cxn->is_cluster_node()) { # for cluster we concatenate various variables to maximize id 'uniqueness' across versions + my $sql = q{SHOW STATUS LIKE 'wsrep\_local\_index'}; + my (undef, $wsrep_local_index) = $cxn->dbh->selectrow_array($sql); + PTDEBUG && _d("Got cluster wsrep_local_index: ",$wsrep_local_index); + $unique_id = $wsrep_local_index."|"; + foreach my $val ('server\_id', 'wsrep\_sst\_receive\_address', 'wsrep\_node\_name', 'wsrep\_node\_address') { + my $sql = "SHOW VARIABLES LIKE '$val'"; + PTDEBUG && _d($cxn->name, $sql); + my (undef, $val) = $cxn->dbh->selectrow_array($sql); + $unique_id .= "|$val"; + } + } else { + my $sql = 'SELECT @@SERVER_ID'; + PTDEBUG && _d($sql); + $unique_id = $cxn->dbh->selectrow_array($sql); + } + PTDEBUG && _d("Generated unique id for cluster:", $unique_id); + return $unique_id; +} + + sub is_cluster_node { my ($self, $cxn) = @_; + $cxn ||= $self; my $sql = "SHOW VARIABLES LIKE 'wsrep\_on'"; PTDEBUG && _d($cxn->name, $sql); my $row = $cxn->dbh->selectrow_arrayref($sql); @@ -2581,11 +2609,8 @@ sub remove_duplicate_cxns { my @trimmed_cxns; for my $cxn ( @cxns ) { - my $dbh = $cxn->dbh(); - my $sql = $self->is_cluster_node($cxn) ? q{SELECT @@wsrep_node_incoming_address} : q{SELECT @@server_id}; - PTDEBUG && _d($sql); - my ($id) = $dbh->selectrow_array($sql); + my $id = $cxn->get_id(); PTDEBUG && _d('Server ID for ', $cxn->name, ': ', $id); if ( ! $seen_ids->{$id}++ ) { diff --git a/lib/Cxn.pm b/lib/Cxn.pm index b8dc7168..6559f9a7 100644 --- a/lib/Cxn.pm +++ b/lib/Cxn.pm @@ -226,11 +226,42 @@ sub name { return $self->{hostname} || $self->{dsn_name} || 'unknown host'; } +# This returns the server_id. +# For cluster nodes, since server_id is unreliable, we use a combination of +# variables to create an id string that is unique. +sub get_id { + my ($self, $cxn) = @_; + + $cxn ||= $self; + + my $unique_id; + if ($cxn->is_cluster_node()) { # for cluster we concatenate various variables to maximize id 'uniqueness' across versions + my $sql = q{SHOW STATUS LIKE 'wsrep\_local\_index'}; + my (undef, $wsrep_local_index) = $cxn->dbh->selectrow_array($sql); + PTDEBUG && _d("Got cluster wsrep_local_index: ",$wsrep_local_index); + $unique_id = $wsrep_local_index."|"; + foreach my $val ('server\_id', 'wsrep\_sst\_receive\_address', 'wsrep\_node\_name', 'wsrep\_node\_address') { + my $sql = "SHOW VARIABLES LIKE '$val'"; + PTDEBUG && _d($cxn->name, $sql); + my (undef, $val) = $cxn->dbh->selectrow_array($sql); + $unique_id .= "|$val"; + } + } else { + my $sql = 'SELECT @@SERVER_ID'; + PTDEBUG && _d($sql); + $unique_id = $cxn->dbh->selectrow_array($sql); + } + PTDEBUG && _d("Generated unique id for cluster:", $unique_id); + return $unique_id; +} + + # This is used to help remove_duplicate_cxns detect cluster nodes # (which often have unreliable server_id's) sub is_cluster_node { my ($self, $cxn) = @_; + $cxn ||= $self; my $sql = "SHOW VARIABLES LIKE 'wsrep\_on'"; PTDEBUG && _d($cxn->name, $sql); my $row = $cxn->dbh->selectrow_arrayref($sql); @@ -257,14 +288,8 @@ sub remove_duplicate_cxns { my @trimmed_cxns; for my $cxn ( @cxns ) { - my $dbh = $cxn->dbh(); - # Very often cluster nodes are configured with matching server_id's - # So in that case we'll use its incoming address as its unique identifier - # Note: this relies on "seen_ids" being populated using the same strategy - my $sql = $self->is_cluster_node($cxn) ? q{SELECT @@wsrep_node_incoming_address} : q{SELECT @@server_id}; - PTDEBUG && _d($sql); - my ($id) = $dbh->selectrow_array($sql); + my $id = $cxn->get_id(); PTDEBUG && _d('Server ID for ', $cxn->name, ': ', $id); if ( ! $seen_ids->{$id}++ ) { diff --git a/lib/Percona/XtraDB/Cluster.pm b/lib/Percona/XtraDB/Cluster.pm index c8ad96ce..836e3e49 100644 --- a/lib/Percona/XtraDB/Cluster.pm +++ b/lib/Percona/XtraDB/Cluster.pm @@ -137,13 +137,7 @@ sub remove_duplicate_cxns { my @trimmed_cxns; for my $cxn ( @cxns ) { - my $dbh = $cxn->dbh(); - # Very often cluster nodes are configured with matching server_id's - # So in that case we'll use its incoming address as its unique identifier - # Note: This relies on "seen_ids" being populated using the same strategy - my $sql = $self->is_cluster_node($cxn) ? q{SELECT @@wsrep_node_incoming_address} : q{SELECT @@server_id}; - PTDEBUG && _d($sql); - my ($id) = $dbh->selectrow_array($sql); + my $id = $cxn->get_id(); PTDEBUG && _d('Server ID for ', $cxn->name, ': ', $id); if ( ! $seen_ids->{$id}++ ) { diff --git a/sandbox/servers/pxc/5.6/my.sandbox.cnf b/sandbox/servers/pxc/5.6/my.sandbox.cnf new file mode 100644 index 00000000..ad2673d9 --- /dev/null +++ b/sandbox/servers/pxc/5.6/my.sandbox.cnf @@ -0,0 +1,42 @@ +[client] +user = msandbox +password = msandbox +port = PORT +socket = /tmp/PORT/mysql_sandboxPORT.sock + +[mysqld] +port = PORT +socket = /tmp/PORT/mysql_sandboxPORT.sock +pid-file = /tmp/PORT/data/mysql_sandboxPORT.pid +basedir = PERCONA_TOOLKIT_SANDBOX +datadir = /tmp/PORT/data +key_buffer_size = 16M +innodb_buffer_pool_size = 16M +innodb_data_home_dir = /tmp/PORT/data +innodb_log_group_home_dir = /tmp/PORT/data +innodb_data_file_path = ibdata1:10M:autoextend +innodb_log_file_size = 5M +log-bin = mysql-bin +relay_log = mysql-relay-bin +log_slave_updates +server-id = PORT +report-host = 127.0.0.1 +report-port = PORT +log-error = /tmp/PORT/data/mysqld.log +innodb_lock_wait_timeout = 3 +general_log +general_log_file = genlog + +binlog_format = ROW +wsrep_provider = LIBGALERA +wsrep_cluster_address = CLUSTER_AD +wsrep_sst_receive_address = ADDR:RECEIVE_PRT +wsrep_node_incoming_address= ADDR:PORT +wsrep_slave_threads = 2 +wsrep_cluster_name = CLUSTER_NAME +wsrep_provider_options = "gmcast.listen_addr=tcp://ADDR:LISTEN_PRT;" +wsrep_sst_method = rsync +wsrep_node_name = PORT +innodb_locks_unsafe_for_binlog = 1 +innodb_autoinc_lock_mode = 2 +wsrep-replicate-myisam diff --git a/t/pt-table-checksum/pxc.t b/t/pt-table-checksum/pxc.t index bfca0b3e..525c6acd 100644 --- a/t/pt-table-checksum/pxc.t +++ b/t/pt-table-checksum/pxc.t @@ -88,8 +88,8 @@ like( ); ok ( - $output =~ qr/WARNING/i && !$exit_status, - "Warns but doesn't die if --recursion-method=none - issue #1373937" + $output !~ qr/no other nodes or regular replicas were found/i && !$exit_status, + "checksums even if --recursion-method=none - issue 1373937" ); for my $args ( @@ -159,6 +159,7 @@ sub test_recursion_methods { my $same_ids = shift; my ($orig_id_1, $orig_id_2, $orig_id_3); + my ($orig_ia_1, $orig_ia_2, $orig_ia_3); if ($same_ids) { # save original values @@ -171,6 +172,19 @@ sub test_recursion_methods { $node1->do($sql); $node2->do($sql); $node3->do($sql); + + # since we're testing server id issues, set wsrep_node_incoming_address=AUTO ( https://bugs.launchpad.net/percona-toolkit/+bug/1399789 ) + # save original values + $sql = 'SELECT @@wsrep_node_incoming_address'; + ($orig_ia_1) = $node1->selectrow_array($sql); + ($orig_ia_2) = $node2->selectrow_array($sql); + ($orig_ia_3) = $node3->selectrow_array($sql); + # set wsrep_node_incoming_address value to AUTO on all nodes + $sql = 'SET GLOBAL wsrep_node_incoming_address = AUTO'; + $node1->do($sql); + $node2->do($sql); + $node3->do($sql); + } for my $args ( @@ -227,6 +241,10 @@ sub test_recursion_methods { $node1->do("SET GLOBAL server_id = $orig_id_1"); $node2->do("SET GLOBAL server_id = $orig_id_2"); $node3->do("SET GLOBAL server_id = $orig_id_3"); + # reset node wsrep_node_incoming_address to original values + $node1->do("SET GLOBAL wsrep_node_incoming_address = $orig_ia_1"); + $node2->do("SET GLOBAL wsrep_node_incoming_address = $orig_ia_2"); + $node3->do("SET GLOBAL wsrep_node_incoming_address = $orig_ia_3"); } } From c3462b6c68b3361a637de537b639e6935b1deb42 Mon Sep 17 00:00:00 2001 From: Frank Cizmich Date: Fri, 16 Jan 2015 16:49:30 -0200 Subject: [PATCH 15/23] Fixed security issues in VersionCheck and HTTP::Micro --- bin/pt-archiver | 13 ++++++++++--- bin/pt-config-diff | 13 ++++++++++--- bin/pt-deadlock-logger | 13 ++++++++++--- bin/pt-diskstats | 13 ++++++++++--- bin/pt-duplicate-key-checker | 13 ++++++++++--- bin/pt-find | 13 ++++++++++--- bin/pt-fk-error-logger | 13 ++++++++++--- bin/pt-heartbeat | 13 ++++++++++--- bin/pt-index-usage | 13 ++++++++++--- bin/pt-kill | 13 ++++++++++--- bin/pt-online-schema-change | 13 ++++++++++--- bin/pt-query-digest | 13 ++++++++++--- bin/pt-slave-delay | 13 ++++++++++--- bin/pt-slave-restart | 13 ++++++++++--- bin/pt-table-checksum | 13 ++++++++++--- bin/pt-table-sync | 13 ++++++++++--- bin/pt-upgrade | 13 ++++++++++--- bin/pt-variable-advisor | 13 ++++++++++--- lib/HTTP/Micro.pm | 3 ++- lib/VersionCheck.pm | 17 ++++++++++++----- 20 files changed, 194 insertions(+), 60 deletions(-) diff --git a/bin/pt-archiver b/bin/pt-archiver index 874a2234..af0ccfaf 100755 --- a/bin/pt-archiver +++ b/bin/pt-archiver @@ -4421,7 +4421,8 @@ sub _split_url { ref($self->{fh}) eq 'IO::Socket::SSL' or die(qq/SSL connection failed for $host\n/); if ( $self->{fh}->can("verify_hostname") ) { - $self->{fh}->verify_hostname( $host, $ssl_verify_args ); + $self->{fh}->verify_hostname( $host, $ssl_verify_args ) + or die(qq/SSL certificate not valid for $host\n/); } else { my $fh = $self->{fh}; @@ -4943,11 +4944,12 @@ sub version_check { PTDEBUG && _d(scalar @$instances_to_check, 'instances to check'); return unless @$instances_to_check; - my $protocol = 'https'; # optimistic, but... + my $protocol = 'https'; eval { require IO::Socket::SSL; }; if ( $EVAL_ERROR ) { PTDEBUG && _d($EVAL_ERROR); - $protocol = 'http'; + PTDEBUG && _d("SSL not available, won't run version_check"); + return; } PTDEBUG && _d('Using', $protocol); @@ -5384,6 +5386,11 @@ sub get_from_mysql { return; } + if ($item->{item} eq 'MySQL' && $item->{type} eq 'mysql_variable') { + $item->{vars} = ['version_comment', 'version']; + } + + my @versions; my %version_for; foreach my $instance ( @$instances ) { diff --git a/bin/pt-config-diff b/bin/pt-config-diff index 4de976fa..b8970a7d 100755 --- a/bin/pt-config-diff +++ b/bin/pt-config-diff @@ -4169,7 +4169,8 @@ sub _split_url { ref($self->{fh}) eq 'IO::Socket::SSL' or die(qq/SSL connection failed for $host\n/); if ( $self->{fh}->can("verify_hostname") ) { - $self->{fh}->verify_hostname( $host, $ssl_verify_args ); + $self->{fh}->verify_hostname( $host, $ssl_verify_args ) + or die(qq/SSL certificate not valid for $host\n/); } else { my $fh = $self->{fh}; @@ -4691,11 +4692,12 @@ sub version_check { PTDEBUG && _d(scalar @$instances_to_check, 'instances to check'); return unless @$instances_to_check; - my $protocol = 'https'; # optimistic, but... + my $protocol = 'https'; eval { require IO::Socket::SSL; }; if ( $EVAL_ERROR ) { PTDEBUG && _d($EVAL_ERROR); - $protocol = 'http'; + PTDEBUG && _d("SSL not available, won't run version_check"); + return; } PTDEBUG && _d('Using', $protocol); @@ -5132,6 +5134,11 @@ sub get_from_mysql { return; } + if ($item->{item} eq 'MySQL' && $item->{type} eq 'mysql_variable') { + $item->{vars} = ['version_comment', 'version']; + } + + my @versions; my %version_for; foreach my $instance ( @$instances ) { diff --git a/bin/pt-deadlock-logger b/bin/pt-deadlock-logger index e9140b02..5600464d 100755 --- a/bin/pt-deadlock-logger +++ b/bin/pt-deadlock-logger @@ -3234,7 +3234,8 @@ sub _split_url { ref($self->{fh}) eq 'IO::Socket::SSL' or die(qq/SSL connection failed for $host\n/); if ( $self->{fh}->can("verify_hostname") ) { - $self->{fh}->verify_hostname( $host, $ssl_verify_args ); + $self->{fh}->verify_hostname( $host, $ssl_verify_args ) + or die(qq/SSL certificate not valid for $host\n/); } else { my $fh = $self->{fh}; @@ -3756,11 +3757,12 @@ sub version_check { PTDEBUG && _d(scalar @$instances_to_check, 'instances to check'); return unless @$instances_to_check; - my $protocol = 'https'; # optimistic, but... + my $protocol = 'https'; eval { require IO::Socket::SSL; }; if ( $EVAL_ERROR ) { PTDEBUG && _d($EVAL_ERROR); - $protocol = 'http'; + PTDEBUG && _d("SSL not available, won't run version_check"); + return; } PTDEBUG && _d('Using', $protocol); @@ -4197,6 +4199,11 @@ sub get_from_mysql { return; } + if ($item->{item} eq 'MySQL' && $item->{type} eq 'mysql_variable') { + $item->{vars} = ['version_comment', 'version']; + } + + my @versions; my %version_for; foreach my $instance ( @$instances ) { diff --git a/bin/pt-diskstats b/bin/pt-diskstats index 76e0cb14..ded40200 100755 --- a/bin/pt-diskstats +++ b/bin/pt-diskstats @@ -3828,7 +3828,8 @@ sub _split_url { ref($self->{fh}) eq 'IO::Socket::SSL' or die(qq/SSL connection failed for $host\n/); if ( $self->{fh}->can("verify_hostname") ) { - $self->{fh}->verify_hostname( $host, $ssl_verify_args ); + $self->{fh}->verify_hostname( $host, $ssl_verify_args ) + or die(qq/SSL certificate not valid for $host\n/); } else { my $fh = $self->{fh}; @@ -4350,11 +4351,12 @@ sub version_check { PTDEBUG && _d(scalar @$instances_to_check, 'instances to check'); return unless @$instances_to_check; - my $protocol = 'https'; # optimistic, but... + my $protocol = 'https'; eval { require IO::Socket::SSL; }; if ( $EVAL_ERROR ) { PTDEBUG && _d($EVAL_ERROR); - $protocol = 'http'; + PTDEBUG && _d("SSL not available, won't run version_check"); + return; } PTDEBUG && _d('Using', $protocol); @@ -4791,6 +4793,11 @@ sub get_from_mysql { return; } + if ($item->{item} eq 'MySQL' && $item->{type} eq 'mysql_variable') { + $item->{vars} = ['version_comment', 'version']; + } + + my @versions; my %version_for; foreach my $instance ( @$instances ) { diff --git a/bin/pt-duplicate-key-checker b/bin/pt-duplicate-key-checker index c38f6e86..e75fd9cc 100755 --- a/bin/pt-duplicate-key-checker +++ b/bin/pt-duplicate-key-checker @@ -3845,7 +3845,8 @@ sub _split_url { ref($self->{fh}) eq 'IO::Socket::SSL' or die(qq/SSL connection failed for $host\n/); if ( $self->{fh}->can("verify_hostname") ) { - $self->{fh}->verify_hostname( $host, $ssl_verify_args ); + $self->{fh}->verify_hostname( $host, $ssl_verify_args ) + or die(qq/SSL certificate not valid for $host\n/); } else { my $fh = $self->{fh}; @@ -4367,11 +4368,12 @@ sub version_check { PTDEBUG && _d(scalar @$instances_to_check, 'instances to check'); return unless @$instances_to_check; - my $protocol = 'https'; # optimistic, but... + my $protocol = 'https'; eval { require IO::Socket::SSL; }; if ( $EVAL_ERROR ) { PTDEBUG && _d($EVAL_ERROR); - $protocol = 'http'; + PTDEBUG && _d("SSL not available, won't run version_check"); + return; } PTDEBUG && _d('Using', $protocol); @@ -4808,6 +4810,11 @@ sub get_from_mysql { return; } + if ($item->{item} eq 'MySQL' && $item->{type} eq 'mysql_variable') { + $item->{vars} = ['version_comment', 'version']; + } + + my @versions; my %version_for; foreach my $instance ( @$instances ) { diff --git a/bin/pt-find b/bin/pt-find index 9d953277..a71b41b8 100755 --- a/bin/pt-find +++ b/bin/pt-find @@ -2572,7 +2572,8 @@ sub _split_url { ref($self->{fh}) eq 'IO::Socket::SSL' or die(qq/SSL connection failed for $host\n/); if ( $self->{fh}->can("verify_hostname") ) { - $self->{fh}->verify_hostname( $host, $ssl_verify_args ); + $self->{fh}->verify_hostname( $host, $ssl_verify_args ) + or die(qq/SSL certificate not valid for $host\n/); } else { my $fh = $self->{fh}; @@ -3094,11 +3095,12 @@ sub version_check { PTDEBUG && _d(scalar @$instances_to_check, 'instances to check'); return unless @$instances_to_check; - my $protocol = 'https'; # optimistic, but... + my $protocol = 'https'; eval { require IO::Socket::SSL; }; if ( $EVAL_ERROR ) { PTDEBUG && _d($EVAL_ERROR); - $protocol = 'http'; + PTDEBUG && _d("SSL not available, won't run version_check"); + return; } PTDEBUG && _d('Using', $protocol); @@ -3535,6 +3537,11 @@ sub get_from_mysql { return; } + if ($item->{item} eq 'MySQL' && $item->{type} eq 'mysql_variable') { + $item->{vars} = ['version_comment', 'version']; + } + + my @versions; my %version_for; foreach my $instance ( @$instances ) { diff --git a/bin/pt-fk-error-logger b/bin/pt-fk-error-logger index 14b43289..895ed857 100755 --- a/bin/pt-fk-error-logger +++ b/bin/pt-fk-error-logger @@ -2739,7 +2739,8 @@ sub _split_url { ref($self->{fh}) eq 'IO::Socket::SSL' or die(qq/SSL connection failed for $host\n/); if ( $self->{fh}->can("verify_hostname") ) { - $self->{fh}->verify_hostname( $host, $ssl_verify_args ); + $self->{fh}->verify_hostname( $host, $ssl_verify_args ) + or die(qq/SSL certificate not valid for $host\n/); } else { my $fh = $self->{fh}; @@ -3261,11 +3262,12 @@ sub version_check { PTDEBUG && _d(scalar @$instances_to_check, 'instances to check'); return unless @$instances_to_check; - my $protocol = 'https'; # optimistic, but... + my $protocol = 'https'; eval { require IO::Socket::SSL; }; if ( $EVAL_ERROR ) { PTDEBUG && _d($EVAL_ERROR); - $protocol = 'http'; + PTDEBUG && _d("SSL not available, won't run version_check"); + return; } PTDEBUG && _d('Using', $protocol); @@ -3702,6 +3704,11 @@ sub get_from_mysql { return; } + if ($item->{item} eq 'MySQL' && $item->{type} eq 'mysql_variable') { + $item->{vars} = ['version_comment', 'version']; + } + + my @versions; my %version_for; foreach my $instance ( @$instances ) { diff --git a/bin/pt-heartbeat b/bin/pt-heartbeat index 855ded6f..a018ea59 100755 --- a/bin/pt-heartbeat +++ b/bin/pt-heartbeat @@ -3744,7 +3744,8 @@ sub _split_url { ref($self->{fh}) eq 'IO::Socket::SSL' or die(qq/SSL connection failed for $host\n/); if ( $self->{fh}->can("verify_hostname") ) { - $self->{fh}->verify_hostname( $host, $ssl_verify_args ); + $self->{fh}->verify_hostname( $host, $ssl_verify_args ) + or die(qq/SSL certificate not valid for $host\n/); } else { my $fh = $self->{fh}; @@ -4266,11 +4267,12 @@ sub version_check { PTDEBUG && _d(scalar @$instances_to_check, 'instances to check'); return unless @$instances_to_check; - my $protocol = 'https'; # optimistic, but... + my $protocol = 'https'; eval { require IO::Socket::SSL; }; if ( $EVAL_ERROR ) { PTDEBUG && _d($EVAL_ERROR); - $protocol = 'http'; + PTDEBUG && _d("SSL not available, won't run version_check"); + return; } PTDEBUG && _d('Using', $protocol); @@ -4707,6 +4709,11 @@ sub get_from_mysql { return; } + if ($item->{item} eq 'MySQL' && $item->{type} eq 'mysql_variable') { + $item->{vars} = ['version_comment', 'version']; + } + + my @versions; my %version_for; foreach my $instance ( @$instances ) { diff --git a/bin/pt-index-usage b/bin/pt-index-usage index 1185ade7..4b62a7cf 100755 --- a/bin/pt-index-usage +++ b/bin/pt-index-usage @@ -5249,7 +5249,8 @@ sub _split_url { ref($self->{fh}) eq 'IO::Socket::SSL' or die(qq/SSL connection failed for $host\n/); if ( $self->{fh}->can("verify_hostname") ) { - $self->{fh}->verify_hostname( $host, $ssl_verify_args ); + $self->{fh}->verify_hostname( $host, $ssl_verify_args ) + or die(qq/SSL certificate not valid for $host\n/); } else { my $fh = $self->{fh}; @@ -5771,11 +5772,12 @@ sub version_check { PTDEBUG && _d(scalar @$instances_to_check, 'instances to check'); return unless @$instances_to_check; - my $protocol = 'https'; # optimistic, but... + my $protocol = 'https'; eval { require IO::Socket::SSL; }; if ( $EVAL_ERROR ) { PTDEBUG && _d($EVAL_ERROR); - $protocol = 'http'; + PTDEBUG && _d("SSL not available, won't run version_check"); + return; } PTDEBUG && _d('Using', $protocol); @@ -6212,6 +6214,11 @@ sub get_from_mysql { return; } + if ($item->{item} eq 'MySQL' && $item->{type} eq 'mysql_variable') { + $item->{vars} = ['version_comment', 'version']; + } + + my @versions; my %version_for; foreach my $instance ( @$instances ) { diff --git a/bin/pt-kill b/bin/pt-kill index c7e5482b..325e09b4 100755 --- a/bin/pt-kill +++ b/bin/pt-kill @@ -5551,7 +5551,8 @@ sub _split_url { ref($self->{fh}) eq 'IO::Socket::SSL' or die(qq/SSL connection failed for $host\n/); if ( $self->{fh}->can("verify_hostname") ) { - $self->{fh}->verify_hostname( $host, $ssl_verify_args ); + $self->{fh}->verify_hostname( $host, $ssl_verify_args ) + or die(qq/SSL certificate not valid for $host\n/); } else { my $fh = $self->{fh}; @@ -6073,11 +6074,12 @@ sub version_check { PTDEBUG && _d(scalar @$instances_to_check, 'instances to check'); return unless @$instances_to_check; - my $protocol = 'https'; # optimistic, but... + my $protocol = 'https'; eval { require IO::Socket::SSL; }; if ( $EVAL_ERROR ) { PTDEBUG && _d($EVAL_ERROR); - $protocol = 'http'; + PTDEBUG && _d("SSL not available, won't run version_check"); + return; } PTDEBUG && _d('Using', $protocol); @@ -6514,6 +6516,11 @@ sub get_from_mysql { return; } + if ($item->{item} eq 'MySQL' && $item->{type} eq 'mysql_variable') { + $item->{vars} = ['version_comment', 'version']; + } + + my @versions; my %version_for; foreach my $instance ( @$instances ) { diff --git a/bin/pt-online-schema-change b/bin/pt-online-schema-change index 67aa5343..8c55bfde 100755 --- a/bin/pt-online-schema-change +++ b/bin/pt-online-schema-change @@ -6552,7 +6552,8 @@ sub _split_url { ref($self->{fh}) eq 'IO::Socket::SSL' or die(qq/SSL connection failed for $host\n/); if ( $self->{fh}->can("verify_hostname") ) { - $self->{fh}->verify_hostname( $host, $ssl_verify_args ); + $self->{fh}->verify_hostname( $host, $ssl_verify_args ) + or die(qq/SSL certificate not valid for $host\n/); } else { my $fh = $self->{fh}; @@ -7074,11 +7075,12 @@ sub version_check { PTDEBUG && _d(scalar @$instances_to_check, 'instances to check'); return unless @$instances_to_check; - my $protocol = 'https'; # optimistic, but... + my $protocol = 'https'; eval { require IO::Socket::SSL; }; if ( $EVAL_ERROR ) { PTDEBUG && _d($EVAL_ERROR); - $protocol = 'http'; + PTDEBUG && _d("SSL not available, won't run version_check"); + return; } PTDEBUG && _d('Using', $protocol); @@ -7515,6 +7517,11 @@ sub get_from_mysql { return; } + if ($item->{item} eq 'MySQL' && $item->{type} eq 'mysql_variable') { + $item->{vars} = ['version_comment', 'version']; + } + + my @versions; my %version_for; foreach my $instance ( @$instances ) { diff --git a/bin/pt-query-digest b/bin/pt-query-digest index cdf6ba6b..dbbc7c38 100755 --- a/bin/pt-query-digest +++ b/bin/pt-query-digest @@ -11833,7 +11833,8 @@ sub _split_url { ref($self->{fh}) eq 'IO::Socket::SSL' or die(qq/SSL connection failed for $host\n/); if ( $self->{fh}->can("verify_hostname") ) { - $self->{fh}->verify_hostname( $host, $ssl_verify_args ); + $self->{fh}->verify_hostname( $host, $ssl_verify_args ) + or die(qq/SSL certificate not valid for $host\n/); } else { my $fh = $self->{fh}; @@ -12355,11 +12356,12 @@ sub version_check { PTDEBUG && _d(scalar @$instances_to_check, 'instances to check'); return unless @$instances_to_check; - my $protocol = 'https'; # optimistic, but... + my $protocol = 'https'; eval { require IO::Socket::SSL; }; if ( $EVAL_ERROR ) { PTDEBUG && _d($EVAL_ERROR); - $protocol = 'http'; + PTDEBUG && _d("SSL not available, won't run version_check"); + return; } PTDEBUG && _d('Using', $protocol); @@ -12796,6 +12798,11 @@ sub get_from_mysql { return; } + if ($item->{item} eq 'MySQL' && $item->{type} eq 'mysql_variable') { + $item->{vars} = ['version_comment', 'version']; + } + + my @versions; my %version_for; foreach my $instance ( @$instances ) { diff --git a/bin/pt-slave-delay b/bin/pt-slave-delay index a9c4d063..ff2b4840 100755 --- a/bin/pt-slave-delay +++ b/bin/pt-slave-delay @@ -3097,7 +3097,8 @@ sub _split_url { ref($self->{fh}) eq 'IO::Socket::SSL' or die(qq/SSL connection failed for $host\n/); if ( $self->{fh}->can("verify_hostname") ) { - $self->{fh}->verify_hostname( $host, $ssl_verify_args ); + $self->{fh}->verify_hostname( $host, $ssl_verify_args ) + or die(qq/SSL certificate not valid for $host\n/); } else { my $fh = $self->{fh}; @@ -3619,11 +3620,12 @@ sub version_check { PTDEBUG && _d(scalar @$instances_to_check, 'instances to check'); return unless @$instances_to_check; - my $protocol = 'https'; # optimistic, but... + my $protocol = 'https'; eval { require IO::Socket::SSL; }; if ( $EVAL_ERROR ) { PTDEBUG && _d($EVAL_ERROR); - $protocol = 'http'; + PTDEBUG && _d("SSL not available, won't run version_check"); + return; } PTDEBUG && _d('Using', $protocol); @@ -4060,6 +4062,11 @@ sub get_from_mysql { return; } + if ($item->{item} eq 'MySQL' && $item->{type} eq 'mysql_variable') { + $item->{vars} = ['version_comment', 'version']; + } + + my @versions; my %version_for; foreach my $instance ( @$instances ) { diff --git a/bin/pt-slave-restart b/bin/pt-slave-restart index a336b3f7..72e15d71 100755 --- a/bin/pt-slave-restart +++ b/bin/pt-slave-restart @@ -3746,7 +3746,8 @@ sub _split_url { ref($self->{fh}) eq 'IO::Socket::SSL' or die(qq/SSL connection failed for $host\n/); if ( $self->{fh}->can("verify_hostname") ) { - $self->{fh}->verify_hostname( $host, $ssl_verify_args ); + $self->{fh}->verify_hostname( $host, $ssl_verify_args ) + or die(qq/SSL certificate not valid for $host\n/); } else { my $fh = $self->{fh}; @@ -4268,11 +4269,12 @@ sub version_check { PTDEBUG && _d(scalar @$instances_to_check, 'instances to check'); return unless @$instances_to_check; - my $protocol = 'https'; # optimistic, but... + my $protocol = 'https'; eval { require IO::Socket::SSL; }; if ( $EVAL_ERROR ) { PTDEBUG && _d($EVAL_ERROR); - $protocol = 'http'; + PTDEBUG && _d("SSL not available, won't run version_check"); + return; } PTDEBUG && _d('Using', $protocol); @@ -4709,6 +4711,11 @@ sub get_from_mysql { return; } + if ($item->{item} eq 'MySQL' && $item->{type} eq 'mysql_variable') { + $item->{vars} = ['version_comment', 'version']; + } + + my @versions; my %version_for; foreach my $instance ( @$instances ) { diff --git a/bin/pt-table-checksum b/bin/pt-table-checksum index 3adee83e..7c9a5d70 100755 --- a/bin/pt-table-checksum +++ b/bin/pt-table-checksum @@ -332,7 +332,8 @@ sub _split_url { ref($self->{fh}) eq 'IO::Socket::SSL' or die(qq/SSL connection failed for $host\n/); if ( $self->{fh}->can("verify_hostname") ) { - $self->{fh}->verify_hostname( $host, $ssl_verify_args ); + $self->{fh}->verify_hostname( $host, $ssl_verify_args ) + or die(qq/SSL certificate not valid for $host\n/); } else { my $fh = $self->{fh}; @@ -854,11 +855,12 @@ sub version_check { PTDEBUG && _d(scalar @$instances_to_check, 'instances to check'); return unless @$instances_to_check; - my $protocol = 'https'; # optimistic, but... + my $protocol = 'https'; eval { require IO::Socket::SSL; }; if ( $EVAL_ERROR ) { PTDEBUG && _d($EVAL_ERROR); - $protocol = 'http'; + PTDEBUG && _d("SSL not available, won't run version_check"); + return; } PTDEBUG && _d('Using', $protocol); @@ -1295,6 +1297,11 @@ sub get_from_mysql { return; } + if ($item->{item} eq 'MySQL' && $item->{type} eq 'mysql_variable') { + $item->{vars} = ['version_comment', 'version']; + } + + my @versions; my %version_for; foreach my $instance ( @$instances ) { diff --git a/bin/pt-table-sync b/bin/pt-table-sync index 9d389748..0d82eac1 100755 --- a/bin/pt-table-sync +++ b/bin/pt-table-sync @@ -8605,7 +8605,8 @@ sub _split_url { ref($self->{fh}) eq 'IO::Socket::SSL' or die(qq/SSL connection failed for $host\n/); if ( $self->{fh}->can("verify_hostname") ) { - $self->{fh}->verify_hostname( $host, $ssl_verify_args ); + $self->{fh}->verify_hostname( $host, $ssl_verify_args ) + or die(qq/SSL certificate not valid for $host\n/); } else { my $fh = $self->{fh}; @@ -9127,11 +9128,12 @@ sub version_check { PTDEBUG && _d(scalar @$instances_to_check, 'instances to check'); return unless @$instances_to_check; - my $protocol = 'https'; # optimistic, but... + my $protocol = 'https'; eval { require IO::Socket::SSL; }; if ( $EVAL_ERROR ) { PTDEBUG && _d($EVAL_ERROR); - $protocol = 'http'; + PTDEBUG && _d("SSL not available, won't run version_check"); + return; } PTDEBUG && _d('Using', $protocol); @@ -9568,6 +9570,11 @@ sub get_from_mysql { return; } + if ($item->{item} eq 'MySQL' && $item->{type} eq 'mysql_variable') { + $item->{vars} = ['version_comment', 'version']; + } + + my @versions; my %version_for; foreach my $instance ( @$instances ) { diff --git a/bin/pt-upgrade b/bin/pt-upgrade index cf04c82b..fc0383b1 100755 --- a/bin/pt-upgrade +++ b/bin/pt-upgrade @@ -3545,7 +3545,8 @@ sub _split_url { ref($self->{fh}) eq 'IO::Socket::SSL' or die(qq/SSL connection failed for $host\n/); if ( $self->{fh}->can("verify_hostname") ) { - $self->{fh}->verify_hostname( $host, $ssl_verify_args ); + $self->{fh}->verify_hostname( $host, $ssl_verify_args ) + or die(qq/SSL certificate not valid for $host\n/); } else { my $fh = $self->{fh}; @@ -4067,11 +4068,12 @@ sub version_check { PTDEBUG && _d(scalar @$instances_to_check, 'instances to check'); return unless @$instances_to_check; - my $protocol = 'https'; # optimistic, but... + my $protocol = 'https'; eval { require IO::Socket::SSL; }; if ( $EVAL_ERROR ) { PTDEBUG && _d($EVAL_ERROR); - $protocol = 'http'; + PTDEBUG && _d("SSL not available, won't run version_check"); + return; } PTDEBUG && _d('Using', $protocol); @@ -4508,6 +4510,11 @@ sub get_from_mysql { return; } + if ($item->{item} eq 'MySQL' && $item->{type} eq 'mysql_variable') { + $item->{vars} = ['version_comment', 'version']; + } + + my @versions; my %version_for; foreach my $instance ( @$instances ) { diff --git a/bin/pt-variable-advisor b/bin/pt-variable-advisor index a966883a..20fd21ad 100755 --- a/bin/pt-variable-advisor +++ b/bin/pt-variable-advisor @@ -4004,7 +4004,8 @@ sub _split_url { ref($self->{fh}) eq 'IO::Socket::SSL' or die(qq/SSL connection failed for $host\n/); if ( $self->{fh}->can("verify_hostname") ) { - $self->{fh}->verify_hostname( $host, $ssl_verify_args ); + $self->{fh}->verify_hostname( $host, $ssl_verify_args ) + or die(qq/SSL certificate not valid for $host\n/); } else { my $fh = $self->{fh}; @@ -4526,11 +4527,12 @@ sub version_check { PTDEBUG && _d(scalar @$instances_to_check, 'instances to check'); return unless @$instances_to_check; - my $protocol = 'https'; # optimistic, but... + my $protocol = 'https'; eval { require IO::Socket::SSL; }; if ( $EVAL_ERROR ) { PTDEBUG && _d($EVAL_ERROR); - $protocol = 'http'; + PTDEBUG && _d("SSL not available, won't run version_check"); + return; } PTDEBUG && _d('Using', $protocol); @@ -4967,6 +4969,11 @@ sub get_from_mysql { return; } + if ($item->{item} eq 'MySQL' && $item->{type} eq 'mysql_variable') { + $item->{vars} = ['version_comment', 'version']; + } + + my @versions; my %version_for; foreach my $instance ( @$instances ) { diff --git a/lib/HTTP/Micro.pm b/lib/HTTP/Micro.pm index 859d5ddd..9cc35853 100644 --- a/lib/HTTP/Micro.pm +++ b/lib/HTTP/Micro.pm @@ -237,7 +237,8 @@ sub _split_url { ref($self->{fh}) eq 'IO::Socket::SSL' or die(qq/SSL connection failed for $host\n/); if ( $self->{fh}->can("verify_hostname") ) { - $self->{fh}->verify_hostname( $host, $ssl_verify_args ); + $self->{fh}->verify_hostname( $host, $ssl_verify_args ) + or die(qq/SSL certificate not valid for $host\n/); } else { # Can't use $self->{fh}->verify_hostname because the IO::Socket::SSL diff --git a/lib/VersionCheck.pm b/lib/VersionCheck.pm index 18294fae..07454a4f 100644 --- a/lib/VersionCheck.pm +++ b/lib/VersionCheck.pm @@ -138,17 +138,17 @@ sub version_check { PTDEBUG && _d(scalar @$instances_to_check, 'instances to check'); return unless @$instances_to_check; - # Get the list of program to check from Percona. Try using - # https first; fallback to http if that fails (probably because - # IO::Socket::SSL isn't installed). - my $protocol = 'https'; # optimistic, but... + # Skip Version Check altogether if SSL not available + my $protocol = 'https'; eval { require IO::Socket::SSL; }; if ( $EVAL_ERROR ) { PTDEBUG && _d($EVAL_ERROR); - $protocol = 'http'; + PTDEBUG && _d("SSL not available, won't run version_check"); + return; } PTDEBUG && _d('Using', $protocol); + # Get list of programs to check from Percona. my $advice = pingback( instances => $instances_to_check, protocol => $protocol, @@ -644,6 +644,13 @@ sub get_from_mysql { return; } + # hardcode the variables we report + # so in case of MITM attack, we don't report sensitive data + if ($item->{item} eq 'MySQL' && $item->{type} eq 'mysql_variable') { + $item->{vars} = ['version_comment', 'version']; + } + + my @versions; my %version_for; foreach my $instance ( @$instances ) { From f8c8411297f46571e577fb236dadb195ad87a930 Mon Sep 17 00:00:00 2001 From: Frank Cizmich Date: Mon, 19 Jan 2015 14:58:47 -0200 Subject: [PATCH 16/23] simplified conditional for testing if HOME is set --- bin/pt-ioprofile | 2 +- bin/pt-mext | 2 +- bin/pt-mysql-summary | 2 +- bin/pt-pmp | 2 +- bin/pt-sift | 2 +- bin/pt-stalk | 2 +- bin/pt-summary | 2 +- lib/bash/parse_options.sh | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/bin/pt-ioprofile b/bin/pt-ioprofile index 83951b18..123cd0a0 100755 --- a/bin/pt-ioprofile +++ b/bin/pt-ioprofile @@ -202,7 +202,7 @@ parse_options() { done else _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" - if [ ! -z "${HOME-}" ]; then + if [ "${HOME:-}" ]; then _parse_config_files "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" fi fi diff --git a/bin/pt-mext b/bin/pt-mext index 60310a99..0fb7e1fb 100755 --- a/bin/pt-mext +++ b/bin/pt-mext @@ -243,7 +243,7 @@ parse_options() { done else _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" - if [ ! -z "${HOME-}" ]; then + if [ "${HOME:-}" ]; then _parse_config_files "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" fi fi diff --git a/bin/pt-mysql-summary b/bin/pt-mysql-summary index fab7fd91..287d39ad 100755 --- a/bin/pt-mysql-summary +++ b/bin/pt-mysql-summary @@ -204,7 +204,7 @@ parse_options() { done else _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" - if [ ! -z "${HOME-}" ]; then + if [ "${HOME:-}" ]; then _parse_config_files "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" fi fi diff --git a/bin/pt-pmp b/bin/pt-pmp index 2fed95fa..8f029967 100755 --- a/bin/pt-pmp +++ b/bin/pt-pmp @@ -245,7 +245,7 @@ parse_options() { done else _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" - if [ ! -z "${HOME-}" ]; then + if [ "${HOME:-}" ]; then _parse_config_files "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" fi fi diff --git a/bin/pt-sift b/bin/pt-sift index 4660fe0d..53f5e4d8 100755 --- a/bin/pt-sift +++ b/bin/pt-sift @@ -243,7 +243,7 @@ parse_options() { done else _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" - if [ ! -z "${HOME-}" ]; then + if [ "${HOME:-}" ]; then _parse_config_files "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" fi fi diff --git a/bin/pt-stalk b/bin/pt-stalk index ece14424..568f4587 100755 --- a/bin/pt-stalk +++ b/bin/pt-stalk @@ -256,7 +256,7 @@ parse_options() { done else _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" - if [ ! -z "${HOME-}" ]; then + if [ "${HOME:-}" ]; then _parse_config_files "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" fi fi diff --git a/bin/pt-summary b/bin/pt-summary index 1e045113..af68ccf7 100755 --- a/bin/pt-summary +++ b/bin/pt-summary @@ -211,7 +211,7 @@ parse_options() { done else _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" - if [ ! -z "${HOME-}" ]; then + if [ "${HOME:-}" ]; then _parse_config_files "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" fi fi diff --git a/lib/bash/parse_options.sh b/lib/bash/parse_options.sh index d5a3fed0..eee9e154 100644 --- a/lib/bash/parse_options.sh +++ b/lib/bash/parse_options.sh @@ -215,7 +215,7 @@ parse_options() { else _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" # conditional in case $HOME isn't set; e.g. tool launched from init - if [ ! -z "${HOME-}" ]; then + if [ "${HOME:-}" ]; then _parse_config_files "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" fi fi From 9ae40a9eb958d7a52578ee983fb5657c944c8679 Mon Sep 17 00:00:00 2001 From: Frank Cizmich Date: Mon, 19 Jan 2015 20:16:06 -0200 Subject: [PATCH 17/23] pt-tcs added testcase for timezone bug --- t/pt-table-checksum/bugs.t | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/t/pt-table-checksum/bugs.t b/t/pt-table-checksum/bugs.t index cf67a889..2d9fb00d 100644 --- a/t/pt-table-checksum/bugs.t +++ b/t/pt-table-checksum/bugs.t @@ -294,6 +294,31 @@ like( "Bug 1210537: tool ran" ); +# ############################################################################# +# pt-table-checksum has errors when slaves have different system_time_zone +# https://bugs.launchpad.net/percona-toolkit/+bug/1388870 +# ############################################################################# + +# make slave set diferent system_time_zone by changing env var TZ. +diag(`/tmp/12346/stop >/dev/null`); +diag(`export TZ='HST';/tmp/12346/start >/dev/null`); + +$output = output( + sub { pt_table_checksum::main(@args, qw(-t sakila.payment)) }, +); + + +is( + PerconaTest::count_checksum_results($output, 'diffs'), + 0, + "Bug 1388870 - No false positive reported when system_tz differ on slave" +); + +# restore slave to original system_tz +diag(`/tmp/12346/stop >/dev/null`); +diag(`/tmp/12346/start >/dev/null`); + + # ############################################################################# # Done. # ############################################################################# From c0b230668f35affaa84c30c9a9006a897035a5eb Mon Sep 17 00:00:00 2001 From: Frank Cizmich Date: Tue, 20 Jan 2015 15:28:56 -0200 Subject: [PATCH 18/23] fixed NibbleIterator test --- t/lib/NibbleIterator.t | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/t/lib/NibbleIterator.t b/t/lib/NibbleIterator.t index 701f2698..3a7276d2 100644 --- a/t/lib/NibbleIterator.t +++ b/t/lib/NibbleIterator.t @@ -392,35 +392,35 @@ $ni = make_nibble_iter( my $row = $ni->next(); is_deeply( $row, - [25, 'd9c52498'], + [25, '303d7b91'], "SELECT chunk checksum 1 FROM sakila.country" ) or diag(Dumper($row)); $row = $ni->next(); is_deeply( $row, - [25, 'ebdc982c'], + [25, '5a5d203a'], "SELECT chunk checksum 2 FROM sakila.country" ) or diag(Dumper($row)); $row = $ni->next(); is_deeply( $row, - [25, 'e8d9438d'], + [25, '7328e41c'], "SELECT chunk checksum 3 FROM sakila.country" ) or diag(Dumper($row)); $row = $ni->next(); is_deeply( $row, - [25, '2e3b895d'], + [25, '7ef0c3e0'], "SELECT chunk checksum 4 FROM sakila.country" ) or diag(Dumper($row)); $row = $ni->next(); is_deeply( $row, - [9, 'bd08fd55'], + [9, '40067b8e'], "SELECT chunk checksum 5 FROM sakila.country" ) or diag(Dumper($row)); From 63c953834c2ed003085ffdc378e7a79838685eec Mon Sep 17 00:00:00 2001 From: Frank Cizmich Date: Tue, 20 Jan 2015 16:18:11 -0200 Subject: [PATCH 19/23] minor tweak of VersionCheck for ease of testing --- lib/VersionCheck.pm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/VersionCheck.pm b/lib/VersionCheck.pm index 07454a4f..616df25a 100644 --- a/lib/VersionCheck.pm +++ b/lib/VersionCheck.pm @@ -644,10 +644,10 @@ sub get_from_mysql { return; } - # hardcode the variables we report - # so in case of MITM attack, we don't report sensitive data + # Only allow version variables to be reported + # So in case of MITM attack, we don't report sensitive data if ($item->{item} eq 'MySQL' && $item->{type} eq 'mysql_variable') { - $item->{vars} = ['version_comment', 'version']; + @{$item->{vars}} = grep { $_ eq 'version' || $_ eq 'version_comment' } @{$item->{vars}}; } From f52271e9994dc1f0e17f1e7d97a90a36224c6ded Mon Sep 17 00:00:00 2001 From: Frank Cizmich Date: Wed, 21 Jan 2015 14:25:09 -0200 Subject: [PATCH 20/23] tweaked checksum test to work in differing timezones --- t/lib/NibbleIterator.t | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/t/lib/NibbleIterator.t b/t/lib/NibbleIterator.t index 3a7276d2..d9ada0e8 100644 --- a/t/lib/NibbleIterator.t +++ b/t/lib/NibbleIterator.t @@ -389,41 +389,59 @@ $ni = make_nibble_iter( select => $chunk_checksum, ); +# The following tests need a trick to make the timestamp column consistent +# across different test servers. +# Sakila uses '2006-02-15 11:44:00' for this column, which is converted to +# a different epoch vaule in different timezones, resulting in different +# checksum values according to the tz of the server where sakila was created. + +# save original value, just in case +my ($orig_datetime) = $dbh->selectrow_array("SELECT last_update FROM sakila.country LIMIT 1"); +# get locat datetime for UTC 2006-02-15 11:44:00 +my ($local_datetime_for_fixed_timestamp) = $dbh->selectrow_array("SELECT FROM_UNIXTIME(1140003840)"); +$dbh->do("UPDATE sakila.country SET last_update = '$local_datetime_for_fixed_timestamp'"); + +# now the following checksums are fixed, no matter the test server timezone +# where the sakila database was created my $row = $ni->next(); is_deeply( $row, - [25, '303d7b91'], + [25, 'a947cb12'], "SELECT chunk checksum 1 FROM sakila.country" ) or diag(Dumper($row)); $row = $ni->next(); is_deeply( $row, - [25, '5a5d203a'], + [25, 'c32790b9'], "SELECT chunk checksum 2 FROM sakila.country" ) or diag(Dumper($row)); $row = $ni->next(); is_deeply( $row, - [25, '7328e41c'], + [25, 'ea52549f'], "SELECT chunk checksum 3 FROM sakila.country" ) or diag(Dumper($row)); $row = $ni->next(); is_deeply( $row, - [25, '7ef0c3e0'], + [25, 'e78a7363'], "SELECT chunk checksum 4 FROM sakila.country" ) or diag(Dumper($row)); $row = $ni->next(); is_deeply( $row, - [9, '40067b8e'], + [9, 'd97ccb0d'], "SELECT chunk checksum 5 FROM sakila.country" ) or diag(Dumper($row)); +# revert timestamp to original value, in case other tests use it +$dbh->do("UPDATE sakila.country SET last_update = '$orig_datetime'"); + + # ######################################################################### # exec_nibble callback and explain_sth # ######################################################################### From 8af390e8be22ae8a68a23f77ba61ab39f5f2081c Mon Sep 17 00:00:00 2001 From: Frank Cizmich Date: Wed, 21 Jan 2015 16:42:22 -0200 Subject: [PATCH 21/23] fixed gtid_parallelreplication test --- t/pt-slave-restart/gtid_parallelreplication.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/pt-slave-restart/gtid_parallelreplication.t b/t/pt-slave-restart/gtid_parallelreplication.t index 439870f4..de5276c7 100644 --- a/t/pt-slave-restart/gtid_parallelreplication.t +++ b/t/pt-slave-restart/gtid_parallelreplication.t @@ -49,7 +49,7 @@ my $output=`$trunk/bin/pt-slave-restart --run-time=1s -h 127.0.0.1 -P 12346 -u m like( $output, - qr/It is impossible to skip transactions properly./, + qr/Cannot skip transactions properly.*slave_parallel_workers/, "pt-slave-restart exits with multiple replication threads" ); From 1ccd6e528ac251a7a4eb7f8b7d6f025f9b7a6394 Mon Sep 17 00:00:00 2001 From: Frank Cizmich Date: Thu, 22 Jan 2015 10:51:26 -0200 Subject: [PATCH 22/23] changed version, added changelog, fixed pxc.t --- Changelog | 16 ++++++++++++++++ bin/pt-align | 2 +- bin/pt-archiver | 4 ++-- bin/pt-config-diff | 4 ++-- bin/pt-deadlock-logger | 4 ++-- bin/pt-diskstats | 4 ++-- bin/pt-duplicate-key-checker | 4 ++-- bin/pt-fifo-split | 2 +- bin/pt-find | 4 ++-- bin/pt-fingerprint | 2 +- bin/pt-fk-error-logger | 4 ++-- bin/pt-heartbeat | 4 ++-- bin/pt-index-usage | 4 ++-- bin/pt-ioprofile | 2 +- bin/pt-kill | 4 ++-- bin/pt-mext | 2 +- bin/pt-mysql-summary | 2 +- bin/pt-online-schema-change | 4 ++-- bin/pt-pmp | 2 +- bin/pt-query-digest | 4 ++-- bin/pt-show-grants | 2 +- bin/pt-sift | 2 +- bin/pt-slave-delay | 4 ++-- bin/pt-slave-find | 2 +- bin/pt-slave-restart | 4 ++-- bin/pt-stalk | 2 +- bin/pt-summary | 2 +- bin/pt-table-checksum | 4 ++-- bin/pt-table-sync | 4 ++-- bin/pt-table-usage | 2 +- bin/pt-upgrade | 4 ++-- bin/pt-variable-advisor | 4 ++-- bin/pt-visual-explain | 2 +- lib/Percona/Toolkit.pm | 2 +- t/pt-table-checksum/pxc.t | 6 +++--- 35 files changed, 70 insertions(+), 54 deletions(-) diff --git a/Changelog b/Changelog index 58cf1058..61b98f4a 100644 --- a/Changelog +++ b/Changelog @@ -1,5 +1,21 @@ Changelog for Percona Toolkit + + * Feature 1391240: pt-kill added query fingerprint hash to output + * Fixed bug 1402668: pt-mysql-summary fails on cluster in Donor/Desynced status + * Fixed bug 1396870: pt-online-schema-change CTRL+C leaves terminal in inconsistent state + * Fixed bug 1396868: pt-online-schema-change --ask-pass option error + * Fixed bug 1266869: pt-stalk fails to start if $HOME environment variable is not set + * Fixed bug 1019479: pt-table-checksum does not work with sql_mode ONLY_FULL_GROUP_BY + * Fixed bug 1394934: pt-table-checksum error in debug mode + * Fixed bug 1321297: pt-table-checksum reports diffs on timestamp columns in 5.5 vs 5.6 + * Fixed bug 1399789: pt-table-checksum fails to find pxc nodes when wsrep_node_incoming_address is set to AUTO + * Fixed bug 1388870: pt-table-checksum has some errors with different time zones + * Fixed bug 1408375: vulnerable to MITM attack which would allow exfiltration of MySQL configuration information via --version-check + * Fixed bug 1404298: missing MySQL5.7 test files for pt-table-checksum + * Fixed bug 1403900: added sandbox and fixed sakila test db for 5.7 + + v2.2.12 released 2014-11-14 diff --git a/bin/pt-align b/bin/pt-align index b9adcc2e..082299c2 100755 --- a/bin/pt-align +++ b/bin/pt-align @@ -1331,6 +1331,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-align 2.2.12 +pt-align 2.2.13 =cut diff --git a/bin/pt-archiver b/bin/pt-archiver index af0ccfaf..999dc6e9 100755 --- a/bin/pt-archiver +++ b/bin/pt-archiver @@ -43,7 +43,7 @@ BEGIN { { package Percona::Toolkit; -our $VERSION = '2.2.12'; +our $VERSION = '2.2.13'; use strict; use warnings FATAL => 'all'; @@ -7910,6 +7910,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-archiver 2.2.12 +pt-archiver 2.2.13 =cut diff --git a/bin/pt-config-diff b/bin/pt-config-diff index 94020013..a71bccd3 100755 --- a/bin/pt-config-diff +++ b/bin/pt-config-diff @@ -43,7 +43,7 @@ BEGIN { { package Percona::Toolkit; -our $VERSION = '2.2.12'; +our $VERSION = '2.2.13'; use strict; use warnings FATAL => 'all'; @@ -5783,6 +5783,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-config-diff 2.2.12 +pt-config-diff 2.2.13 =cut diff --git a/bin/pt-deadlock-logger b/bin/pt-deadlock-logger index cec2dfe2..42f00e32 100755 --- a/bin/pt-deadlock-logger +++ b/bin/pt-deadlock-logger @@ -42,7 +42,7 @@ BEGIN { { package Percona::Toolkit; -our $VERSION = '2.2.12'; +our $VERSION = '2.2.13'; use strict; use warnings FATAL => 'all'; @@ -5573,6 +5573,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-deadlock-logger 2.2.12 +pt-deadlock-logger 2.2.13 =cut diff --git a/bin/pt-diskstats b/bin/pt-diskstats index ded40200..8400d000 100755 --- a/bin/pt-diskstats +++ b/bin/pt-diskstats @@ -38,7 +38,7 @@ BEGIN { { package Percona::Toolkit; -our $VERSION = '2.2.12'; +our $VERSION = '2.2.13'; use strict; use warnings FATAL => 'all'; @@ -5586,6 +5586,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-diskstats 2.2.12 +pt-diskstats 2.2.13 =cut diff --git a/bin/pt-duplicate-key-checker b/bin/pt-duplicate-key-checker index e75fd9cc..8d61a5eb 100755 --- a/bin/pt-duplicate-key-checker +++ b/bin/pt-duplicate-key-checker @@ -39,7 +39,7 @@ BEGIN { { package Percona::Toolkit; -our $VERSION = '2.2.12'; +our $VERSION = '2.2.13'; use strict; use warnings FATAL => 'all'; @@ -5607,6 +5607,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-duplicate-key-checker 2.2.12 +pt-duplicate-key-checker 2.2.13 =cut diff --git a/bin/pt-fifo-split b/bin/pt-fifo-split index 74245a3b..84f9a28b 100755 --- a/bin/pt-fifo-split +++ b/bin/pt-fifo-split @@ -1620,6 +1620,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-fifo-split 2.2.12 +pt-fifo-split 2.2.13 =cut diff --git a/bin/pt-find b/bin/pt-find index a71b41b8..ca2a19f4 100755 --- a/bin/pt-find +++ b/bin/pt-find @@ -35,7 +35,7 @@ BEGIN { { package Percona::Toolkit; -our $VERSION = '2.2.12'; +our $VERSION = '2.2.13'; use strict; use warnings FATAL => 'all'; @@ -4991,6 +4991,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-find 2.2.12 +pt-find 2.2.13 =cut diff --git a/bin/pt-fingerprint b/bin/pt-fingerprint index c08c20c9..192a3641 100755 --- a/bin/pt-fingerprint +++ b/bin/pt-fingerprint @@ -2211,6 +2211,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-fingerprint 2.2.12 +pt-fingerprint 2.2.13 =cut diff --git a/bin/pt-fk-error-logger b/bin/pt-fk-error-logger index 1d8a0ee6..eb4757c6 100755 --- a/bin/pt-fk-error-logger +++ b/bin/pt-fk-error-logger @@ -37,7 +37,7 @@ BEGIN { { package Percona::Toolkit; -our $VERSION = '2.2.12'; +our $VERSION = '2.2.13'; use strict; use warnings FATAL => 'all'; @@ -4559,6 +4559,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-fk-error-logger 2.2.12 +pt-fk-error-logger 2.2.13 =cut diff --git a/bin/pt-heartbeat b/bin/pt-heartbeat index a018ea59..17115c59 100755 --- a/bin/pt-heartbeat +++ b/bin/pt-heartbeat @@ -38,7 +38,7 @@ BEGIN { { package Percona::Toolkit; -our $VERSION = '2.2.12'; +our $VERSION = '2.2.13'; use strict; use warnings FATAL => 'all'; @@ -6225,6 +6225,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-heartbeat 2.2.12 +pt-heartbeat 2.2.13 =cut diff --git a/bin/pt-index-usage b/bin/pt-index-usage index 4b62a7cf..361f282e 100755 --- a/bin/pt-index-usage +++ b/bin/pt-index-usage @@ -45,7 +45,7 @@ BEGIN { { package Percona::Toolkit; -our $VERSION = '2.2.12'; +our $VERSION = '2.2.13'; use strict; use warnings FATAL => 'all'; @@ -7555,6 +7555,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-index-usage 2.2.12 +pt-index-usage 2.2.13 =cut diff --git a/bin/pt-ioprofile b/bin/pt-ioprofile index 123cd0a0..c8bd4c74 100755 --- a/bin/pt-ioprofile +++ b/bin/pt-ioprofile @@ -1125,7 +1125,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-ioprofile 2.2.12 +pt-ioprofile 2.2.13 =cut diff --git a/bin/pt-kill b/bin/pt-kill index 4e3ad04a..f5ccead9 100755 --- a/bin/pt-kill +++ b/bin/pt-kill @@ -47,7 +47,7 @@ BEGIN { { package Percona::Toolkit; -our $VERSION = '2.2.12'; +our $VERSION = '2.2.13'; use strict; use warnings FATAL => 'all'; @@ -8254,6 +8254,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-kill 2.2.12 +pt-kill 2.2.13 =cut diff --git a/bin/pt-mext b/bin/pt-mext index 0fb7e1fb..cb974ca3 100755 --- a/bin/pt-mext +++ b/bin/pt-mext @@ -801,7 +801,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-mext 2.2.12 +pt-mext 2.2.13 =cut diff --git a/bin/pt-mysql-summary b/bin/pt-mysql-summary index 6b5076b8..2a2dd092 100755 --- a/bin/pt-mysql-summary +++ b/bin/pt-mysql-summary @@ -3088,7 +3088,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-mysql-summary 2.2.12 +pt-mysql-summary 2.2.13 =cut diff --git a/bin/pt-online-schema-change b/bin/pt-online-schema-change index 1b8a799d..d7b0d83f 100755 --- a/bin/pt-online-schema-change +++ b/bin/pt-online-schema-change @@ -55,7 +55,7 @@ BEGIN { { package Percona::Toolkit; -our $VERSION = '2.2.12'; +our $VERSION = '2.2.13'; use strict; use warnings FATAL => 'all'; @@ -11807,6 +11807,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-online-schema-change 2.2.12 +pt-online-schema-change 2.2.13 =cut diff --git a/bin/pt-pmp b/bin/pt-pmp index 8f029967..02db953e 100755 --- a/bin/pt-pmp +++ b/bin/pt-pmp @@ -895,7 +895,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-pmp 2.2.12 +pt-pmp 2.2.13 =cut diff --git a/bin/pt-query-digest b/bin/pt-query-digest index dbbc7c38..1b9a8454 100755 --- a/bin/pt-query-digest +++ b/bin/pt-query-digest @@ -64,7 +64,7 @@ BEGIN { { package Percona::Toolkit; -our $VERSION = '2.2.12'; +our $VERSION = '2.2.13'; use strict; use warnings FATAL => 'all'; @@ -16624,6 +16624,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-query-digest 2.2.12 +pt-query-digest 2.2.13 =cut diff --git a/bin/pt-show-grants b/bin/pt-show-grants index 9e4c02e3..9fcc733f 100755 --- a/bin/pt-show-grants +++ b/bin/pt-show-grants @@ -2414,6 +2414,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-show-grants 2.2.12 +pt-show-grants 2.2.13 =cut diff --git a/bin/pt-sift b/bin/pt-sift index 53f5e4d8..94d9576c 100755 --- a/bin/pt-sift +++ b/bin/pt-sift @@ -1243,7 +1243,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-sift 2.2.12 +pt-sift 2.2.13 =cut diff --git a/bin/pt-slave-delay b/bin/pt-slave-delay index ff2b4840..d7595760 100755 --- a/bin/pt-slave-delay +++ b/bin/pt-slave-delay @@ -40,7 +40,7 @@ BEGIN { { package Percona::Toolkit; -our $VERSION = '2.2.12'; +our $VERSION = '2.2.13'; use strict; use warnings FATAL => 'all'; @@ -4876,6 +4876,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-slave-delay 2.2.12 +pt-slave-delay 2.2.13 =cut diff --git a/bin/pt-slave-find b/bin/pt-slave-find index 568e9dfb..4c8a1169 100755 --- a/bin/pt-slave-find +++ b/bin/pt-slave-find @@ -4342,6 +4342,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-slave-find 2.2.12 +pt-slave-find 2.2.13 =cut diff --git a/bin/pt-slave-restart b/bin/pt-slave-restart index 72e15d71..51d64717 100755 --- a/bin/pt-slave-restart +++ b/bin/pt-slave-restart @@ -41,7 +41,7 @@ BEGIN { { package Percona::Toolkit; -our $VERSION = '2.2.12'; +our $VERSION = '2.2.13'; use strict; use warnings FATAL => 'all'; @@ -5944,6 +5944,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-slave-restart 2.2.12 +pt-slave-restart 2.2.13 =cut diff --git a/bin/pt-stalk b/bin/pt-stalk index 568f4587..da3fbeb6 100755 --- a/bin/pt-stalk +++ b/bin/pt-stalk @@ -2241,7 +2241,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-stalk 2.2.12 +pt-stalk 2.2.13 =cut diff --git a/bin/pt-summary b/bin/pt-summary index af68ccf7..1e3da759 100755 --- a/bin/pt-summary +++ b/bin/pt-summary @@ -2696,7 +2696,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-summary 2.2.12 +pt-summary 2.2.13 =cut diff --git a/bin/pt-table-checksum b/bin/pt-table-checksum index 3d1a24e2..5de8e7f1 100755 --- a/bin/pt-table-checksum +++ b/bin/pt-table-checksum @@ -57,7 +57,7 @@ BEGIN { { package Percona::Toolkit; -our $VERSION = '2.2.12'; +our $VERSION = '2.2.13'; use strict; use warnings FATAL => 'all'; @@ -12788,6 +12788,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-table-checksum 2.2.12 +pt-table-checksum 2.2.13 =cut diff --git a/bin/pt-table-sync b/bin/pt-table-sync index 0d82eac1..39e3e7a5 100755 --- a/bin/pt-table-sync +++ b/bin/pt-table-sync @@ -55,7 +55,7 @@ BEGIN { { package Percona::Toolkit; -our $VERSION = '2.2.12'; +our $VERSION = '2.2.13'; use strict; use warnings FATAL => 'all'; @@ -12775,6 +12775,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-table-sync 2.2.12 +pt-table-sync 2.2.13 =cut diff --git a/bin/pt-table-usage b/bin/pt-table-usage index 4d86326a..815cc98f 100755 --- a/bin/pt-table-usage +++ b/bin/pt-table-usage @@ -7571,6 +7571,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-table-usage 2.2.12 +pt-table-usage 2.2.13 =cut diff --git a/bin/pt-upgrade b/bin/pt-upgrade index 6ebc54c4..13746689 100755 --- a/bin/pt-upgrade +++ b/bin/pt-upgrade @@ -61,7 +61,7 @@ BEGIN { { package Percona::Toolkit; -our $VERSION = '2.2.12'; +our $VERSION = '2.2.13'; use strict; use warnings FATAL => 'all'; @@ -11290,6 +11290,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-upgrade 2.2.12 +pt-upgrade 2.2.13 =cut diff --git a/bin/pt-variable-advisor b/bin/pt-variable-advisor index 20fd21ad..9bb463ec 100755 --- a/bin/pt-variable-advisor +++ b/bin/pt-variable-advisor @@ -44,7 +44,7 @@ BEGIN { { package Percona::Toolkit; -our $VERSION = '2.2.12'; +our $VERSION = '2.2.13'; use strict; use warnings FATAL => 'all'; @@ -6145,6 +6145,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-variable-advisor 2.2.12 +pt-variable-advisor 2.2.13 =cut diff --git a/bin/pt-visual-explain b/bin/pt-visual-explain index 6379ebad..0e879a72 100755 --- a/bin/pt-visual-explain +++ b/bin/pt-visual-explain @@ -3251,6 +3251,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -pt-visual-explain 2.2.12 +pt-visual-explain 2.2.13 =cut diff --git a/lib/Percona/Toolkit.pm b/lib/Percona/Toolkit.pm index 4dc19a75..494e2ace 100644 --- a/lib/Percona/Toolkit.pm +++ b/lib/Percona/Toolkit.pm @@ -18,7 +18,7 @@ # ########################################################################### package Percona::Toolkit; -our $VERSION = '2.2.12'; +our $VERSION = '2.2.13'; use strict; use warnings FATAL => 'all'; diff --git a/t/pt-table-checksum/pxc.t b/t/pt-table-checksum/pxc.t index 525c6acd..ea25ffb3 100644 --- a/t/pt-table-checksum/pxc.t +++ b/t/pt-table-checksum/pxc.t @@ -242,9 +242,9 @@ sub test_recursion_methods { $node2->do("SET GLOBAL server_id = $orig_id_2"); $node3->do("SET GLOBAL server_id = $orig_id_3"); # reset node wsrep_node_incoming_address to original values - $node1->do("SET GLOBAL wsrep_node_incoming_address = $orig_ia_1"); - $node2->do("SET GLOBAL wsrep_node_incoming_address = $orig_ia_2"); - $node3->do("SET GLOBAL wsrep_node_incoming_address = $orig_ia_3"); + $node1->do("SET GLOBAL wsrep_node_incoming_address = '$orig_ia_1'"); + $node2->do("SET GLOBAL wsrep_node_incoming_address = '$orig_ia_2'"); + $node3->do("SET GLOBAL wsrep_node_incoming_address = '$orig_ia_3'"); } } From 3016c52341c91b140e8e77bc98af606cd997dcaf Mon Sep 17 00:00:00 2001 From: Tomislav Plavcic Date: Fri, 23 Jan 2015 11:19:56 +0100 Subject: [PATCH 23/23] Build percona-toolkit-2.2.13 --- Changelog | 2 ++ Makefile.PL | 2 +- bin/pt-align | 2 +- bin/pt-archiver | 2 +- bin/pt-config-diff | 2 +- bin/pt-deadlock-logger | 2 +- bin/pt-diskstats | 2 +- bin/pt-duplicate-key-checker | 2 +- bin/pt-fifo-split | 2 +- bin/pt-find | 2 +- bin/pt-fingerprint | 2 +- bin/pt-fk-error-logger | 2 +- bin/pt-heartbeat | 2 +- bin/pt-index-usage | 2 +- bin/pt-ioprofile | 2 +- bin/pt-kill | 2 +- bin/pt-mext | 2 +- bin/pt-mysql-summary | 2 +- bin/pt-online-schema-change | 2 +- bin/pt-pmp | 2 +- bin/pt-query-digest | 2 +- bin/pt-show-grants | 2 +- bin/pt-sift | 2 +- bin/pt-slave-delay | 2 +- bin/pt-slave-find | 2 +- bin/pt-slave-restart | 2 +- bin/pt-stalk | 2 +- bin/pt-summary | 2 +- bin/pt-table-checksum | 2 +- bin/pt-table-sync | 2 +- bin/pt-table-usage | 2 +- bin/pt-upgrade | 2 +- bin/pt-variable-advisor | 2 +- bin/pt-visual-explain | 2 +- config/deb/changelog | 18 ++++++++++++++ config/sphinx-build/conf.py | 2 +- docs/percona-toolkit.pod | 4 ++-- docs/release_notes.rst | 46 ++++++++++++++++++++++++++++++++++++ 38 files changed, 102 insertions(+), 36 deletions(-) diff --git a/Changelog b/Changelog index 61b98f4a..2823771d 100644 --- a/Changelog +++ b/Changelog @@ -1,5 +1,7 @@ Changelog for Percona Toolkit +v2.2.13 released 2015-01-26 + * Feature 1391240: pt-kill added query fingerprint hash to output * Fixed bug 1402668: pt-mysql-summary fails on cluster in Donor/Desynced status diff --git a/Makefile.PL b/Makefile.PL index abdf18f7..0ccb4e4a 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -2,7 +2,7 @@ use ExtUtils::MakeMaker; WriteMakefile( NAME => 'percona-toolkit', - VERSION => '2.2.12', + VERSION => '2.2.13', EXE_FILES => [ ], MAN1PODS => { 'docs/percona-toolkit.pod' => 'blib/man1/percona-toolkit.1p', diff --git a/bin/pt-align b/bin/pt-align index 082299c2..6bb356a0 100755 --- a/bin/pt-align +++ b/bin/pt-align @@ -1312,7 +1312,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates, +This program is copyright 2011-2015 Percona LLC and/or its affiliates, 2010-2011 Baron Schwartz. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED diff --git a/bin/pt-archiver b/bin/pt-archiver index 999dc6e9..b2c4f83d 100755 --- a/bin/pt-archiver +++ b/bin/pt-archiver @@ -7891,7 +7891,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates, +This program is copyright 2011-2015 Percona LLC and/or its affiliates, 2007-2011 Baron Schwartz. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED diff --git a/bin/pt-config-diff b/bin/pt-config-diff index a71bccd3..56330e79 100755 --- a/bin/pt-config-diff +++ b/bin/pt-config-diff @@ -5765,7 +5765,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates. +This program is copyright 2011-2015 Percona LLC and/or its affiliates. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF diff --git a/bin/pt-deadlock-logger b/bin/pt-deadlock-logger index 42f00e32..5235a9d2 100755 --- a/bin/pt-deadlock-logger +++ b/bin/pt-deadlock-logger @@ -5554,7 +5554,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates, +This program is copyright 2011-2015 Percona LLC and/or its affiliates, 2007-2011 Baron Schwartz. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED diff --git a/bin/pt-diskstats b/bin/pt-diskstats index 8400d000..96ac0dfa 100755 --- a/bin/pt-diskstats +++ b/bin/pt-diskstats @@ -5567,7 +5567,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates, +This program is copyright 2011-2015 Percona LLC and/or its affiliates, 2010-2011 Baron Schwartz. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED diff --git a/bin/pt-duplicate-key-checker b/bin/pt-duplicate-key-checker index 8d61a5eb..6600b7c9 100755 --- a/bin/pt-duplicate-key-checker +++ b/bin/pt-duplicate-key-checker @@ -5588,7 +5588,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates, +This program is copyright 2011-2015 Percona LLC and/or its affiliates, 2007-2011 Baron Schwartz. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED diff --git a/bin/pt-fifo-split b/bin/pt-fifo-split index 84f9a28b..0dff4447 100755 --- a/bin/pt-fifo-split +++ b/bin/pt-fifo-split @@ -1601,7 +1601,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates, +This program is copyright 2011-2015 Percona LLC and/or its affiliates, 2007-2011 Baron Schwartz. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED diff --git a/bin/pt-find b/bin/pt-find index ca2a19f4..fb1c9ea9 100755 --- a/bin/pt-find +++ b/bin/pt-find @@ -4972,7 +4972,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates, +This program is copyright 2011-2015 Percona LLC and/or its affiliates, 2007-2011 Baron Schwartz. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED diff --git a/bin/pt-fingerprint b/bin/pt-fingerprint index 192a3641..67e60c01 100755 --- a/bin/pt-fingerprint +++ b/bin/pt-fingerprint @@ -2193,7 +2193,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates. +This program is copyright 2011-2015 Percona LLC and/or its affiliates. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF diff --git a/bin/pt-fk-error-logger b/bin/pt-fk-error-logger index eb4757c6..e7783618 100755 --- a/bin/pt-fk-error-logger +++ b/bin/pt-fk-error-logger @@ -4541,7 +4541,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates. +This program is copyright 2011-2015 Percona LLC and/or its affiliates. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF diff --git a/bin/pt-heartbeat b/bin/pt-heartbeat index 17115c59..baf50777 100755 --- a/bin/pt-heartbeat +++ b/bin/pt-heartbeat @@ -6204,7 +6204,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2007-2014 Percona LLC and/or its affiliates, +This program is copyright 2007-2015 Percona LLC and/or its affiliates, 2006 Proven Scaling LLC and Six Apart Ltd. Feedback and improvements are welcome. diff --git a/bin/pt-index-usage b/bin/pt-index-usage index 361f282e..85815f4c 100755 --- a/bin/pt-index-usage +++ b/bin/pt-index-usage @@ -7536,7 +7536,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates, +This program is copyright 2011-2015 Percona LLC and/or its affiliates, 2010-2011 Baron Schwartz. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED diff --git a/bin/pt-ioprofile b/bin/pt-ioprofile index c8bd4c74..d1e73584 100755 --- a/bin/pt-ioprofile +++ b/bin/pt-ioprofile @@ -1106,7 +1106,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates, +This program is copyright 2011-2015 Percona LLC and/or its affiliates, 2010-2011 Baron Schwartz. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED diff --git a/bin/pt-kill b/bin/pt-kill index f5ccead9..3e2e6256 100755 --- a/bin/pt-kill +++ b/bin/pt-kill @@ -8235,7 +8235,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates, +This program is copyright 2011-2015 Percona LLC and/or its affiliates, 2009-2011 Baron Schwartz. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED diff --git a/bin/pt-mext b/bin/pt-mext index cb974ca3..83e19040 100755 --- a/bin/pt-mext +++ b/bin/pt-mext @@ -782,7 +782,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates, +This program is copyright 2011-2015 Percona LLC and/or its affiliates, 2010 Baron Schwartz. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED diff --git a/bin/pt-mysql-summary b/bin/pt-mysql-summary index 2a2dd092..b0fe56d9 100755 --- a/bin/pt-mysql-summary +++ b/bin/pt-mysql-summary @@ -3069,7 +3069,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates, +This program is copyright 2011-2015 Percona LLC and/or its affiliates, 2010-2011 Baron Schwartz. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED diff --git a/bin/pt-online-schema-change b/bin/pt-online-schema-change index d7b0d83f..7ddc6a0f 100755 --- a/bin/pt-online-schema-change +++ b/bin/pt-online-schema-change @@ -11789,7 +11789,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates. +This program is copyright 2011-2015 Percona LLC and/or its affiliates. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF diff --git a/bin/pt-pmp b/bin/pt-pmp index 02db953e..6a56910b 100755 --- a/bin/pt-pmp +++ b/bin/pt-pmp @@ -876,7 +876,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates, +This program is copyright 2011-2015 Percona LLC and/or its affiliates, 2010-2011 Baron Schwartz. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED diff --git a/bin/pt-query-digest b/bin/pt-query-digest index 1b9a8454..697288ca 100755 --- a/bin/pt-query-digest +++ b/bin/pt-query-digest @@ -16606,7 +16606,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2008-2014 Percona LLC and/or its affiliates. +This program is copyright 2008-2015 Percona LLC and/or its affiliates. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF diff --git a/bin/pt-show-grants b/bin/pt-show-grants index 9fcc733f..6a0e34e6 100755 --- a/bin/pt-show-grants +++ b/bin/pt-show-grants @@ -2395,7 +2395,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates, +This program is copyright 2011-2015 Percona LLC and/or its affiliates, 2007-2011 Baron Schwartz. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED diff --git a/bin/pt-sift b/bin/pt-sift index 94d9576c..a87a9f3b 100755 --- a/bin/pt-sift +++ b/bin/pt-sift @@ -1224,7 +1224,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates, +This program is copyright 2011-2015 Percona LLC and/or its affiliates, 2010-2011 Baron Schwartz. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED diff --git a/bin/pt-slave-delay b/bin/pt-slave-delay index d7595760..87d04b7f 100755 --- a/bin/pt-slave-delay +++ b/bin/pt-slave-delay @@ -4857,7 +4857,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates, +This program is copyright 2011-2015 Percona LLC and/or its affiliates, 2007-2011 Sergey Zhuravle and Baron Schwartz. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED diff --git a/bin/pt-slave-find b/bin/pt-slave-find index 4c8a1169..cd447fff 100755 --- a/bin/pt-slave-find +++ b/bin/pt-slave-find @@ -4323,7 +4323,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates, +This program is copyright 2011-2015 Percona LLC and/or its affiliates, 2007-2011 Baron Schwartz. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED diff --git a/bin/pt-slave-restart b/bin/pt-slave-restart index 51d64717..c319a369 100755 --- a/bin/pt-slave-restart +++ b/bin/pt-slave-restart @@ -5925,7 +5925,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates, +This program is copyright 2011-2015 Percona LLC and/or its affiliates, 2007-2011 Baron Schwartz. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED diff --git a/bin/pt-stalk b/bin/pt-stalk index da3fbeb6..4b084187 100755 --- a/bin/pt-stalk +++ b/bin/pt-stalk @@ -2222,7 +2222,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates, +This program is copyright 2011-2015 Percona LLC and/or its affiliates, 2010-2011 Baron Schwartz. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED diff --git a/bin/pt-summary b/bin/pt-summary index 1e3da759..364c9947 100755 --- a/bin/pt-summary +++ b/bin/pt-summary @@ -2677,7 +2677,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates, +This program is copyright 2011-2015 Percona LLC and/or its affiliates, 2010-2011 Baron Schwartz. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED diff --git a/bin/pt-table-checksum b/bin/pt-table-checksum index 5de8e7f1..295af447 100755 --- a/bin/pt-table-checksum +++ b/bin/pt-table-checksum @@ -12769,7 +12769,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates, +This program is copyright 2011-2015 Percona LLC and/or its affiliates, 2007-2011 Baron Schwartz. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED diff --git a/bin/pt-table-sync b/bin/pt-table-sync index 39e3e7a5..36da0d28 100755 --- a/bin/pt-table-sync +++ b/bin/pt-table-sync @@ -12756,7 +12756,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates, +This program is copyright 2011-2015 Percona LLC and/or its affiliates, 2007-2011 Baron Schwartz. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED diff --git a/bin/pt-table-usage b/bin/pt-table-usage index 815cc98f..35a689d9 100755 --- a/bin/pt-table-usage +++ b/bin/pt-table-usage @@ -7553,7 +7553,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2012-2014 Percona LLC and/or its affiliates. +This program is copyright 2012-2015 Percona LLC and/or its affiliates. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF diff --git a/bin/pt-upgrade b/bin/pt-upgrade index 13746689..fb9441bd 100755 --- a/bin/pt-upgrade +++ b/bin/pt-upgrade @@ -11271,7 +11271,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2009-2014 Percona LLC and/or its affiliates. +This program is copyright 2009-2015 Percona LLC and/or its affiliates. Feedback and improvements are welcome. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED diff --git a/bin/pt-variable-advisor b/bin/pt-variable-advisor index 9bb463ec..73052e4d 100755 --- a/bin/pt-variable-advisor +++ b/bin/pt-variable-advisor @@ -6127,7 +6127,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2010-2014 Percona LLC and/or its affiliates. +This program is copyright 2010-2015 Percona LLC and/or its affiliates. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF diff --git a/bin/pt-visual-explain b/bin/pt-visual-explain index 0e879a72..6eed88c7 100755 --- a/bin/pt-visual-explain +++ b/bin/pt-visual-explain @@ -3232,7 +3232,7 @@ software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY -This program is copyright 2011-2014 Percona LLC and/or its affiliates, +This program is copyright 2011-2015 Percona LLC and/or its affiliates, 2007-2011 Baron Schwartz. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED diff --git a/config/deb/changelog b/config/deb/changelog index d825775d..3ea10bfe 100644 --- a/config/deb/changelog +++ b/config/deb/changelog @@ -1,3 +1,21 @@ +percona-toolkit (2.2.13) unstable; urgency=low + + * Feature 1391240: pt-kill added query fingerprint hash to output + * Fixed bug 1402668: pt-mysql-summary fails on cluster in Donor/Desynced status + * Fixed bug 1396870: pt-online-schema-change CTRL+C leaves terminal in inconsistent state + * Fixed bug 1396868: pt-online-schema-change --ask-pass option error + * Fixed bug 1266869: pt-stalk fails to start if $HOME environment variable is not set + * Fixed bug 1019479: pt-table-checksum does not work with sql_mode ONLY_FULL_GROUP_BY + * Fixed bug 1394934: pt-table-checksum error in debug mode + * Fixed bug 1321297: pt-table-checksum reports diffs on timestamp columns in 5.5 vs 5.6 + * Fixed bug 1399789: pt-table-checksum fails to find pxc nodes when wsrep_node_incoming_address is set to AUTO + * Fixed bug 1388870: pt-table-checksum has some errors with different time zones + * Fixed bug 1408375: vulnerable to MITM attack which would allow exfiltration of MySQL configuration information via --version-check + * Fixed bug 1404298: missing MySQL5.7 test files for pt-table-checksum + * Fixed bug 1403900: added sandbox and fixed sakila test db for 5.7 + + -- Percona Toolkit Developers Fri, 23 Jan 2015 10:08:15 +0000 + percona-toolkit (2.2.12) unstable; urgency=low * Fixed bug 1376561: pt-archiver is not able to archive all the rows when a table has a hash partition diff --git a/config/sphinx-build/conf.py b/config/sphinx-build/conf.py index b122a8b9..88a0c7e3 100644 --- a/config/sphinx-build/conf.py +++ b/config/sphinx-build/conf.py @@ -50,7 +50,7 @@ copyright = u'2013, Percona LLC and/or its affiliates' # The short X.Y version. version = '2.2' # The full version, including alpha/beta/rc tags. -release = '2.2.12' +release = '2.2.13' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/percona-toolkit.pod b/docs/percona-toolkit.pod index 5e2427ff..b58a476a 100644 --- a/docs/percona-toolkit.pod +++ b/docs/percona-toolkit.pod @@ -538,7 +538,7 @@ Many people have contributed code over the years. See each tool's =head1 COPYRIGHT, LICENSE, AND WARRANTY -Percona Toolkit is copyright 2011-2014 Percona LLC and/or its affiliates, et al. +Percona Toolkit is copyright 2011-2015 Percona LLC and/or its affiliates, et al. See each program's documentation for complete copyright notices. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED @@ -557,6 +557,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION -Percona Toolkit v2.2.12 released 2014-11-11 +Percona Toolkit v2.2.13 released 2015-01-23 =cut diff --git a/docs/release_notes.rst b/docs/release_notes.rst index 16a3a72f..4dd6d7f8 100644 --- a/docs/release_notes.rst +++ b/docs/release_notes.rst @@ -1,6 +1,52 @@ Release Notes ************* +v2.2.13 released 2015-01-26 +=========================== + +Percona Toolkit 2.2.13 has been released. This release contains one new feature and twelve bug fixes. + +New Features: + +* pt-kill now supports new ``--query-id`` option. This option can be used to print a query fingerprint hash after killing a query to enable the cross-referencing with the pt-query-digest output. This option can be used along with ``--print`` option as well. + +Bugs Fixed: + +* Fixed bug 1019479: pt-table-checksum now works with ``ONLY_FULL_GROUP_BY`` sql_mode. + +* Fixed bug 1394934: running pt-table-checksum in debug mode would cause an error. + +* Fixed bug 1396868: regression introduced in Percona Toolkit 2.2.12 caused pt-online-schema-change not to honor ``--ask-pass`` option. + +* Fixed bug 1399789: pt-table-checksum would fail to find Percona XtraDB Cluster nodes when variable ``wsrep_node_incoming_address`` was set to ``AUTO``. + +* Fixed bug 1408375: Percona Toolkit was vulnerable to MITM attack which could allow exfiltration of MySQL configuration information via ``--version-check`` option. This vulnerability was logged as `CVE 2015-1027 _` + +* Fixed bug 1321297: pt-table-checksum was reporting differences on timestamp columns with replication from 5.5 to 5.6 server version, although the data was identical. + +* Fixed bug 1388870: pt-table-checksum was showing differences if the master and slave were in different time zone. + +* Fixed bug 1402668: pt-mysql-summary would exit if Percona XtraDB Cluster was in ``Donor/Desynced`` state. + +* Fixed bug 1266869: pt-stalk would fail to start if ``$HOME`` environment variable was not set. + +Changelog +--------- + +* Feature 1391240: pt-kill added query fingerprint hash to output +* Fixed bug 1402668: pt-mysql-summary fails on cluster in Donor/Desynced status +* Fixed bug 1396870: pt-online-schema-change CTRL+C leaves terminal in inconsistent state +* Fixed bug 1396868: pt-online-schema-change --ask-pass option error +* Fixed bug 1266869: pt-stalk fails to start if $HOME environment variable is not set +* Fixed bug 1019479: pt-table-checksum does not work with sql_mode ONLY_FULL_GROUP_BY +* Fixed bug 1394934: pt-table-checksum error in debug mode +* Fixed bug 1321297: pt-table-checksum reports diffs on timestamp columns in 5.5 vs 5.6 +* Fixed bug 1399789: pt-table-checksum fails to find pxc nodes when wsrep_node_incoming_address is set to AUTO +* Fixed bug 1388870: pt-table-checksum has some errors with different time zones +* Fixed bug 1408375: vulnerable to MITM attack which would allow exfiltration of MySQL configuration information via --version-check +* Fixed bug 1404298: missing MySQL5.7 test files for pt-table-checksum +* Fixed bug 1403900: added sandbox and fixed sakila test db for 5.7 + v2.2.12 released 2014-11-14 ===========================