polardbxengine/mysql-test/include/assert_transaction_length.inc

247 lines
6.7 KiB
PHP

# ==== Purpose ====
#
# To assert that all transactions in server's binary have the correct
# transaction length information.
#
# ==== Usage ====
#
# [--let $binlog_file= slave-relay-bin.000002]
# [--let $is_relay_log= 1]
# [--let $skip_output= 1]
# --source include/assert_transaction_length.inc
#
# Parameters:
#
# $binlog_file
# The binary or relay log file to be inspected. If not specified,
# the current server binary log file will be inspected.
#
# $is_relay_log
# The log file to be inspected is a relay log. In a relay log
# file is not possible to assert the transaction length of the
# last transaction, as the end_log_pos information is not usable.
#
# $skip_output
# When this option is set, the include will not display the results
# with the summary of the log file evaluation.
#
--let $_atl_data_dir= `SELECT @@datadir`
--let $_atl_log_file= query_get_value(SHOW MASTER STATUS, File, 1)
if ($binlog_file)
{
--let $_atl_log_file= $binlog_file
}
--let $_atl_is_relay_log= 0
if ($is_relay_log)
{
--let $_atl_is_relay_log= 1
}
--let $_atl_prefix= `SELECT UUID()`
--let $_atl_out_file = $MYSQLTEST_VARDIR/tmp/$_atl_prefix.out
--let $_atl_err_file = $MYSQLTEST_VARDIR/tmp/$_atl_prefix.err
--let $_atl_dump_file = $MYSQLTEST_VARDIR/tmp/$_atl_prefix.sql
--exec $MYSQL_BINLOG --force-read --force-if-open $_atl_data_dir/$_atl_log_file > $_atl_dump_file
--let ATL_OUT_FILE = $_atl_out_file
--let ATL_ERR_FILE = $_atl_err_file
--let ATL_DUMP_FILE = $_atl_dump_file
--let ATL_IS_RELAY_LOG = $_atl_is_relay_log
if (!$skip_output)
{
--echo Asserting all GTID transaction length information in '$_atl_log_file'
}
perl;
use strict;
my $dump = $ENV{'ATL_DUMP_FILE'} or die "ATL_DUMP_FILE not set";
my $out = $ENV{'ATL_OUT_FILE'} or die "ATL_OUT_FILE not set";
my $err = $ENV{'ATL_ERR_FILE'} or die "ATL_ERR_FILE not set";
my $is_relay_log = $ENV{'ATL_IS_RELAY_LOG'};
open(FILE, "$dump") or die("Unable to open $dump: $!\n");
my $end_log_pos= 0;
my $error= 0;
my $line;
my $last_log_pos= 0;
my $log_pos= 0;
my $trx_counter= 0;
my $trx_gtid= "n/a";
my $trx_size= 0;
my $trx_start= 0;
my $trx_remaining_size= 0;
sub trx_too_small
{
$trx_remaining_size= abs($trx_remaining_size);
my $calculated_length= $trx_size + $trx_remaining_size;
open ERR, "> $err" or die("Error $? opening $err: $!");
print ERR "\n";
print ERR "Wrong transaction length found for ($trx_gtid) at log file position = $trx_start.\n";
print ERR "Transaction length information ($trx_size) is smaller than calculated length ($calculated_length).\n";
print ERR "Transaction is over sized by $trx_remaining_size bytes at log file position = $log_pos.";
close ERR or die("Error $? closing $err: $!");
$error= 1;
}
sub trx_too_big
{
my $calculated_length= $trx_size - $trx_remaining_size;
open ERR, "> $err" or die("Error $? opening $err: $!");
print ERR "\n";
print ERR "Wrong transaction length found for ($trx_gtid) at log file position = $trx_start.\n";
print ERR "Transaction length information ($trx_size) is bigger than calculated length ($calculated_length).\n";
print ERR "Transaction is missing $trx_remaining_size bytes at log file position = $log_pos.";
close ERR or die("Error $? closing $err: $!");
$error= 1;
}
while (my $line = <FILE>)
{
chomp $line;
# Event begin
if ($line =~ m/^# at /)
{
$last_log_pos = $log_pos;
$log_pos = $line;
$log_pos =~ s/^# at //g;
# Consume the event size from the transaction size
if ($trx_size > 0)
{
$trx_remaining_size = $trx_remaining_size - ($log_pos - $last_log_pos);
if ($trx_remaining_size < 0)
{
trx_too_small();
last;
}
}
}
# Assume end of transaction on INCIDENT or ROTATE with server id 0
if ($line =~ m/^# Incident:/ ||
$line =~ m/^#.*server id 0.*Rotate/)
{
# If we found an INCIDENT, all the events from the last transaction are consumed
if ($trx_remaining_size != 0)
{
trx_too_big();
last;
}
$trx_size = 0;
$trx_remaining_size = 0;
$trx_start = 0;
$trx_gtid = "n/a";
}
# Store the end log pos to be used on the last transaction of binary logs
if ($line =~ m/^#.*end_log_pos/)
{
$end_log_pos = $line;
$end_log_pos =~ s/.*end_log_pos //g;
$end_log_pos =~ s/ .*//g;
}
# Store the GTID being processed (just informed on errors)
if ($line =~ m/^SET.*SESSION.GTID_NEXT=/)
{
$trx_gtid = $line;
$trx_gtid =~ s/.*GTID_NEXT= \'//g; #'
$trx_gtid =~ s/\'.*//g; #'
}
# Gtid information
if ($line =~ m/^#.*original_committed_timestamp.*transaction_length/ )
{
# If we found a GTID, all the events from the last transaction are consumed
if ($trx_remaining_size != 0)
{
trx_too_big();
last;
}
$trx_size = $line;
$trx_size =~ s/.*transaction_length=//g;
$trx_remaining_size = $trx_size;
$trx_start = $log_pos;
$trx_gtid = "n/a";
$trx_counter++;
}
}
close(FILE) or die("Error $? closing $dump: $!");
if (!$is_relay_log)
{
# Consumes the last event by using end_log_pos
if ($error == 0 && $trx_remaining_size > 0)
{
$trx_remaining_size = $trx_remaining_size - ($end_log_pos - $log_pos);
if ($trx_remaining_size < 0)
{
trx_too_small();
}
if ($trx_remaining_size > 0)
{
trx_too_big();
}
}
}
else
{
# Discard last transaction information
if ($trx_size > 0 && $trx_remaining_size > 0)
{
$trx_counter--;
$trx_size = 0;
$trx_remaining_size = 0;
}
}
open OUT, "> $out" or die("Error $? opening $out: $!");
if ($error)
{
print OUT ("assert_transaction_length.inc failed");
}
else {
if ($trx_counter > 0)
{
print OUT "Inspected $trx_counter transactions, all with correct transaction length.";
}
else
{
print OUT "Log file had no transactions with length information.";
}
}
close OUT or die("Error $? closing $out: $!");
EOF
# Load result
--let $_atl_outcome= `SELECT LOAD_FILE('$_ATL_OUT_FILE')`
# Cleanup
--remove_file $_atl_out_file
--remove_file $_atl_dump_file
# If failed, show extra info
if ($_atl_outcome == 'assert_transaction_length.inc failed')
{
--let $extra_debug_info= `SELECT LOAD_FILE('$_ATL_ERR_FILE')`
--remove_file $_atl_err_file
--source include/show_rpl_debug_info.inc
--echo Error asserting GTID transaction length information in '$_atl_log_file'
--die assert_transaction_length.inc failed.
}
# Display successful info if requested
if ($_atl_outcome != 'assert_transaction_length.inc failed')
{
if (!$skip_output)
{
--echo $_atl_outcome
}
}