diff --git a/bin/pt-heartbeat b/bin/pt-heartbeat index 2bae5904..0ea81008 100755 --- a/bin/pt-heartbeat +++ b/bin/pt-heartbeat @@ -5749,33 +5749,6 @@ sub main { : $dsn_defaults; my $dbh = $dp->get_dbh($dp->get_cxn_params($dsn), {AutoCommit=>1}); - # we need binlog_format = STATEMENT for this session - # note that ROW is the default format in 5.7+ - if ( VersionParser->new($dbh) >= '5.1.5' ) { - my $sql = 'SELECT @@binlog_format'; - PTDEBUG && _d($dbh, $sql); - my ($original_binlog_format) = $dbh->selectrow_array($sql); - PTDEBUG && _d('Original binlog_format:', $original_binlog_format); - if ( $original_binlog_format !~ /STATEMENT/i ) { - $sql = q{/*!50108 SET @@binlog_format = 'STATEMENT'*/}; - eval { - PTDEBUG && _d($dbh, $sql); - $dbh->do($sql); - }; - if ( $EVAL_ERROR ) { - die "Failed to $sql: $EVAL_ERROR\n" - . "This tool requires binlog_format=STATEMENT, " - . "but the current binlog_format is set to " - ."$original_binlog_format and an error occurred while " - . "attempting to change it. If running MySQL 5.1.29 or newer, " - . "setting binlog_format requires the SUPER privilege. " - . "You will need to manually set binlog_format to 'STATEMENT' " - . "before running this tool.\n"; - } - } - } - - $dbh->{InactiveDestroy} = 1; # Don't disconnect on fork $dbh->{FetchHashKeyName} = 'NAME_lc'; $dbh->do("USE `$db`"); @@ -5818,20 +5791,34 @@ sub main { $sql =~ s/heartbeat/IF NOT EXISTS $db_tbl/; PTDEBUG && _d($sql); $dbh->do($sql); + + # Now we insert first row. + # Some caveats: - $sql = ($o->get('replace') ? "REPLACE" : "INSERT") - . qq/ INTO $db_tbl (ts, server_id) VALUES ($now_func, $server_id)/; - PTDEBUG && _d($sql); + # 1) # This may fail if the table already existed and already had this row. # We eval to ignore this possibility. # NOTE: This can break replication though! See: # https://bugs.launchpad.net/percona-toolkit/+bug/1004567 # So --replace should be used in most cases. - # - # Addendum: binlog_format = ROW makes both REPLACE and INSERT fail in - # Perl's DBI in this cirumstance. Until this is fixed we have to - # attempt to change binlog_row to STATEMENT at the start of the run - eval { $dbh->do($sql); }; + my $sql_insert_row = ($o->get('replace') ? "REPLACE" : "INSERT") + . qq/ INTO $db_tbl (ts, server_id) VALUES ($now_func, $server_id)/; + + # 2) + # RBR (Row Based Replication) converts REPLACE to INSERT if row isn't + # present in master. This breakes replication when the row is present in slave. + # Other workarounds also fail. + # INSERT IGNORE (ignore is not replicated if no error in master) + # DELETE then INSERT (DELETE is ignored, INSERT breaks replication) + # INSERT ON DUPLICATE UPDATE (converts to simple INSERT) + # TRUNCATE gets trough and replicates! So we use that to wipe slave(s). + if ($o->get('replace')) { + my $sql_truncate = "TRUNCATE TABLE $db_tbl"; + PTDEBUG && _d($sql_truncate); + eval { $dbh->do($sql_truncate) }; + } + PTDEBUG && _d($sql_insert_row); + eval { $dbh->do($sql_insert_row); }; } # ########################################################################