mirror of
https://github.com/percona/percona-toolkit.git
synced 2025-09-10 05:00:45 +00:00
Merge 2.1.9 fixes.
This commit is contained in:
@@ -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
|
||||
@@ -5863,6 +5865,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.
|
||||
|
@@ -20,23 +20,32 @@ PTFUNCNAME=""
|
||||
PTDEBUG="${PTDEBUG:-""}"
|
||||
EXIT_STATUS=0
|
||||
|
||||
log() {
|
||||
TS=$(date +%F-%T | tr ':-' '_');
|
||||
ts() {
|
||||
TS=$(date +%F-%T | tr ':-' '_')
|
||||
echo "$TS $*"
|
||||
}
|
||||
|
||||
info() {
|
||||
[ ${OPT_VERBOSE:-3} -ge 3 ] && ts "$*"
|
||||
}
|
||||
|
||||
log() {
|
||||
[ ${OPT_VERBOSE:-3} -ge 2 ] && ts "$*"
|
||||
}
|
||||
|
||||
warn() {
|
||||
log "$*" >&2
|
||||
[ ${OPT_VERBOSE:-3} -ge 1 ] && ts "$*" >&2
|
||||
EXIT_STATUS=1
|
||||
}
|
||||
|
||||
die() {
|
||||
warn "$*"
|
||||
ts "$*" >&2
|
||||
EXIT_STATUS=1
|
||||
exit 1
|
||||
}
|
||||
|
||||
_d () {
|
||||
[ "$PTDEBUG" ] && echo "# $PTFUNCNAME: $(log "$*")" >&2
|
||||
[ "$PTDEBUG" ] && echo "# $PTFUNCNAME: $(ts "$*")" >&2
|
||||
}
|
||||
|
||||
# ###########################################################################
|
||||
@@ -861,7 +870,7 @@ main() {
|
||||
# Execute the program if it was not included from another file.
|
||||
# This makes it possible to include without executing, and thus test.
|
||||
if [ "${0##*/}" = "$TOOL" ] \
|
||||
|| [ "${0##*/}" = "bash" -a "$_" = "$0" ]; then
|
||||
|| [ "${0##*/}" = "bash" -a "${_:-""}" = "$0" ]; then
|
||||
|
||||
# Parse command line options. We must do this first so we can
|
||||
# see if --daemonize was specified.
|
||||
|
@@ -22,23 +22,32 @@ PTFUNCNAME=""
|
||||
PTDEBUG="${PTDEBUG:-""}"
|
||||
EXIT_STATUS=0
|
||||
|
||||
log() {
|
||||
TS=$(date +%F-%T | tr ':-' '_');
|
||||
ts() {
|
||||
TS=$(date +%F-%T | tr ':-' '_')
|
||||
echo "$TS $*"
|
||||
}
|
||||
|
||||
info() {
|
||||
[ ${OPT_VERBOSE:-3} -ge 3 ] && ts "$*"
|
||||
}
|
||||
|
||||
log() {
|
||||
[ ${OPT_VERBOSE:-3} -ge 2 ] && ts "$*"
|
||||
}
|
||||
|
||||
warn() {
|
||||
log "$*" >&2
|
||||
[ ${OPT_VERBOSE:-3} -ge 1 ] && ts "$*" >&2
|
||||
EXIT_STATUS=1
|
||||
}
|
||||
|
||||
die() {
|
||||
warn "$*"
|
||||
ts "$*" >&2
|
||||
EXIT_STATUS=1
|
||||
exit 1
|
||||
}
|
||||
|
||||
_d () {
|
||||
[ "$PTDEBUG" ] && echo "# $PTFUNCNAME: $(log "$*")" >&2
|
||||
[ "$PTDEBUG" ] && echo "# $PTFUNCNAME: $(ts "$*")" >&2
|
||||
}
|
||||
|
||||
# ###########################################################################
|
||||
@@ -2412,7 +2421,7 @@ main() {
|
||||
# Execute the program if it was not included from another file.
|
||||
# This makes it possible to include without executing, and thus test.
|
||||
if [ "${0##*/}" = "$TOOL" ] \
|
||||
|| [ "${0##*/}" = "bash" -a "$_" = "$0" ]; then
|
||||
|| [ "${0##*/}" = "bash" -a "${_:-""}" = "$0" ]; then
|
||||
|
||||
# Set up temporary dir.
|
||||
mk_tmpdir
|
||||
|
@@ -3348,7 +3348,7 @@ sub check_table {
|
||||
die "I need a $arg argument" unless $args{$arg};
|
||||
}
|
||||
my ($dbh, $db, $tbl) = @args{@required_args};
|
||||
my $q = $self->{Quoter};
|
||||
my $q = $self->{Quoter} || 'Quoter';
|
||||
my $db_tbl = $q->quote($db, $tbl);
|
||||
PTDEBUG && _d('Checking', $db_tbl);
|
||||
|
||||
@@ -8450,19 +8450,74 @@ sub main {
|
||||
# Find a pk or unique index to use for the delete trigger. can_nibble()
|
||||
# above returns an index, but NibbleIterator will use non-unique indexes,
|
||||
# so we have to do this again here.
|
||||
my $indexes = $new_tbl->{tbl_struct}->{keys}; # brevity
|
||||
foreach my $index ( $tp->sort_indexes($new_tbl->{tbl_struct}) ) {
|
||||
if ( $index eq 'PRIMARY' || $indexes->{$index}->{is_unique} ) {
|
||||
PTDEBUG && _d('Delete trigger index:', Dumper($index));
|
||||
$new_tbl->{del_index} = $index;
|
||||
last;
|
||||
{
|
||||
my $indexes = $new_tbl->{tbl_struct}->{keys}; # brevity
|
||||
foreach my $index ( $tp->sort_indexes($new_tbl->{tbl_struct}) ) {
|
||||
if ( $index eq 'PRIMARY' || $indexes->{$index}->{is_unique} ) {
|
||||
PTDEBUG && _d('Delete trigger new index:', Dumper($index));
|
||||
$new_tbl->{del_index} = $index;
|
||||
last;
|
||||
}
|
||||
}
|
||||
PTDEBUG && _d('New table delete index:', $new_tbl->{del_index});
|
||||
}
|
||||
|
||||
{
|
||||
my $indexes = $orig_tbl->{tbl_struct}->{keys}; # brevity
|
||||
foreach my $index ( $tp->sort_indexes($orig_tbl->{tbl_struct}) ) {
|
||||
if ( $index eq 'PRIMARY' || $indexes->{$index}->{is_unique} ) {
|
||||
PTDEBUG && _d('Delete trigger orig index:', Dumper($index));
|
||||
$orig_tbl->{del_index} = $index;
|
||||
last;
|
||||
}
|
||||
}
|
||||
PTDEBUG && _d('Orig table delete index:', $orig_tbl->{del_index});
|
||||
}
|
||||
|
||||
if ( !$new_tbl->{del_index} ) {
|
||||
die "The new table $new_tbl->{name} does not have a PRIMARY KEY "
|
||||
. "or a unique index which is required for the DELETE trigger.\n";
|
||||
}
|
||||
|
||||
# Determine whether to use the new or orig table delete index.
|
||||
# The new table del index is preferred due to
|
||||
# https://bugs.launchpad.net/percona-toolkit/+bug/1062324
|
||||
# In short, if the chosen del index is re-created with new columns,
|
||||
# its original columns may be dropped, so just use its new columns.
|
||||
# But, due to https://bugs.launchpad.net/percona-toolkit/+bug/1103672,
|
||||
# the chosen del index on the new table may reference columns which
|
||||
# do not/no longer exist in the orig table, so we check for this
|
||||
# and, if it's the case, we fall back to using the del index from
|
||||
# the orig table.
|
||||
my $del_tbl = $new_tbl; # preferred
|
||||
my $new_del_index_cols # brevity
|
||||
= $new_tbl->{tbl_struct}->{keys}->{ $new_tbl->{del_index} }->{cols};
|
||||
foreach my $new_del_index_col ( @$new_del_index_cols ) {
|
||||
if ( !exists $orig_cols->{$new_del_index_col} ) {
|
||||
if ( !$orig_tbl->{del_index} ) {
|
||||
die "The new table index $new_tbl->{del_index} would be used "
|
||||
. "for the DELETE trigger, but it uses column "
|
||||
. "$new_del_index_col which does not exist in the original "
|
||||
. "table and the original table does not have a PRIMARY KEY "
|
||||
. "or a unique index to use for the DELETE trigger.\n";
|
||||
}
|
||||
print "Using original table index $orig_tbl->{del_index} for the "
|
||||
. "DELETE trigger instead of new table index $new_tbl->{del_index} "
|
||||
. "because the new table index uses column $new_del_index_col "
|
||||
. "which does not exist in the original table.\n";
|
||||
$del_tbl = $orig_tbl;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
my $del_cols
|
||||
= $del_tbl->{tbl_struct}->{keys}->{ $del_tbl->{del_index} }->{cols};
|
||||
PTDEBUG && _d('Index for delete trigger: table', $del_tbl->{name},
|
||||
'index', $del_tbl->{del_index},
|
||||
'columns', @$del_cols);
|
||||
}
|
||||
|
||||
# ########################################################################
|
||||
# Step 3: Create the triggers to capture changes on the original table and
|
||||
# apply them to the new table.
|
||||
@@ -8492,6 +8547,7 @@ sub main {
|
||||
create_triggers(
|
||||
orig_tbl => $orig_tbl,
|
||||
new_tbl => $new_tbl,
|
||||
del_tbl => $del_tbl,
|
||||
columns => \@common_cols,
|
||||
Cxn => $cxn,
|
||||
Quoter => $q,
|
||||
@@ -9010,6 +9066,28 @@ sub check_alter {
|
||||
|
||||
my $ok = 1;
|
||||
|
||||
# ########################################################################
|
||||
# Check for DROP PRIMARY KEY.
|
||||
# ########################################################################
|
||||
if ( $alter =~ m/DROP\s+PRIMARY\s+KEY/i ) {
|
||||
my $msg = "--alter contains 'DROP PRIMARY KEY'. Dropping and "
|
||||
. "altering the primary key can be dangerous, "
|
||||
. "especially if the original table does not have other "
|
||||
. "unique indexes.\n";
|
||||
if ( $dry_run ) {
|
||||
print $msg;
|
||||
}
|
||||
else {
|
||||
$ok = 0;
|
||||
warn $msg
|
||||
. "The tool should handle this correctly, but you should "
|
||||
. "test it first and carefully examine the triggers which "
|
||||
. "rely on the PRIMARY KEY or a unique index. Specify "
|
||||
. "--no-check-alter to disable this check and perform the "
|
||||
. "--alter.\n";
|
||||
}
|
||||
}
|
||||
|
||||
# ########################################################################
|
||||
# Check for renamed columns.
|
||||
# https://bugs.launchpad.net/percona-toolkit/+bug/1068562
|
||||
@@ -9056,6 +9134,7 @@ sub check_alter {
|
||||
}
|
||||
|
||||
if ( !$ok ) {
|
||||
# check_alter.t relies on this output.
|
||||
die "--check-alter failed.\n";
|
||||
}
|
||||
|
||||
@@ -9616,11 +9695,11 @@ sub drop_swap {
|
||||
|
||||
sub create_triggers {
|
||||
my ( %args ) = @_;
|
||||
my @required_args = qw(orig_tbl new_tbl columns Cxn Quoter OptionParser);
|
||||
my @required_args = qw(orig_tbl new_tbl del_tbl columns Cxn Quoter OptionParser);
|
||||
foreach my $arg ( @required_args ) {
|
||||
die "I need a $arg argument" unless $args{$arg};
|
||||
}
|
||||
my ($orig_tbl, $new_tbl, $cols, $cxn, $q, $o) = @args{@required_args};
|
||||
my ($orig_tbl, $new_tbl, $del_tbl, $cols, $cxn, $q, $o) = @args{@required_args};
|
||||
|
||||
# This sub works for --dry-run and --execute. With --dry-run it's
|
||||
# only interesting if --print is specified, too; then the user can
|
||||
@@ -9649,8 +9728,8 @@ sub create_triggers {
|
||||
# unique indexes can be nullable. Cols are from the new table and
|
||||
# they may have been renamed
|
||||
my %old_col_for = map { $_->{new} => $_->{old} } @$cols;
|
||||
my $tbl_struct = $new_tbl->{tbl_struct};
|
||||
my $del_index = $new_tbl->{del_index};
|
||||
my $tbl_struct = $del_tbl->{tbl_struct};
|
||||
my $del_index = $del_tbl->{del_index};
|
||||
my $del_index_cols = join(" AND ", map {
|
||||
my $new_col = $_;
|
||||
my $old_col = $old_col_for{$new_col} || $new_col;
|
||||
@@ -9778,6 +9857,10 @@ sub exec_nibble {
|
||||
# Ignore this warning because we have purposely set statement-based
|
||||
# replication.
|
||||
1592 => 1,
|
||||
# Error: 1062 SQLSTATE: 23000 ( ER_DUP_ENTRY )
|
||||
# Message: Duplicate entry '%ld' for key '%s'
|
||||
# MariaDB 5.5.28+ has this as a warning; See https://bugs.launchpad.net/percona-toolkit/+bug/1099836
|
||||
1062 => 1,
|
||||
);
|
||||
|
||||
# Warn once per-table for these error codes if the error message
|
||||
@@ -9852,6 +9935,7 @@ sub exec_nibble {
|
||||
. "Specify --statistics to see a count of all "
|
||||
. "suppressed warnings and errors.\n";
|
||||
}
|
||||
warn $err;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -10306,9 +10390,19 @@ In previous versions of the tool, renaming a column with
|
||||
C<CHANGE COLUMN name new_name> would lead to that column's data being lost.
|
||||
The tool now parses the alter statement and tries to catch these cases, so
|
||||
the renamed columns should have the same data as the originals. However, the
|
||||
code that does this is not a full-blown SQL parser, so we recommend that users
|
||||
run the tool with L<"--dry-run"> and check if it's detecting the renames
|
||||
correctly.
|
||||
code that does this is not a full-blown SQL parser, so you should first
|
||||
run the tool with L<"--dry-run"> and L<"--print"> and verify that it detects
|
||||
the renamed columns correctly.
|
||||
|
||||
=item DROP PRIMARY KEY
|
||||
|
||||
If L<"--alter"> contain C<DROP PRIMARY KEY> (case- and space-insensitive),
|
||||
a warning is printed and the tool exits unless L<"--dry-run"> is specified.
|
||||
Altering the primary key can be dangerous, but the tool can handle it.
|
||||
The tool's triggers, particularly the DELETE trigger, are most affected by
|
||||
altering the primary key because the tool prefers to use the primary key
|
||||
for its triggers. You should first run the tool with L<"--dry-run"> and
|
||||
L<"--print"> and verify that the triggers are correct.
|
||||
|
||||
=back
|
||||
|
||||
|
@@ -215,7 +215,7 @@ main() {
|
||||
# Execute the program if it was not included from another file. This makes it
|
||||
# possible to include without executing, and thus test.
|
||||
if [ "${0##*/}" = "$TOOL" ] \
|
||||
|| [ "${0##*/}" = "bash" -a "$_" = "$0" ]; then
|
||||
|| [ "${0##*/}" = "bash" -a "${_:-""}" = "$0" ]; then
|
||||
mk_tmpdir
|
||||
main "$@"
|
||||
rm_tmpdir
|
||||
|
@@ -587,7 +587,7 @@ main() {
|
||||
# Execute the program if it was not included from another file. This makes it
|
||||
# possible to include without executing, and thus test.
|
||||
if [ "${0##*/}" = "$TOOL" ] \
|
||||
|| [ "${0##*/}" = "bash" -a "$_" = "$0" ]; then
|
||||
|| [ "${0##*/}" = "bash" -a "${_:-""}" = "$0" ]; then
|
||||
main "${@:-""}"
|
||||
fi
|
||||
|
||||
|
67
bin/pt-stalk
67
bin/pt-stalk
@@ -22,23 +22,32 @@ PTFUNCNAME=""
|
||||
PTDEBUG="${PTDEBUG:-""}"
|
||||
EXIT_STATUS=0
|
||||
|
||||
log() {
|
||||
TS=$(date +%F-%T | tr ':-' '_');
|
||||
ts() {
|
||||
TS=$(date +%F-%T | tr ':-' '_')
|
||||
echo "$TS $*"
|
||||
}
|
||||
|
||||
info() {
|
||||
[ ${OPT_VERBOSE:-3} -ge 3 ] && ts "$*"
|
||||
}
|
||||
|
||||
log() {
|
||||
[ ${OPT_VERBOSE:-3} -ge 2 ] && ts "$*"
|
||||
}
|
||||
|
||||
warn() {
|
||||
log "$*" >&2
|
||||
[ ${OPT_VERBOSE:-3} -ge 1 ] && ts "$*" >&2
|
||||
EXIT_STATUS=1
|
||||
}
|
||||
|
||||
die() {
|
||||
warn "$*"
|
||||
ts "$*" >&2
|
||||
EXIT_STATUS=1
|
||||
exit 1
|
||||
}
|
||||
|
||||
_d () {
|
||||
[ "$PTDEBUG" ] && echo "# $PTFUNCNAME: $(log "$*")" >&2
|
||||
[ "$PTDEBUG" ] && echo "# $PTFUNCNAME: $(ts "$*")" >&2
|
||||
}
|
||||
|
||||
# ###########################################################################
|
||||
@@ -962,6 +971,10 @@ after_collect_sleep() {
|
||||
:
|
||||
}
|
||||
|
||||
after_interval_sleep() {
|
||||
:
|
||||
}
|
||||
|
||||
after_stalk() {
|
||||
:
|
||||
}
|
||||
@@ -1066,9 +1079,7 @@ sleep_ok() {
|
||||
local seconds="$1"
|
||||
local msg="${2:-""}"
|
||||
if oktorun; then
|
||||
if [ -n "$msg" ]; then
|
||||
log "$msg"
|
||||
fi
|
||||
[ "$msg" ] && info "$msg"
|
||||
sleep $seconds
|
||||
fi
|
||||
}
|
||||
@@ -1126,7 +1137,11 @@ stalk() {
|
||||
fi
|
||||
|
||||
local msg="Check results: $OPT_VARIABLE=$value, matched=${matched:-no}, cycles_true=$cycles_true"
|
||||
log "$msg"
|
||||
if [ "$matched" ]; then
|
||||
log "$msg"
|
||||
else
|
||||
info "$msg"
|
||||
fi
|
||||
elif [ "$OPT_COLLECT" ]; then
|
||||
# Make the next if condition true.
|
||||
matched=1
|
||||
@@ -1140,7 +1155,7 @@ stalk() {
|
||||
# ##################################################################
|
||||
# Start collecting, maybe.
|
||||
# ##################################################################
|
||||
log "Collect triggered"
|
||||
log "Collect $ITER triggered"
|
||||
|
||||
# Send email to whomever that collect has been triggered.
|
||||
if [ "$OPT_NOTIFY_BY_EMAIL" ]; then
|
||||
@@ -1166,8 +1181,8 @@ stalk() {
|
||||
"$margin"
|
||||
if [ $? -eq 0 ]; then
|
||||
# There should be enough disk space, so collect.
|
||||
log "$msg" >> "$OPT_DEST/$prefix-trigger"
|
||||
log "pt-stalk ran with $RAN_WITH" >> "$OPT_DEST/$prefix-trigger"
|
||||
ts "$msg" >> "$OPT_DEST/$prefix-trigger"
|
||||
ts "pt-stalk ran with $RAN_WITH" >> "$OPT_DEST/$prefix-trigger"
|
||||
last_prefix="$prefix"
|
||||
|
||||
# Plugin hook:
|
||||
@@ -1181,7 +1196,7 @@ stalk() {
|
||||
collect "$OPT_DEST" "$prefix"
|
||||
) >> "$OPT_DEST/$prefix-output" 2>&1 &
|
||||
local collector_pid=$!
|
||||
log "Collector PID $collector_pid"
|
||||
log "Collect $ITER PID $collector_pid"
|
||||
|
||||
# Plugin hook:
|
||||
after_collect $collector_pid
|
||||
@@ -1199,6 +1214,7 @@ stalk() {
|
||||
# ##################################################################
|
||||
# Done collecting.
|
||||
# ##################################################################
|
||||
log "Collect $ITER done"
|
||||
ITER=$((ITER + 1))
|
||||
cycles_true=0
|
||||
sleep_ok "$OPT_SLEEP" "Sleeping $OPT_SLEEP seconds after collect"
|
||||
@@ -1208,6 +1224,9 @@ stalk() {
|
||||
else
|
||||
# Trigger/check/value is ok, sleep until next check.
|
||||
sleep_ok "$OPT_INTERVAL"
|
||||
|
||||
# Plugin hook:
|
||||
after_interval_sleep
|
||||
fi
|
||||
done
|
||||
|
||||
@@ -1291,7 +1310,7 @@ main() {
|
||||
# Execute the program if it was not included from another file.
|
||||
# This makes it possible to include without executing, and thus test.
|
||||
if [ "${0##*/}" = "$TOOL" ] \
|
||||
|| [ "${0##*/}" = "bash" -a "$_" = "$0" ]; then
|
||||
|| [ "${0##*/}" = "bash" -a "${_:-""}" = "$0" ]; then
|
||||
|
||||
# Parse command line options. We must do this first so we can
|
||||
# see if --daemonize was specified.
|
||||
@@ -1737,6 +1756,10 @@ C<after_collect_sleep>.
|
||||
Called after sleeping L<"--sleep"> seconds for the collector process to finish.
|
||||
This hook is called after C<after_collect>.
|
||||
|
||||
=item after_interval_sleep
|
||||
|
||||
Called after sleeping L<"--interval"> seconds after each trigger check.
|
||||
|
||||
=item after_stalk
|
||||
|
||||
Called after stalking. Since pt-stalk stalks forever by default,
|
||||
@@ -1840,6 +1863,22 @@ type: string; default: Threads_running
|
||||
|
||||
The variable to compare against the threshold. See L<"--function"> for details.
|
||||
|
||||
=item --verbose
|
||||
|
||||
type: int; default: 2
|
||||
|
||||
Print more or less information while running. Since the tool is designed
|
||||
to be a long-running daemon, the default verbosity level only prints the
|
||||
most important information. If you run the tool interactively, you may
|
||||
want to use a higher verbosity level.
|
||||
|
||||
LEVEL PRINTS
|
||||
===== =====================================
|
||||
0 Errors
|
||||
1 Warnings
|
||||
2 Matching triggers and collection info
|
||||
3 Non-matching triggers
|
||||
|
||||
=item --version
|
||||
|
||||
Print tool's version and exit.
|
||||
|
@@ -29,23 +29,32 @@ PTFUNCNAME=""
|
||||
PTDEBUG="${PTDEBUG:-""}"
|
||||
EXIT_STATUS=0
|
||||
|
||||
log() {
|
||||
TS=$(date +%F-%T | tr ':-' '_');
|
||||
ts() {
|
||||
TS=$(date +%F-%T | tr ':-' '_')
|
||||
echo "$TS $*"
|
||||
}
|
||||
|
||||
info() {
|
||||
[ ${OPT_VERBOSE:-3} -ge 3 ] && ts "$*"
|
||||
}
|
||||
|
||||
log() {
|
||||
[ ${OPT_VERBOSE:-3} -ge 2 ] && ts "$*"
|
||||
}
|
||||
|
||||
warn() {
|
||||
log "$*" >&2
|
||||
[ ${OPT_VERBOSE:-3} -ge 1 ] && ts "$*" >&2
|
||||
EXIT_STATUS=1
|
||||
}
|
||||
|
||||
die() {
|
||||
warn "$*"
|
||||
ts "$*" >&2
|
||||
EXIT_STATUS=1
|
||||
exit 1
|
||||
}
|
||||
|
||||
_d () {
|
||||
[ "$PTDEBUG" ] && echo "# $PTFUNCNAME: $(log "$*")" >&2
|
||||
[ "$PTDEBUG" ] && echo "# $PTFUNCNAME: $(ts "$*")" >&2
|
||||
}
|
||||
|
||||
# ###########################################################################
|
||||
@@ -2280,7 +2289,7 @@ sigtrap() { local PTFUNCNAME=sigtrap;
|
||||
# Execute the program if it was not included from another file. This makes it
|
||||
# possible to include without executing, and thus test.
|
||||
if [ "${0##*/}" = "$TOOL" ] \
|
||||
|| [ "${0##*/}" = "bash" -a "$_" = "$0" ]; then
|
||||
|| [ "${0##*/}" = "bash" -a "${_:-""}" = "$0" ]; then
|
||||
|
||||
# Set up temporary dir.
|
||||
mk_tmpdir
|
||||
|
@@ -8774,12 +8774,13 @@ sub main {
|
||||
}
|
||||
|
||||
if ( $master_binlog ne $slave_binlog ) {
|
||||
$err .= $master_cxn->name() . " has binlog_format "
|
||||
. $master_binlog . " but replica " . $slave_cxn->name()
|
||||
. " has binlog_format $slave_binlog. This could cause "
|
||||
. "pt-table-checksum to break replication. "
|
||||
. "If you understand the risks, specify "
|
||||
. "--no-check-binlog-format to disable this check.\n";
|
||||
$err .= "Replica " . $slave_cxn->name()
|
||||
. qq{ has binlog_format $slave_binlog which could cause }
|
||||
. qq{pt-table-checksum to break replication. Please read }
|
||||
. qq{"Replicas using row-based replication" in the }
|
||||
. qq{LIMITATIONS section of the tool's documentation. }
|
||||
. qq{If you understand the risks, specify }
|
||||
. qq{--no-check-binlog-format to disable this check.\n};
|
||||
}
|
||||
}
|
||||
die $err if $err;
|
||||
|
@@ -10582,6 +10582,7 @@ sub sync_a_table {
|
||||
trim => $o->get('trim'),
|
||||
wait => $o->get('wait'),
|
||||
function => $o->get('function'),
|
||||
trace => !$ENV{PT_TEST_NO_TRACE},
|
||||
);
|
||||
|
||||
if ( sum(@status{@ChangeHandler::ACTIONS}) ) {
|
||||
@@ -11281,19 +11282,30 @@ sub diff_where {
|
||||
PTDEBUG && _d('Ascend params:', Dumper($asc));
|
||||
}
|
||||
|
||||
my $lb_sql = $asc->{boundaries}->{'>='};
|
||||
foreach my $val ( $q->deserialize_list($diff->{lower_boundary}) ) {
|
||||
my $quoted_val = $q->quote_val($val);
|
||||
$lb_sql =~ s/\?/$quoted_val/;
|
||||
my ($lb_sql, $ub_sql);
|
||||
|
||||
if ( defined $diff->{lower_boundary} ) {
|
||||
$lb_sql = $asc->{boundaries}->{'>='};
|
||||
foreach my $val ( $q->deserialize_list($diff->{lower_boundary}) ) {
|
||||
my $quoted_val = $q->quote_val($val);
|
||||
$lb_sql =~ s/\?/$quoted_val/;
|
||||
}
|
||||
}
|
||||
|
||||
my $ub_sql = $asc->{boundaries}->{'<='};
|
||||
foreach my $val ( $q->deserialize_list($diff->{upper_boundary}) ) {
|
||||
my $quoted_val = $q->quote_val($val);
|
||||
$ub_sql =~ s/\?/$quoted_val/;
|
||||
if ( defined $diff->{upper_boundary} ) {
|
||||
$ub_sql = $asc->{boundaries}->{'<='};
|
||||
foreach my $val ( $q->deserialize_list($diff->{upper_boundary}) ) {
|
||||
my $quoted_val = $q->quote_val($val);
|
||||
$ub_sql =~ s/\?/$quoted_val/;
|
||||
}
|
||||
}
|
||||
|
||||
return "$lb_sql AND $ub_sql";
|
||||
die "Invalid checksum diff: " . Dumper($diff)
|
||||
unless $lb_sql || $ub_sql;
|
||||
|
||||
return $lb_sql && $ub_sql ? "$lb_sql AND $ub_sql"
|
||||
: $lb_sql ? $lb_sql
|
||||
: $ub_sql;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -58,7 +58,6 @@ our @EXPORT = qw(
|
||||
wait_until
|
||||
wait_for
|
||||
wait_until_slave_running
|
||||
wait_until_no_lag
|
||||
test_log_parser
|
||||
test_protocol_parser
|
||||
test_packet_parser
|
||||
@@ -325,6 +324,39 @@ sub wait_for_sh {
|
||||
);
|
||||
};
|
||||
|
||||
sub kill_program {
|
||||
my (%args) = @_;
|
||||
|
||||
my $pid_file = $args{pid_file};
|
||||
my $pid = $args{pid};
|
||||
|
||||
if ( $pid_file ) {
|
||||
chomp($pid = `cat $pid_file 2>/dev/null`);
|
||||
}
|
||||
|
||||
if ( $pid ) {
|
||||
PTDEVDEBUG && _d('Killing PID', $pid);
|
||||
kill(15, $pid);
|
||||
wait_until(
|
||||
sub { my $is_alive = kill(0, $pid); return !$is_alive; },
|
||||
1.5, # sleep between tries
|
||||
15, # max time to try
|
||||
);
|
||||
if ( kill(0, $pid) ) {
|
||||
warn "PID $pid did not die; using kill -9\n";
|
||||
kill(9, $pid);
|
||||
}
|
||||
}
|
||||
else {
|
||||
PTDEVDEBUG && _d('No PID to kill');
|
||||
}
|
||||
|
||||
if ( $pid_file && -f $pid_file ) {
|
||||
PTDEVDEBUG && _d('Removing PID file', $pid_file);
|
||||
unlink $pid_file;
|
||||
}
|
||||
}
|
||||
|
||||
sub not_running {
|
||||
my ($cmd) = @_;
|
||||
PTDEVDEBUG && _d('Wait until not running:', $cmd);
|
||||
|
@@ -302,7 +302,7 @@ sub check_table {
|
||||
die "I need a $arg argument" unless $args{$arg};
|
||||
}
|
||||
my ($dbh, $db, $tbl) = @args{@required_args};
|
||||
my $q = $self->{Quoter};
|
||||
my $q = $self->{Quoter} || 'Quoter';
|
||||
my $db_tbl = $q->quote($db, $tbl);
|
||||
PTDEBUG && _d('Checking', $db_tbl);
|
||||
|
||||
|
@@ -28,23 +28,32 @@ PTFUNCNAME=""
|
||||
PTDEBUG="${PTDEBUG:-""}"
|
||||
EXIT_STATUS=0
|
||||
|
||||
log() {
|
||||
TS=$(date +%F-%T | tr ':-' '_');
|
||||
ts() {
|
||||
TS=$(date +%F-%T | tr ':-' '_')
|
||||
echo "$TS $*"
|
||||
}
|
||||
|
||||
info() {
|
||||
[ ${OPT_VERBOSE:-3} -ge 3 ] && ts "$*"
|
||||
}
|
||||
|
||||
log() {
|
||||
[ ${OPT_VERBOSE:-3} -ge 2 ] && ts "$*"
|
||||
}
|
||||
|
||||
warn() {
|
||||
log "$*" >&2
|
||||
[ ${OPT_VERBOSE:-3} -ge 1 ] && ts "$*" >&2
|
||||
EXIT_STATUS=1
|
||||
}
|
||||
|
||||
die() {
|
||||
warn "$*"
|
||||
ts "$*" >&2
|
||||
EXIT_STATUS=1
|
||||
exit 1
|
||||
}
|
||||
|
||||
_d () {
|
||||
[ "$PTDEBUG" ] && echo "# $PTFUNCNAME: $(log "$*")" >&2
|
||||
[ "$PTDEBUG" ] && echo "# $PTFUNCNAME: $(ts "$*")" >&2
|
||||
}
|
||||
|
||||
# ###########################################################################
|
||||
|
@@ -27,6 +27,13 @@ debug_sandbox() {
|
||||
fi
|
||||
}
|
||||
|
||||
mysql_upgrade_on() {
|
||||
local cnf_file="$1"
|
||||
local upgrade="$(which mysql_upgrade)"
|
||||
|
||||
$upgrade --defaults-file=$cnf_file --skip-write-binlog
|
||||
}
|
||||
|
||||
make_sandbox() {
|
||||
# Make the sandbox dir and extract the base files.
|
||||
rm -rf /tmp/$port || die "Failed to rm /tmp/$port"
|
||||
@@ -138,6 +145,10 @@ make_sandbox() {
|
||||
/tmp/$port/use -e "CREATE TABLE IF NOT EXISTS percona_test.sentinel (id INT PRIMARY KEY, ping VARCHAR(64) NOT NULL DEFAULT '')";
|
||||
/tmp/$port/use -e "REPLACE INTO percona_test.sentinel (id, ping) VALUES (1, '')";
|
||||
|
||||
if [ -n "${MYSQL_UPGRADE:-""}" ]; then
|
||||
mysql_upgrade_on /tmp/$port/my.sandbox.cnf
|
||||
fi
|
||||
|
||||
# If the sandbox is a slave, start the slave.
|
||||
if [ "$type" = "slave" ]; then
|
||||
/tmp/$port/use -e "change master to master_host='127.0.0.1', master_user='msandbox', master_password='msandbox', master_port=$master_port"
|
||||
|
@@ -1,17 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
plan 6
|
||||
|
||||
source "$LIB_DIR/log_warn_die.sh"
|
||||
|
||||
log "Hello world!" > $TEST_PT_TMPDIR/log
|
||||
log "Hello world A!" > $TEST_PT_TMPDIR/log
|
||||
cmd_ok \
|
||||
"grep -q 'Hello world!' $TEST_PT_TMPDIR/log" \
|
||||
"grep -q 'Hello world A!' $TEST_PT_TMPDIR/log" \
|
||||
"log msg"
|
||||
|
||||
log "Hello" "world!" > $TEST_PT_TMPDIR/log
|
||||
log "Hello" "world B!" > $TEST_PT_TMPDIR/log
|
||||
cmd_ok \
|
||||
"grep -q 'Hello world!' $TEST_PT_TMPDIR/log" \
|
||||
"grep -q 'Hello world B!' $TEST_PT_TMPDIR/log" \
|
||||
"log msg msg"
|
||||
|
||||
is \
|
||||
@@ -19,14 +17,14 @@ is \
|
||||
"0" \
|
||||
"Exit status 0"
|
||||
|
||||
warn "Hello world!" 2> $TEST_PT_TMPDIR/log
|
||||
warn "Hello world C!" 2> $TEST_PT_TMPDIR/log
|
||||
cmd_ok \
|
||||
"grep -q 'Hello world!' $TEST_PT_TMPDIR/log" \
|
||||
"grep -q 'Hello world C!' $TEST_PT_TMPDIR/log" \
|
||||
"warn msg"
|
||||
|
||||
warn "Hello" "world!" 2> $TEST_PT_TMPDIR/log
|
||||
warn "Hello" "world D!" 2> $TEST_PT_TMPDIR/log
|
||||
cmd_ok \
|
||||
"grep -q 'Hello world!' $TEST_PT_TMPDIR/log" \
|
||||
"grep -q 'Hello world D!' $TEST_PT_TMPDIR/log" \
|
||||
"warn msg msg"
|
||||
|
||||
is \
|
||||
@@ -34,6 +32,81 @@ is \
|
||||
"1" \
|
||||
"Exit status 1"
|
||||
|
||||
OPT_VERBOSE=1
|
||||
|
||||
info "Hello world 1!" > $TEST_PT_TMPDIR/log
|
||||
file_is_empty \
|
||||
$TEST_PT_TMPDIR/log \
|
||||
"verbose=1 info"
|
||||
|
||||
log "Hello world 2!" > $TEST_PT_TMPDIR/log
|
||||
file_is_empty \
|
||||
$TEST_PT_TMPDIR/log \
|
||||
"verbose=1 log"
|
||||
|
||||
warn "Hello world 3!" > $TEST_PT_TMPDIR/log 2>&1
|
||||
file_contains \
|
||||
$TEST_PT_TMPDIR/log \
|
||||
"Hello world 3!" \
|
||||
"verbose=1 warn"
|
||||
|
||||
OPT_VERBOSE=2
|
||||
|
||||
info "Hello world 4!" > $TEST_PT_TMPDIR/log
|
||||
file_is_empty \
|
||||
$TEST_PT_TMPDIR/log \
|
||||
"verbose=2 info"
|
||||
|
||||
log "Hello world 5!" > $TEST_PT_TMPDIR/log
|
||||
file_contains \
|
||||
$TEST_PT_TMPDIR/log \
|
||||
"Hello world 5!" \
|
||||
"verbose=2 log"
|
||||
|
||||
warn "Hello world 6!" > $TEST_PT_TMPDIR/log 2>&1
|
||||
file_contains \
|
||||
$TEST_PT_TMPDIR/log \
|
||||
"Hello world 6!" \
|
||||
"verbose=2 warn"
|
||||
|
||||
OPT_VERBOSE=3
|
||||
|
||||
info "Hello world 7!" > $TEST_PT_TMPDIR/log
|
||||
file_contains \
|
||||
$TEST_PT_TMPDIR/log \
|
||||
"Hello world 7!" \
|
||||
"verbose=3 info"
|
||||
|
||||
log "Hello world 8!" > $TEST_PT_TMPDIR/log
|
||||
file_contains \
|
||||
$TEST_PT_TMPDIR/log \
|
||||
"Hello world 8!" \
|
||||
"verbose=3 log"
|
||||
|
||||
warn "Hello world 9!" > $TEST_PT_TMPDIR/log 2>&1
|
||||
file_contains \
|
||||
$TEST_PT_TMPDIR/log \
|
||||
"Hello world 9!" \
|
||||
"verbose=3 warn"
|
||||
|
||||
OPT_VERBOSE=0
|
||||
|
||||
info "Hello world 10!" > $TEST_PT_TMPDIR/log
|
||||
file_is_empty \
|
||||
$TEST_PT_TMPDIR/log \
|
||||
"verbose=0 info"
|
||||
|
||||
log "Hello world 11!" > $TEST_PT_TMPDIR/log
|
||||
file_is_empty \
|
||||
$TEST_PT_TMPDIR/log \
|
||||
"verbose=0 log"
|
||||
|
||||
warn "Hello world 12!" > $TEST_PT_TMPDIR/log 2>&1
|
||||
file_is_empty \
|
||||
$TEST_PT_TMPDIR/log \
|
||||
"verbose=0 warn"
|
||||
|
||||
# ###########################################################################
|
||||
# Done
|
||||
# ###########################################################################
|
||||
done_testing
|
||||
|
@@ -93,7 +93,7 @@ my $slave1_dsn = $sb->dsn_for('slave1');
|
||||
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,11 +102,35 @@ 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
|
||||
# #############################################################################
|
||||
|
||||
$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.
|
||||
# ############################################################################
|
||||
|
@@ -210,7 +210,7 @@ $sb->load_file('master', "$sample/del-trg-bug-1062324.sql");
|
||||
sub { pt_online_schema_change::main(@args,
|
||||
"$master_dsn,D=test,t=t1",
|
||||
"--alter", "drop key 2bpk, drop key c3, drop primary key, drop c1, add primary key (c2, c3(4)), add key (c3(4))",
|
||||
qw(--execute --no-drop-new-table --no-swap-tables)) },
|
||||
qw(--no-check-alter --execute --no-drop-new-table --no-swap-tables)) },
|
||||
);
|
||||
|
||||
# Since _t1_new no longer has the c1 column, the bug caused this
|
||||
@@ -233,6 +233,34 @@ $sb->load_file('master', "$sample/del-trg-bug-1062324.sql");
|
||||
undef,
|
||||
"Delete trigger works after altering PK (bug 1062324)"
|
||||
);
|
||||
|
||||
# Another instance of this bug:
|
||||
# https://bugs.launchpad.net/percona-toolkit/+bug/1103672
|
||||
$sb->load_file('master', "$sample/del-trg-bug-1103672.sql");
|
||||
|
||||
($output, $exit_status) = full_output(
|
||||
sub { pt_online_schema_change::main(@args,
|
||||
"$master_dsn,D=test,t=t1",
|
||||
"--alter", "drop primary key, add column _id int unsigned not null primary key auto_increment FIRST",
|
||||
qw(--no-check-alter --execute --no-drop-new-table --no-swap-tables)) },
|
||||
);
|
||||
|
||||
eval {
|
||||
$master_dbh->do("DELETE FROM test.t1 WHERE id=1");
|
||||
};
|
||||
is(
|
||||
$EVAL_ERROR,
|
||||
"",
|
||||
"No delete trigger error after altering PK (bug 1103672)"
|
||||
) or diag($output);
|
||||
|
||||
$row = $master_dbh->selectrow_arrayref("SELECT * FROM test._t1_new WHERE id=1");
|
||||
is(
|
||||
$row,
|
||||
undef,
|
||||
"Delete trigger works after altering PK (bug 1103672)"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
# #############################################################################
|
||||
|
65
t/pt-online-schema-change/check_alter.t
Normal file
65
t/pt-online-schema-change/check_alter.t
Normal file
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
BEGIN {
|
||||
die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
|
||||
unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
|
||||
unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
|
||||
};
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => 'all';
|
||||
use English qw(-no_match_vars);
|
||||
use Test::More;
|
||||
|
||||
use Data::Dumper;
|
||||
use PerconaTest;
|
||||
use Sandbox;
|
||||
|
||||
require "$trunk/bin/pt-online-schema-change";
|
||||
|
||||
my $dp = new DSNParser(opts=>$dsn_opts);
|
||||
my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
|
||||
my $master_dbh = $sb->get_dbh_for('master');
|
||||
my $slave_dbh = $sb->get_dbh_for('slave1');
|
||||
|
||||
if ( !$master_dbh ) {
|
||||
plan skip_all => 'Cannot connect to sandbox master';
|
||||
}
|
||||
elsif ( !$slave_dbh ) {
|
||||
plan skip_all => 'Cannot connect to sandbox slave1';
|
||||
}
|
||||
|
||||
# The sandbox servers run with lock_wait_timeout=3 and it's not dynamic
|
||||
# so we need to specify --lock-wait-timeout=3 else the tool will die.
|
||||
my $master_dsn = 'h=127.1,P=12345,u=msandbox,p=msandbox';
|
||||
my @args = (qw(--lock-wait-timeout 3));
|
||||
my $output;
|
||||
my $exit_status;
|
||||
my $sample = "t/pt-online-schema-change/samples/";
|
||||
|
||||
# #############################################################################
|
||||
# DROP PRIMARY KEY
|
||||
# #############################################################################
|
||||
|
||||
$sb->load_file('master', "$sample/del-trg-bug-1103672.sql");
|
||||
|
||||
($output, $exit_status) = full_output(
|
||||
sub { pt_online_schema_change::main(@args,
|
||||
"$master_dsn,D=test,t=t1",
|
||||
"--alter", "drop primary key, add column _id int unsigned not null primary key auto_increment FIRST",
|
||||
qw(--execute)),
|
||||
},
|
||||
);
|
||||
|
||||
like(
|
||||
$output,
|
||||
qr/--check-alter failed/,
|
||||
"DROP PRIMARY KEY"
|
||||
);
|
||||
|
||||
# #############################################################################
|
||||
# Done.
|
||||
# #############################################################################
|
||||
$sb->wipe_clean($master_dbh);
|
||||
ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
|
||||
done_testing;
|
20
t/pt-online-schema-change/samples/del-trg-bug-1103672.sql
Normal file
20
t/pt-online-schema-change/samples/del-trg-bug-1103672.sql
Normal file
@@ -0,0 +1,20 @@
|
||||
drop database if exists test;
|
||||
create database test;
|
||||
use test;
|
||||
|
||||
CREATE TABLE `t1` (
|
||||
`id` int(10) unsigned NOT NULL,
|
||||
`x` char(3) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
INSERT INTO t1 VALUES
|
||||
(1, 'a'),
|
||||
(2, 'b'),
|
||||
(3, 'c'),
|
||||
(4, 'd'),
|
||||
(5, 'f'),
|
||||
(6, 'g'),
|
||||
(7, 'h'),
|
||||
(8, 'i'),
|
||||
(9, 'j');
|
24
t/pt-stalk/option_sanity.t
Normal file
24
t/pt-stalk/option_sanity.t
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
BEGIN {
|
||||
die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
|
||||
unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
|
||||
unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
|
||||
};
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => 'all';
|
||||
use English qw(-no_match_vars);
|
||||
use Test::More;
|
||||
|
||||
use PerconaTest;
|
||||
|
||||
my $output = `$trunk/bin/pt-stalk --help`;
|
||||
|
||||
like(
|
||||
$output,
|
||||
qr/^\s+--verbose\s+2/m,
|
||||
"Default --verbose=2"
|
||||
);
|
||||
|
||||
done_testing;
|
@@ -28,11 +28,28 @@ my $cnf = "/tmp/12345/my.sandbox.cnf";
|
||||
my $pid_file = "/tmp/pt-stalk.pid.$PID";
|
||||
my $log_file = "/tmp/pt-stalk.log.$PID";
|
||||
my $dest = "/tmp/pt-stalk.collect.$PID";
|
||||
my $int_file = "/tmp/pt-stalk-after-interval-sleep";
|
||||
my $pid;
|
||||
|
||||
diag(`rm $pid_file 2>/dev/null`);
|
||||
diag(`rm $log_file 2>/dev/null`);
|
||||
diag(`rm -rf $dest 2>/dev/null`);
|
||||
sub cleanup {
|
||||
diag(`rm $pid_file $log_file $int_file 2>/dev/null`);
|
||||
diag(`rm -rf $dest 2>/dev/null`);
|
||||
}
|
||||
|
||||
sub wait_n_cycles {
|
||||
my ($n) = @_;
|
||||
PerconaTest::wait_until(
|
||||
sub {
|
||||
return 0 unless -f "$dest/after_interval_sleep";
|
||||
my $n_cycles = `wc -l "$dest/after_interval_sleep" | awk '{print \$1}'`;
|
||||
$n_cycles ||= '';
|
||||
chomp($n_cycles);
|
||||
return ($n_cycles || 0) >= $n;
|
||||
},
|
||||
1.5,
|
||||
15
|
||||
);
|
||||
}
|
||||
|
||||
# ###########################################################################
|
||||
# Test that it won't run if can't connect to MySQL.
|
||||
@@ -56,11 +73,14 @@ is(
|
||||
# ###########################################################################
|
||||
# Test that it runs and dies normally.
|
||||
# ###########################################################################
|
||||
diag(`rm $pid_file 2>/dev/null`);
|
||||
diag(`rm $log_file 2>/dev/null`);
|
||||
diag(`rm -rf $dest 2>/dev/null`);
|
||||
|
||||
$retval = system("$trunk/bin/pt-stalk --daemonize --pid $pid_file --log $log_file --dest $dest -- --defaults-file=$cnf");
|
||||
cleanup();
|
||||
|
||||
# As of v2.1.9 when --verbose was added, non-matching checks are not
|
||||
# printed by default. So we use the --plugin to tell us when the tool
|
||||
# has completed a cycle.
|
||||
|
||||
$retval = system("$trunk/bin/pt-stalk --daemonize --pid $pid_file --log $log_file --dest $dest --plugin $trunk/t/pt-stalk/samples/plugin002.sh -- --defaults-file=$cnf");
|
||||
|
||||
is(
|
||||
$retval >> 8,
|
||||
@@ -94,21 +114,16 @@ is(
|
||||
"pt-stalk is running"
|
||||
);
|
||||
|
||||
PerconaTest::wait_for_sh("grep -q 'Check results' $log_file >/dev/null");
|
||||
wait_n_cycles(2);
|
||||
PerconaTest::kill_program(pid_file => $pid_file);
|
||||
|
||||
$output = `cat $log_file 2>/dev/null`;
|
||||
like(
|
||||
unlike(
|
||||
$output,
|
||||
qr/Check results: Threads_running=\d+, matched=no, cycles_true=0/,
|
||||
"Check results logged"
|
||||
"Non-matching results not logged because --verbose=2"
|
||||
) or diag(`cat $log_file 2>/dev/null`, `cat $dest/*-output 2>/dev/null`);
|
||||
|
||||
$retval = system("kill $pid 2>/dev/null");
|
||||
is(
|
||||
$retval >> 0,
|
||||
0,
|
||||
"Killed pt-stalk"
|
||||
);
|
||||
|
||||
PerconaTest::wait_until(sub { !-f $pid_file });
|
||||
|
||||
ok(
|
||||
@@ -123,12 +138,56 @@ like(
|
||||
"Caught signal logged"
|
||||
) or diag(`cat $log_file 2>/dev/null`, `cat $dest/*-output 2>/dev/null`);
|
||||
|
||||
# #############################################################################
|
||||
# --verbose 3 (non-matching results)
|
||||
# #############################################################################
|
||||
|
||||
cleanup();
|
||||
|
||||
$retval = system("$trunk/bin/pt-stalk --daemonize --pid $pid_file --log $log_file --dest $dest --verbose 3 -- --defaults-file=$cnf");
|
||||
|
||||
PerconaTest::wait_for_files($pid_file, $log_file);
|
||||
PerconaTest::wait_for_sh("grep -q 'Check results' $log_file >/dev/null");
|
||||
PerconaTest::kill_program(pid_file => $pid_file);
|
||||
|
||||
$output = `cat $log_file 2>/dev/null`;
|
||||
like(
|
||||
$output,
|
||||
qr/Check results: Threads_running=\d+, matched=no, cycles_true=0/,
|
||||
"Matching results logged with --verbose 3"
|
||||
) or diag(`cat $log_file 2>/dev/null`, `cat $dest/*-output 2>/dev/null`);
|
||||
|
||||
# #############################################################################
|
||||
# --verbose 1 (just errors and warnings)
|
||||
# #############################################################################
|
||||
|
||||
cleanup();
|
||||
|
||||
$retval = system("$trunk/bin/pt-stalk --daemonize --pid $pid_file --log $log_file --dest $dest --verbose 1 --plugin $trunk/t/pt-stalk/samples/plugin002.sh -- --defaults-file=$cnf");
|
||||
|
||||
PerconaTest::wait_for_files($pid_file, $log_file);
|
||||
wait_n_cycles(2);
|
||||
PerconaTest::kill_program(pid_file => $pid_file);
|
||||
|
||||
$output = `cat $log_file 2>/dev/null`;
|
||||
|
||||
like(
|
||||
$output,
|
||||
qr/Caught signal, exiting/,
|
||||
"Warning logged (--verbose 1)"
|
||||
);
|
||||
|
||||
unlike(
|
||||
$output,
|
||||
qr/Start|Collect|Check/i,
|
||||
"No run info log (--verbose 1)"
|
||||
);
|
||||
|
||||
# ###########################################################################
|
||||
# Test collect.
|
||||
# ###########################################################################
|
||||
diag(`rm $pid_file 2>/dev/null`);
|
||||
diag(`rm $log_file 2>/dev/null`);
|
||||
diag(`rm $dest/* 2>/dev/null`);
|
||||
|
||||
cleanup();
|
||||
|
||||
# We'll have to watch Uptime since it's the only status var that's going
|
||||
# to be predictable.
|
||||
@@ -180,10 +239,10 @@ like(
|
||||
"Trigger file logs how pt-stalk was ran"
|
||||
);
|
||||
|
||||
chomp($output = `cat $log_file 2>/dev/null | grep 'Collector PID'`);
|
||||
chomp($output = `cat $log_file 2>/dev/null | grep 'Collect [0-9] PID'`);
|
||||
like(
|
||||
$output,
|
||||
qr/Collector PID \d+/,
|
||||
qr/Collect 1 PID \d+/,
|
||||
"Collector PID logged"
|
||||
)
|
||||
or diag(
|
||||
@@ -195,9 +254,8 @@ or diag(
|
||||
# ###########################################################################
|
||||
# Triggered but --no-collect.
|
||||
# ###########################################################################
|
||||
diag(`rm $pid_file 2>/dev/null`);
|
||||
diag(`rm $log_file 2>/dev/null`);
|
||||
diag(`rm $dest/* 2>/dev/null`);
|
||||
|
||||
cleanup();
|
||||
|
||||
(undef, $uptime) = $dbh->selectrow_array("SHOW STATUS LIKE 'Uptime'");
|
||||
$threshold = $uptime + 2;
|
||||
@@ -209,7 +267,7 @@ PerconaTest::wait_until(sub { !-f $pid_file });
|
||||
$output = `cat $log_file 2>/dev/null`;
|
||||
like(
|
||||
$output,
|
||||
qr/Collect triggered/,
|
||||
qr/Collect 1 triggered/,
|
||||
"Collect triggered"
|
||||
);
|
||||
|
||||
@@ -227,6 +285,8 @@ ok(
|
||||
# --config
|
||||
# #############################################################################
|
||||
|
||||
cleanup();
|
||||
|
||||
diag(`cp $ENV{HOME}/.pt-stalk.conf $ENV{HOME}/.pt-stalk.conf.original 2>/dev/null`);
|
||||
diag(`cp $trunk/t/pt-stalk/samples/config001.conf $ENV{HOME}/.pt-stalk.conf`);
|
||||
|
||||
@@ -254,9 +314,8 @@ diag(`cp $ENV{HOME}/.pt-stalk.conf.original $ENV{HOME}/.pt-stalk.conf 2>/dev/nul
|
||||
# #############################################################################
|
||||
# Don't stalk, just collect.
|
||||
# #############################################################################
|
||||
diag(`rm $pid_file 2>/dev/null`);
|
||||
diag(`rm $log_file 2>/dev/null`);
|
||||
diag(`rm $dest/* 2>/dev/null`);
|
||||
|
||||
cleanup();
|
||||
|
||||
$retval = system("$trunk/bin/pt-stalk --no-stalk --run-time 2 --dest $dest --prefix nostalk --pid $pid_file -- --defaults-file=$cnf >$log_file 2>&1");
|
||||
|
||||
@@ -343,9 +402,7 @@ unlike(
|
||||
# #############################################################################
|
||||
# Done.
|
||||
# #############################################################################
|
||||
diag(`rm $pid_file 2>/dev/null`);
|
||||
diag(`rm $log_file 2>/dev/null`);
|
||||
cleanup();
|
||||
diag(`rm -rf $dest 2>/dev/null`);
|
||||
ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
|
||||
|
||||
done_testing;
|
||||
|
5
t/pt-stalk/samples/plugin002.sh
Normal file
5
t/pt-stalk/samples/plugin002.sh
Normal file
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
after_interval_sleep() {
|
||||
date >> "$OPT_DEST/after_interval_sleep"
|
||||
}
|
@@ -256,7 +256,7 @@ SKIP: {
|
||||
|
||||
$output = output( sub { pt_table_checksum::main(@args) }, stderr => 1 );
|
||||
|
||||
my $re = qr/ has binlog_format .*? has binlog_format (\S+)\./msi;
|
||||
my $re = qr/Replica .+? has binlog_format (\S+)/msi;
|
||||
like(
|
||||
$output,
|
||||
$re,
|
||||
|
@@ -9,7 +9,7 @@ BEGIN {
|
||||
use strict;
|
||||
use warnings FATAL => 'all';
|
||||
use English qw(-no_match_vars);
|
||||
use Test::More tests => 1;
|
||||
use Test::More;
|
||||
|
||||
use PerconaTest;
|
||||
use Sandbox;
|
||||
@@ -57,7 +57,28 @@ test_diff_where(
|
||||
where => "((`id` >= '7')) AND ((`id` <= '9'))",
|
||||
);
|
||||
|
||||
test_diff_where(
|
||||
name => "Lower oob chunk (bug 918056)",
|
||||
file => "$sample/bug-918056-ddl.sql",
|
||||
diff => {
|
||||
chunk => '3',
|
||||
chunk_index => 'PRIMARY',
|
||||
cnt_diff => '49',
|
||||
crc_diff => '0',
|
||||
db => 'test',
|
||||
lower_boundary => undef,
|
||||
master_cnt => '0',
|
||||
master_crc => '0',
|
||||
table => 'test.history',
|
||||
tbl => 'history',
|
||||
this_cnt => '49',
|
||||
this_crc => '0',
|
||||
upper_boundary => '21,21,1045'
|
||||
},
|
||||
where => "((`uid` < '21') OR (`uid` = '21' AND `nid` <= '1045'))",
|
||||
);
|
||||
|
||||
# #############################################################################
|
||||
# Done.
|
||||
# #############################################################################
|
||||
exit;
|
||||
done_testing;
|
||||
|
90
t/pt-table-sync/replicate.t
Normal file
90
t/pt-table-sync/replicate.t
Normal file
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
BEGIN {
|
||||
die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
|
||||
unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
|
||||
unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
|
||||
|
||||
# Don't add /* trace */ messages to --print queries becuase they
|
||||
# contain non-determinstic info like user, etc.
|
||||
$ENV{PT_TEST_NO_TRACE} = 1;
|
||||
};
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => 'all';
|
||||
use English qw(-no_match_vars);
|
||||
use Test::More;
|
||||
|
||||
use PerconaTest;
|
||||
use Sandbox;
|
||||
require "$trunk/bin/pt-table-sync";
|
||||
|
||||
my $dp = new DSNParser(opts=>$dsn_opts);
|
||||
my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
|
||||
my $master_dbh = $sb->get_dbh_for('master');
|
||||
my $slave1_dbh = $sb->get_dbh_for('slave1');
|
||||
|
||||
if ( !$master_dbh ) {
|
||||
plan skip_all => 'Cannot connect to sandbox master';
|
||||
}
|
||||
elsif ( !$slave1_dbh ) {
|
||||
plan skip_all => 'Cannot connect to sandbox slave1';
|
||||
}
|
||||
|
||||
my $master_dsn = $sb->dsn_for('master');
|
||||
my $slave1_dsn = $sb->dsn_for('slave1');
|
||||
|
||||
my $output;
|
||||
my $sample = "t/pt-table-sync/samples";
|
||||
|
||||
# #############################################################################
|
||||
# --replicate tests
|
||||
# #############################################################################
|
||||
|
||||
# #############################################################################
|
||||
# Bug 918056: pt-table-sync false-positive error "Cannot nibble table because
|
||||
# MySQL chose no index instead of the PRIMARY index"
|
||||
# https://bugs.launchpad.net/percona-toolkit/+bug/918056
|
||||
# #############################################################################
|
||||
|
||||
# The slave has 49 extra rows on the low end, e.g. master has rows 50+
|
||||
# but slave has rows 1-49 and 50+. This tests syncing the lower oob chunk.
|
||||
$sb->create_dbs($master_dbh, [qw(bug918056)]);
|
||||
$sb->load_file('master', "$sample/bug-918056-master.sql", "bug918056");
|
||||
$sb->load_file('slave1', "$sample/bug-918056-slave.sql", "bug918056");
|
||||
|
||||
ok(
|
||||
no_diff(
|
||||
sub {
|
||||
pt_table_sync::main($master_dsn, qw(--replicate percona.checksums),
|
||||
qw(--print))
|
||||
},
|
||||
"$sample/bug-918056-print.txt",
|
||||
stderr => 1,
|
||||
),
|
||||
"Sync lower oob (bug 918056)"
|
||||
);
|
||||
|
||||
# Test syncing the upper oob chunk.
|
||||
$sb->load_file('master', "$sample/upper-oob-master.sql");
|
||||
$sb->load_file('slave1', "$sample/upper-oob-slave.sql");
|
||||
|
||||
ok(
|
||||
no_diff(
|
||||
sub {
|
||||
pt_table_sync::main($master_dsn, qw(--replicate percona.checksums),
|
||||
qw(--print))
|
||||
},
|
||||
"$sample/upper-oob-print.txt",
|
||||
stderr => 1,
|
||||
),
|
||||
"Sync upper oob (bug 918056)"
|
||||
);
|
||||
|
||||
# #############################################################################
|
||||
# Done.
|
||||
# #############################################################################
|
||||
$sb->wipe_clean($master_dbh);
|
||||
$sb->wipe_clean($slave1_dbh);
|
||||
ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
|
||||
done_testing;
|
6
t/pt-table-sync/samples/bug-918056-ddl.sql
Normal file
6
t/pt-table-sync/samples/bug-918056-ddl.sql
Normal file
@@ -0,0 +1,6 @@
|
||||
CREATE TABLE `history` (
|
||||
`uid` int(11) NOT NULL DEFAULT '0',
|
||||
`nid` int(11) NOT NULL DEFAULT '0',
|
||||
`timestamp` int(11) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`uid`,`nid`)
|
||||
) ENGINE=InnoDB;
|
59
t/pt-table-sync/samples/bug-918056-master.sql
Normal file
59
t/pt-table-sync/samples/bug-918056-master.sql
Normal file
File diff suppressed because one or more lines are too long
49
t/pt-table-sync/samples/bug-918056-print.txt
Normal file
49
t/pt-table-sync/samples/bug-918056-print.txt
Normal file
@@ -0,0 +1,49 @@
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='1' AND `nid`='14' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='1' AND `nid`='1591' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='1' AND `nid`='11501' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='1' AND `nid`='12648' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='1' AND `nid`='12652' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='1045' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='1046' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='11556' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12166' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12598' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12599' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12601' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12602' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12603' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12606' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12607' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12609' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12616' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12617' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12618' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12621' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12623' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12624' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12626' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12627' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12628' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12632' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12651' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12652' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12672' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12674' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12675' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12677' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12678' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12680' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12682' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12694' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12733' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12734' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='20' AND `nid`='12738' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='21' AND `nid`='12' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='21' AND `nid`='14' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='21' AND `nid`='16' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='21' AND `nid`='191' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='21' AND `nid`='307' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='21' AND `nid`='339' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='21' AND `nid`='340' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='21' AND `nid`='901' LIMIT 1;
|
||||
DELETE FROM `bug918056`.`history` WHERE `uid`='21' AND `nid`='1039' LIMIT 1;
|
39
t/pt-table-sync/samples/bug-918056-slave.sql
Normal file
39
t/pt-table-sync/samples/bug-918056-slave.sql
Normal file
File diff suppressed because one or more lines are too long
148
t/pt-table-sync/samples/upper-oob-master.sql
Normal file
148
t/pt-table-sync/samples/upper-oob-master.sql
Normal file
@@ -0,0 +1,148 @@
|
||||
DROP DATABASE IF EXISTS upper_oob;
|
||||
CREATE DATABASE upper_oob;
|
||||
USE upper_oob;
|
||||
|
||||
CREATE TABLE t (
|
||||
id int not null auto_increment primary key,
|
||||
c varchar(64)
|
||||
) engine=innodb;
|
||||
|
||||
insert into t values
|
||||
(1, 'Afghanistan'),
|
||||
(2, 'Algeria'),
|
||||
(3, 'American Samoa'),
|
||||
(4, 'Angola'),
|
||||
(5, 'Anguilla'),
|
||||
(6, 'Argentina'),
|
||||
(7, 'Armenia'),
|
||||
(8, 'Australia'),
|
||||
(9, 'Austria'),
|
||||
(10, 'Azerbaijan'),
|
||||
(11, 'Bahrain'),
|
||||
(12, 'Bangladesh'),
|
||||
(13, 'Belarus'),
|
||||
(14, 'Bolivia'),
|
||||
(15, 'Brazil'),
|
||||
(16, 'Brunei'),
|
||||
(17, 'Bulgaria'),
|
||||
(18, 'Cambodia'),
|
||||
(19, 'Cameroon'),
|
||||
(20, 'Canada'),
|
||||
(21, 'Chad'),
|
||||
(22, 'Chile'),
|
||||
(23, 'China'),
|
||||
(24, 'Colombia'),
|
||||
(25, 'Congo, The Democratic Republic of the'),
|
||||
(26, 'Czech Republic'),
|
||||
(27, 'Dominican Republic'),
|
||||
(28, 'Ecuador'),
|
||||
(29, 'Egypt'),
|
||||
(30, 'Estonia'),
|
||||
(31, 'Ethiopia'),
|
||||
(32, 'Faroe Islands'),
|
||||
(33, 'Finland'),
|
||||
(34, 'France'),
|
||||
(35, 'French Guiana'),
|
||||
(36, 'French Polynesia'),
|
||||
(37, 'Gambia'),
|
||||
(38, 'Germany'),
|
||||
(39, 'Greece'),
|
||||
(40, 'Greenland'),
|
||||
(41, 'Holy See (Vatican City State)'),
|
||||
(42, 'Hong Kong'),
|
||||
(43, 'Hungary'),
|
||||
(44, 'India'),
|
||||
(45, 'Indonesia'),
|
||||
(46, 'Iran'),
|
||||
(47, 'Iraq'),
|
||||
(48, 'Israel'),
|
||||
(49, 'Italy'),
|
||||
(50, 'Japan'),
|
||||
(51, 'Kazakstan'),
|
||||
(52, 'Kenya'),
|
||||
(53, 'Kuwait'),
|
||||
(54, 'Latvia'),
|
||||
(55, 'Liechtenstein'),
|
||||
(56, 'Lithuania'),
|
||||
(57, 'Madagascar'),
|
||||
(58, 'Malawi'),
|
||||
(59, 'Malaysia'),
|
||||
(60, 'Mexico'),
|
||||
(61, 'Moldova'),
|
||||
(62, 'Morocco'),
|
||||
(63, 'Mozambique'),
|
||||
(64, 'Myanmar'),
|
||||
(65, 'Nauru'),
|
||||
(66, 'Nepal'),
|
||||
(67, 'Netherlands'),
|
||||
(68, 'New Zealand'),
|
||||
(69, 'Nigeria'),
|
||||
(70, 'North Korea'),
|
||||
(71, 'Oman'),
|
||||
(72, 'Pakistan'),
|
||||
(73, 'Paraguay'),
|
||||
(74, 'Peru'),
|
||||
(75, 'Philippines'),
|
||||
(76, 'Poland'),
|
||||
(77, 'Puerto Rico'),
|
||||
(78, 'Romania'),
|
||||
(79, 'Runion'),
|
||||
(80, 'Russian Federation'),
|
||||
(81, 'Saint Vincent and the Grenadines'),
|
||||
(82, 'Saudi Arabia'),
|
||||
(83, 'Senegal'),
|
||||
(84, 'Slovakia'),
|
||||
(85, 'South Africa'),
|
||||
(86, 'South Korea'),
|
||||
(87, 'Spain'),
|
||||
(88, 'Sri Lanka'),
|
||||
(89, 'Sudan'),
|
||||
(90, 'Sweden'),
|
||||
(91, 'Switzerland'),
|
||||
(92, 'Taiwan'),
|
||||
(93, 'Tanzania'),
|
||||
(94, 'Thailand'),
|
||||
(95, 'Tonga'),
|
||||
(96, 'Tunisia'),
|
||||
(97, 'Turkey'),
|
||||
(98, 'Turkmenistan'),
|
||||
(99, 'Tuvalu'),
|
||||
(100, 'Ukraine'),
|
||||
(101, 'United Arab Emirates'),
|
||||
(102, 'United Kingdom'),
|
||||
(103, 'United States'),
|
||||
(104, 'Venezuela'),
|
||||
(105, 'Vietnam'),
|
||||
(106, 'Virgin Islands, U.S.'),
|
||||
(107, 'Yemen'),
|
||||
(108, 'Yugoslavia'),
|
||||
(109, 'Zambia');
|
||||
|
||||
CREATE DATABASE IF NOT EXISTS percona;
|
||||
USE percona;
|
||||
DROP TABLE IF EXISTS checksums;
|
||||
CREATE TABLE `checksums` (
|
||||
`db` char(64) NOT NULL,
|
||||
`tbl` char(64) NOT NULL,
|
||||
`chunk` int(11) NOT NULL,
|
||||
`chunk_time` float DEFAULT NULL,
|
||||
`chunk_index` varchar(200) DEFAULT NULL,
|
||||
`lower_boundary` text,
|
||||
`upper_boundary` text,
|
||||
`this_crc` char(40) NOT NULL,
|
||||
`this_cnt` int(11) NOT NULL,
|
||||
`master_crc` char(40) DEFAULT NULL,
|
||||
`master_cnt` int(11) DEFAULT NULL,
|
||||
`ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`db`,`tbl`,`chunk`),
|
||||
KEY `ts_db_tbl` (`ts`,`db`,`tbl`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
SET SQL_LOG_BIN=0;
|
||||
DELETE FROM upper_oob.t where id > 99;
|
||||
INSERT INTO percona.checksums VALUES
|
||||
('upper_oob','t',1,0.001144,'PRIMARY','1','50','398f3270',50,'398f3270',50,'2013-01-23 17:36:56'),
|
||||
('upper_oob','t',2,0.000878,'PRIMARY','51','99','bd9a892d',49,'bd9a892d',49,'2013-01-23 17:36:56'),
|
||||
('upper_oob','t',3,0.000763,'PRIMARY',NULL,'1','0',0,'0',0,'2013-01-23 17:36:56'),
|
||||
('upper_oob','t',4,0.000877,'PRIMARY','99',NULL,'0',0,'0',0,'2013-01-23 17:36:56');
|
||||
SET SQL_LOG_BIN=1;
|
10
t/pt-table-sync/samples/upper-oob-print.txt
Normal file
10
t/pt-table-sync/samples/upper-oob-print.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
DELETE FROM `upper_oob`.`t` WHERE `id`='100' LIMIT 1;
|
||||
DELETE FROM `upper_oob`.`t` WHERE `id`='101' LIMIT 1;
|
||||
DELETE FROM `upper_oob`.`t` WHERE `id`='102' LIMIT 1;
|
||||
DELETE FROM `upper_oob`.`t` WHERE `id`='103' LIMIT 1;
|
||||
DELETE FROM `upper_oob`.`t` WHERE `id`='104' LIMIT 1;
|
||||
DELETE FROM `upper_oob`.`t` WHERE `id`='105' LIMIT 1;
|
||||
DELETE FROM `upper_oob`.`t` WHERE `id`='106' LIMIT 1;
|
||||
DELETE FROM `upper_oob`.`t` WHERE `id`='107' LIMIT 1;
|
||||
DELETE FROM `upper_oob`.`t` WHERE `id`='108' LIMIT 1;
|
||||
DELETE FROM `upper_oob`.`t` WHERE `id`='109' LIMIT 1;
|
7
t/pt-table-sync/samples/upper-oob-slave.sql
Normal file
7
t/pt-table-sync/samples/upper-oob-slave.sql
Normal file
@@ -0,0 +1,7 @@
|
||||
USE percona;
|
||||
TRUNCATE TABLE checksums;
|
||||
INSERT INTO `checksums` VALUES
|
||||
('upper_oob','t',1,0.001144,'PRIMARY','1','50','398f3270',50,'398f3270',50,'2013-01-23 17:36:56'),
|
||||
('upper_oob','t',2,0.000878,'PRIMARY','51','99','bd9a892d',49,'bd9a892d',49,'2013-01-23 17:36:56'),
|
||||
('upper_oob','t',3,0.000763,'PRIMARY',NULL,'1','0',0,'0',0,'2013-01-23 17:36:56'),
|
||||
('upper_oob','t',4,0.000877,'PRIMARY','99',NULL,'0',10,'0',0,'2013-01-23 17:36:56');
|
@@ -100,6 +100,7 @@ run_test() {
|
||||
result() {
|
||||
local result=$1
|
||||
local test_name=${2:-""}
|
||||
testno=$((testno + 1))
|
||||
if [ $result -eq 0 ]; then
|
||||
echo "ok $testno - $TEST_FILE $test_name"
|
||||
else
|
||||
@@ -110,7 +111,6 @@ result() {
|
||||
cat $TEST_PT_TMPDIR/failed_result | sed -e 's/^/# /' -e '30q' >&2
|
||||
fi
|
||||
fi
|
||||
testno=$((testno + 1))
|
||||
return $result
|
||||
}
|
||||
|
||||
@@ -121,19 +121,21 @@ plan() {
|
||||
fi
|
||||
}
|
||||
|
||||
done_testing() {
|
||||
echo "1..$testno"
|
||||
}
|
||||
|
||||
#
|
||||
# The following subs are for the test files to call.
|
||||
#
|
||||
|
||||
pass() {
|
||||
local reason="${1:-""}"
|
||||
|
||||
result 0 "$reason"
|
||||
}
|
||||
|
||||
fail() {
|
||||
local reason="${1:-""}"
|
||||
|
||||
result 1 "$reason"
|
||||
}
|
||||
|
||||
@@ -177,6 +179,42 @@ is() {
|
||||
result $? "$test_name"
|
||||
}
|
||||
|
||||
file_is_empty() {
|
||||
local file=$1
|
||||
local test_name=${2:-""}
|
||||
test_command="-s $file"
|
||||
if [ ! -f "$file" ]; then
|
||||
echo "$file does not exist" > $TEST_PT_TMPDIR/failed_result
|
||||
result 1 "$test_name"
|
||||
fi
|
||||
if [ -s "$file" ]; then
|
||||
echo "$file is not empty:" > $TEST_PT_TMPDIR/failed_result
|
||||
cat "$file" >> $TEST_PT_TMPDIR/failed_result
|
||||
result 1 "$test_name"
|
||||
else
|
||||
result 0 "$test_name"
|
||||
fi
|
||||
}
|
||||
|
||||
file_contains() {
|
||||
local file="$1"
|
||||
local pat="$2"
|
||||
local test_name=${3:-""}
|
||||
test_command="grep -q '$pat' '$file'"
|
||||
if [ ! -f "$file" ]; then
|
||||
echo "$file does not exist" > $TEST_PT_TMPDIR/failed_result
|
||||
result 1 "$test_name"
|
||||
fi
|
||||
grep -q "$pat" $file
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "$file does not contain '$pat':" > $TEST_PT_TMPDIR/failed_result
|
||||
cat "$file" >> $TEST_PT_TMPDIR/failed_result
|
||||
result 1 "$test_name"
|
||||
else
|
||||
result 0 "$test_name"
|
||||
fi
|
||||
}
|
||||
|
||||
cmd_ok() {
|
||||
local test_command=$1
|
||||
local test_name=${2:-""}
|
||||
@@ -226,7 +264,7 @@ diag() {
|
||||
# Script starts here
|
||||
# ############################################################################
|
||||
|
||||
testno=1
|
||||
testno=0
|
||||
failed_tests=0
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
|
Reference in New Issue
Block a user