mirror of
https://github.com/percona/percona-toolkit.git
synced 2025-09-12 14:18:32 +00:00
Detect infinite loops using only lower boundaries.
This commit is contained in:
@@ -447,6 +447,29 @@ sub _next_boundaries {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Detect infinite loops. If the lower boundary we just nibbled from
|
||||||
|
# is identical to the next lower boundary, then this next nibble won't
|
||||||
|
# go anywhere, so to speak, unless perhaps the chunk size has changed
|
||||||
|
# which will cause us to nibble further ahead and maybe get a new lower
|
||||||
|
# boundary that isn't identical, but we can't detect this, and in any
|
||||||
|
# case, if there's one infinite loop there will probably be others.
|
||||||
|
if ( $self->_identical_boundaries($self->{lb}, $self->{next_lb}) ) {
|
||||||
|
MKDEBUG && _d('Infinite loop detected');
|
||||||
|
my $tbl = $self->{tbl};
|
||||||
|
my $index = $tbl->{tbl_struct}->{keys}->{$self->{index}};
|
||||||
|
my $n_cols = scalar @{$index->{cols}};
|
||||||
|
my $chunkno = $self->{nibbleno};
|
||||||
|
die "Possible infinite loop detected! "
|
||||||
|
. "The lower boundary for chunk $chunkno is "
|
||||||
|
. "<" . join(', ', @{$self->{lb}}) . "> and the lower "
|
||||||
|
. "boundary for chunk " . ($chunkno + 1) . " is also "
|
||||||
|
. "<" . join(', ', @{$self->{next_lb}}) . ">. "
|
||||||
|
. "This usually happens when using a non-unique single "
|
||||||
|
. "column index. The current chunk index for table "
|
||||||
|
. "$tbl->{db}.$tbl->{tbl} is $self->{index} which is"
|
||||||
|
. ($index->{is_unique} ? '' : ' not') . " unique and covers "
|
||||||
|
. ($n_cols > 1 ? "$n_cols columns" : "1 column") . ".\n";
|
||||||
|
}
|
||||||
$self->{lb} = $self->{next_lb};
|
$self->{lb} = $self->{next_lb};
|
||||||
|
|
||||||
MKDEBUG && _d($self->{ub_sth}->{Statement}, 'params:',
|
MKDEBUG && _d($self->{ub_sth}->{Statement}, 'params:',
|
||||||
@@ -457,22 +480,6 @@ sub _next_boundaries {
|
|||||||
if ( $boundary && @$boundary ) {
|
if ( $boundary && @$boundary ) {
|
||||||
$self->{ub} = $boundary->[0]; # this nibble
|
$self->{ub} = $boundary->[0]; # this nibble
|
||||||
if ( $boundary->[1] ) {
|
if ( $boundary->[1] ) {
|
||||||
if ( $self->_identical_boundaries($boundary) ) {
|
|
||||||
my $tbl = $self->{tbl};
|
|
||||||
my $index = $tbl->{tbl_struct}->{keys}->{$self->{index}};
|
|
||||||
my $n_cols = scalar @{$index->{cols}};
|
|
||||||
my $chunkno = $self->{nibbleno} + 1;
|
|
||||||
die "Possible infinite loop detected! "
|
|
||||||
. "The upper boundary for chunk $chunkno is "
|
|
||||||
. "<" . join(', ', @{$boundary->[0]}) . "> and the lower "
|
|
||||||
. "boundary for chunk " . ($chunkno + 1) . " is also "
|
|
||||||
. "<" . join(', ', @{$boundary->[1]}) . ">. "
|
|
||||||
. "This usually happens when using a non-unique single "
|
|
||||||
. "column index. The current chunk index for table "
|
|
||||||
. "$tbl->{db}.$tbl->{tbl} is $self->{index} which is"
|
|
||||||
. ($index->{is_unique} ? '' : ' not') . " unique and covers "
|
|
||||||
. ($n_cols > 1 ? "$n_cols columns" : "1 column") . ".\n";
|
|
||||||
}
|
|
||||||
$self->{next_lb} = $boundary->[1]; # next nibble
|
$self->{next_lb} = $boundary->[1]; # next nibble
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -491,16 +498,23 @@ sub _next_boundaries {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub _identical_boundaries {
|
sub _identical_boundaries {
|
||||||
my ($self, $boundaries) = @_;
|
my ($self, $b1, $b2) = @_;
|
||||||
my $ub = $boundaries->[0];
|
|
||||||
my $lb = $boundaries->[1];
|
# If only one boundary isn't defined, then they can't be identical.
|
||||||
return 0 unless $ub && $lb;
|
return 0 if ($b1 && !$b2) || (!$b1 && $b2);
|
||||||
my $n_vals = scalar @$ub;
|
|
||||||
|
# If both boundaries aren't defined, then they're identical.
|
||||||
|
return 1 if !$b1 && !$b2;
|
||||||
|
|
||||||
|
# Both boundaries are defined; compare their values and return false
|
||||||
|
# on the fisrt difference because only one diff is needed to prove
|
||||||
|
# that they're not identical.
|
||||||
|
die "Boundaries have different numbers of values"
|
||||||
|
if scalar @$b1 != scalar @$b2; # shouldn't happen
|
||||||
|
my $n_vals = scalar @$b1;
|
||||||
for my $i ( 0..($n_vals-1) ) {
|
for my $i ( 0..($n_vals-1) ) {
|
||||||
# One diff means the bounds aren't identical.
|
return 0 if $b1->[$i] ne $b2->[$i]; # diff
|
||||||
return 0 if $lb->[$i] ne $ub->[$i];
|
|
||||||
}
|
}
|
||||||
MKDEBUG && _d('Infinite loop detected');
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -503,7 +503,7 @@ $dbh->do('alter table bad_tables.inv drop index index_inv_on_tee_id_and_on_id');
|
|||||||
$ni = make_nibble_iter(
|
$ni = make_nibble_iter(
|
||||||
db => 'bad_tables',
|
db => 'bad_tables',
|
||||||
tbl => 'inv',
|
tbl => 'inv',
|
||||||
argv => [qw(--databases bad_tables --chunk-size 7)],
|
argv => [qw(--databases bad_tables --chunk-size 3)],
|
||||||
);
|
);
|
||||||
|
|
||||||
is(
|
is(
|
||||||
|
Reference in New Issue
Block a user