From ca8fc5e47e8afbe5e6ae20b3dee4b483d261d33f Mon Sep 17 00:00:00 2001 From: Daniel Nichter Date: Tue, 22 Jan 2013 16:22:59 -0700 Subject: [PATCH 1/2] Add failling test for bug 1103221. Add --utc option, not implemented yet. --- bin/pt-heartbeat | 10 ++++++++++ t/pt-heartbeat/bugs.t | 27 ++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/bin/pt-heartbeat b/bin/pt-heartbeat index 35ab1432..122832c7 100755 --- a/bin/pt-heartbeat +++ b/bin/pt-heartbeat @@ -5863,6 +5863,16 @@ short form: -u; type: string User for login if not current user. +=item --utc + +Ignore system time zones and use only UTC. By default pt-heartbeat does +not check or adjust for different system or MySQL time zones which can +cause the tool to compute the lag incorrectly. Specifying this option is +a good idea because it ensures that the tool works correctly regardless of +time zones, but it also makes the tool backwards-incompatible with +pt-heartbeat 2.1.7 and older (unless the older version of pt-heartbeat +is running on a system that uses UTC). + =item --version Show version and exit. diff --git a/t/pt-heartbeat/bugs.t b/t/pt-heartbeat/bugs.t index d50ef976..3969c395 100644 --- a/t/pt-heartbeat/bugs.t +++ b/t/pt-heartbeat/bugs.t @@ -89,7 +89,7 @@ PerconaTest::wait_for_table($slave1_dbh, 'test.heartbeat', 'server_id=12345'); my $slave1_dsn = $sb->dsn_for('slave1'); # Using full_output here to work around a Perl bug: Only the first explicit # tzset works. -($output) = full_output(sub { +($output) = output(sub { local $ENV{TZ} = '-09:00'; tzset(); pt_heartbeat::main($slave1_dsn, qw(--database test --table heartbeat), @@ -107,6 +107,31 @@ like( stop_all_instances(); + +# ############################################################################# +# pt-heartbeat 2.1.8 doesn't use precision/sub-second timestamps +# https://bugs.launchpad.net/percona-toolkit/+bug/1103221 +# ############################################################################# + +$master_dbh->do('truncate table test.heartbeat'); +$sb->wait_for_slaves; + +my $master_dsn = $sb->dsn_for('master'); + +($output) = output( + sub { + pt_heartbeat::main($master_dsn, qw(--database test --update), + qw(--run-time 1)) + }, +); + +my ($row) = $master_dbh->selectrow_hashref('select * from test.heartbeat'); +like( + $row->{ts}, + qr/\d{4}-\d\d-\d\dT\d+:\d+:\d+\.\d+/, + "Hi-res timestamp (bug 1103221)" +); + # ############################################################################ # Done. # ############################################################################ From 2cc48cb13921355ab90bd96581f93a95e79a499f Mon Sep 17 00:00:00 2001 From: Daniel Nichter Date: Tue, 22 Jan 2013 16:51:33 -0700 Subject: [PATCH 2/2] Implement --utc. --- bin/pt-heartbeat | 18 ++++++++++-------- t/pt-heartbeat/bugs.t | 7 +++---- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/bin/pt-heartbeat b/bin/pt-heartbeat index 122832c7..e7775c49 100755 --- a/bin/pt-heartbeat +++ b/bin/pt-heartbeat @@ -4807,6 +4807,8 @@ sub main { # ######################################################################## # Create the heartbeat table if --create-table was given. # ######################################################################## + my $utc = $o->get('utc'); + my $now_func = $utc ? 'UTC_TIMESTAMP()' : 'NOW()'; my $db_tbl = $q->quote($db, $tbl); my $server_id = $dbh->selectrow_array('SELECT @@server_id'); if ( $o->get('create-table') ) { @@ -4816,7 +4818,7 @@ sub main { $dbh->do($sql); $sql = ($o->get('replace') ? "REPLACE" : "INSERT") - . qq/ INTO $db_tbl (ts, server_id) VALUES (UTC_TIMESTAMP(), $server_id)/; + . qq/ INTO $db_tbl (ts, server_id) VALUES ($now_func, $server_id)/; PTDEBUG && _d($sql); # This may fail if the table already existed and already had this row. # We eval to ignore this possibility. @@ -4913,7 +4915,7 @@ sub main { PTDEBUG && _d('No heartbeat row in table'); if ( $o->get('insert-heartbeat-row') ) { my $sql = "INSERT INTO $db_tbl ($pk_col, ts) " - . "VALUES ('$pk_val', UTC_TIMESTAMP())"; + . "VALUES ('$pk_val', $now_func)"; PTDEBUG && _d($sql); $dbh->do($sql); } @@ -5007,8 +5009,7 @@ sub main { tries => 3, wait => sub { sleep 0.25; return; }, try => sub { - my ($now) = $dbh->selectrow_array(q{SELECT UTC_TIMESTAMP()}); - $sth->execute($now, @vals); + $sth->execute(ts(time, $utc), @vals); PTDEBUG && _d($sth->{Statement}); $sth->finish(); }, @@ -5039,7 +5040,7 @@ sub main { # UNIX_TIMESTAMP(ts) replaces unix_timestamp($ts) -- MySQL is the # authority here, so let it calculate everything. $heartbeat_sql - = "SELECT UNIX_TIMESTAMP(UTC_TIMESTAMP()), UNIX_TIMESTAMP(ts)" + = "SELECT " . ($utc ? 'UNIX_TIMESTAMP(ts)' : 'ts') . ($dbi_driver eq 'mysql' ? '/*!50038, @@hostname AS host*/' : '') . ($id ? "" : ", server_id") . " FROM $db_tbl " @@ -5053,12 +5054,13 @@ sub main { my ($sth) = @_; $sth->execute(); PTDEBUG && _d($sth->{Statement}); - my ($now, $ts, $hostname, $server_id) = $sth->fetchrow_array(); + my ($ts, $hostname, $server_id) = $sth->fetchrow_array(); + my $now = time; PTDEBUG && _d("Heartbeat from server", $server_id, "\n", - " now:", $now, "\n", + " now:", ts($now, $utc), "\n", " ts:", $ts, "\n", "skew:", $skew); - my $delay = $now - $ts - $skew; + my $delay = $now - unix_timestamp($ts, $utc) - $skew; PTDEBUG && _d('Delay', sprintf('%.6f', $delay), 'on', $hostname); # Because we adjust for skew, if the ts are less than skew seconds diff --git a/t/pt-heartbeat/bugs.t b/t/pt-heartbeat/bugs.t index 3969c395..0cff266a 100644 --- a/t/pt-heartbeat/bugs.t +++ b/t/pt-heartbeat/bugs.t @@ -89,11 +89,11 @@ PerconaTest::wait_for_table($slave1_dbh, 'test.heartbeat', 'server_id=12345'); my $slave1_dsn = $sb->dsn_for('slave1'); # Using full_output here to work around a Perl bug: Only the first explicit # tzset works. -($output) = output(sub { +($output) = full_output(sub { local $ENV{TZ} = '-09:00'; tzset(); pt_heartbeat::main($slave1_dsn, qw(--database test --table heartbeat), - qw(--check --master-server-id), $master_port) + qw(--utc --check --master-server-id), $master_port) }); # If the servers use UTC then the lag should be 0.00, or at least @@ -102,12 +102,11 @@ my $slave1_dsn = $sb->dsn_for('slave1'); like( $output, qr/\A\d.\d{2}$/, - "Bug 886059: pt-heartbeat doesn't get confused with differing timezones" + "--utc bypasses time zone differences (bug 886059, bug 1099665)" ); stop_all_instances(); - # ############################################################################# # pt-heartbeat 2.1.8 doesn't use precision/sub-second timestamps # https://bugs.launchpad.net/percona-toolkit/+bug/1103221