Make NibbleIter query comments customizable. Update the module in pt-table-checksum and pt-osc.

This commit is contained in:
Daniel Nichter
2012-03-25 10:37:19 -06:00
parent 686a511b22
commit 45c1f3bfb6
4 changed files with 172 additions and 64 deletions

View File

@@ -3907,6 +3907,16 @@ sub new {
my $nibble_params = can_nibble(%args);
my %comments = (
bite => "bite table",
nibble => "nibble table",
);
if ( $args{comments} ) {
map { $comments{$_} = $args{comments}->{$_} }
grep { defined $args{comments}->{$_} }
keys %{$args{comments}};
}
my $where = $o->has('where') ? $o->get('where') : '';
my $tbl_struct = $tbl->{tbl_struct};
my $ignore_col = $o->has('ignore-columns')
@@ -3924,7 +3934,7 @@ sub new {
: join(', ', map { $q->quote($_) } @cols))
. " FROM $tbl->{name}"
. ($where ? " WHERE $where" : '')
. " /*checksum table*/";
. " /*$comments{bite}*/";
PTDEBUG && _d('One nibble statement:', $nibble_sql);
my $explain_nibble_sql
@@ -3933,7 +3943,7 @@ sub new {
: join(', ', map { $q->quote($_) } @cols))
. " FROM $tbl->{name}"
. ($where ? " WHERE $where" : '')
. " /*explain checksum table*/";
. " /*explain $comments{bite}*/";
PTDEBUG && _d('Explain one nibble statement:', $explain_nibble_sql);
$self = {
@@ -4015,9 +4025,7 @@ sub new {
. " AND " . $asc->{boundaries}->{'<='} # upper boundary
. ($where ? " AND ($where)" : '')
. ($args{order_by} ? " ORDER BY $order_by" : "")
. " /*checksum chunk*/";
# BARON: the above "checksum chunk" looks like this module isn't
# genericized for use outside of pt-table-checksum.
. " /*$comments{nibble}*/";
PTDEBUG && _d('Nibble statement:', $nibble_sql);
my $explain_nibble_sql
@@ -4029,7 +4037,7 @@ sub new {
. " AND " . $asc->{boundaries}->{'<='} # upper boundary
. ($where ? " AND ($where)" : '')
. ($args{order_by} ? " ORDER BY $order_by" : "")
. " /*explain checksum chunk*/";
. " /*explain $comments{nibble}*/";
PTDEBUG && _d('Explain nibble statement:', $explain_nibble_sql);
my $limit = $chunk_size - 1;
@@ -4867,8 +4875,6 @@ sub main {
}
}
# BARON: we should check that this option has a legal value. (Is this
# something we should add to OptionParser?)
my $rename_fk_method = lc($o->get('update-foreign-keys-method') || '');
if ( $rename_fk_method eq 'drop_old_table' ) {
$o->set('swap-tables', 0);
@@ -4925,7 +4931,8 @@ sub main {
$o->save_error("--find-child-tables requires --update-foreign-keys-method");
}
# BARON: oh, I see you do it here.
# See the "pod-based-option-value-validation" spec for how this may
# be automagically validated.
if ( $rename_fk_method
&& $rename_fk_method ne 'rebuild_constraints'
&& $rename_fk_method ne 'drop_old_table' ) {
@@ -5628,6 +5635,10 @@ sub main {
Quoter => $q,
TableParser => $tp,
TableNibbler => new TableNibbler(TableParser => $tp, Quoter => $q),
comments => {
bite => "pt-online-schema-change $PID copy table",
nibble => "pt-online-schema-change $PID copy nibble",
},
);
};
if ( $EVAL_ERROR ) {

View File

@@ -3528,47 +3528,45 @@ sub new {
}
my ($cxn, $tbl, $chunk_size, $o, $q) = @args{@required_args};
my $where = $o->get('where');
my ($row_est, $mysql_index) = get_row_estimate(%args, where => $where);
my $one_nibble = !defined $args{one_nibble} || $args{one_nibble}
? $row_est <= $chunk_size * $o->get('chunk-size-limit')
: 0;
PTDEBUG && _d('One nibble:', $one_nibble ? 'yes' : 'no');
my $nibble_params = can_nibble(%args);
if ( $args{resume}
&& !defined $args{resume}->{lower_boundary}
&& !defined $args{resume}->{upper_boundary} ) {
PTDEBUG && _d('Resuming from one nibble table');
$one_nibble = 1;
}
my $index = _find_best_index(%args, mysql_index => $mysql_index);
if ( !$index && !$one_nibble ) {
die "There is no good index and the table is oversized.";
my %comments = (
bite => "bite table",
nibble => "nibble table",
);
if ( $args{comments} ) {
map { $comments{$_} = $args{comments}->{$_} }
grep { defined $args{comments}->{$_} }
keys %{$args{comments}};
}
my $where = $o->has('where') ? $o->get('where') : '';
my $tbl_struct = $tbl->{tbl_struct};
my $ignore_col = $o->get('ignore-columns') || {};
my $all_cols = $o->get('columns') || $tbl_struct->{cols};
my $ignore_col = $o->has('ignore-columns')
? ($o->get('ignore-columns') || {})
: {};
my $all_cols = $o->has('columns')
? ($o->get('columns') || $tbl_struct->{cols})
: $tbl_struct->{cols};
my @cols = grep { !$ignore_col->{$_} } @$all_cols;
my $self;
if ( $one_nibble ) {
if ( $nibble_params->{one_nibble} ) {
my $nibble_sql
= ($args{dml} ? "$args{dml} " : "SELECT ")
. ($args{select} ? $args{select}
: join(', ', map { $q->quote($_) } @cols))
. " FROM " . $q->quote(@{$tbl}{qw(db tbl)})
. " FROM $tbl->{name}"
. ($where ? " WHERE $where" : '')
. " /*checksum table*/";
. " /*$comments{bite}*/";
PTDEBUG && _d('One nibble statement:', $nibble_sql);
my $explain_nibble_sql
= "EXPLAIN SELECT "
. ($args{select} ? $args{select}
: join(', ', map { $q->quote($_) } @cols))
. " FROM " . $q->quote(@{$tbl}{qw(db tbl)})
. " FROM $tbl->{name}"
. ($where ? " WHERE $where" : '')
. " /*explain checksum table*/";
. " /*explain $comments{bite}*/";
PTDEBUG && _d('Explain one nibble statement:', $explain_nibble_sql);
$self = {
@@ -3580,6 +3578,7 @@ sub new {
};
}
else {
my $index = $nibble_params->{index}; # brevity
my $index_cols = $tbl->{tbl_struct}->{keys}->{$index}->{cols};
my $asc = $args{TableNibbler}->generate_asc_stmt(
@@ -3591,7 +3590,7 @@ sub new {
);
PTDEBUG && _d('Ascend params:', Dumper($asc));
my $from = $q->quote(@{$tbl}{qw(db tbl)}) . " FORCE INDEX(`$index`)";
my $from = "$tbl->{name} FORCE INDEX(`$index`)";
my $order_by = join(', ', map {$q->quote($_)} @{$index_cols});
my $first_lb_sql
@@ -3649,7 +3648,7 @@ sub new {
. " AND " . $asc->{boundaries}->{'<='} # upper boundary
. ($where ? " AND ($where)" : '')
. ($args{order_by} ? " ORDER BY $order_by" : "")
. " /*checksum chunk*/";
. " /*$comments{nibble}*/";
PTDEBUG && _d('Nibble statement:', $nibble_sql);
my $explain_nibble_sql
@@ -3661,7 +3660,7 @@ sub new {
. " AND " . $asc->{boundaries}->{'<='} # upper boundary
. ($where ? " AND ($where)" : '')
. ($args{order_by} ? " ORDER BY $order_by" : "")
. " /*explain checksum chunk*/";
. " /*explain $comments{nibble}*/";
PTDEBUG && _d('Explain nibble statement:', $explain_nibble_sql);
my $limit = $chunk_size - 1;
@@ -3688,7 +3687,7 @@ sub new {
};
}
$self->{row_est} = $row_est;
$self->{row_est} = $nibble_params->{row_est},
$self->{nibbleno} = 0;
$self->{have_rows} = 0;
$self->{rowno} = 0;
@@ -3851,6 +3850,44 @@ sub row_estimate {
return $self->{row_est};
}
sub can_nibble {
my (%args) = @_;
my @required_args = qw(Cxn tbl chunk_size OptionParser TableParser);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($cxn, $tbl, $chunk_size, $o) = @args{@required_args};
my ($row_est, $mysql_index) = get_row_estimate(
Cxn => $cxn,
tbl => $tbl,
where => $o->has('where') ? $o->get('where') : '',
);
my $one_nibble = !defined $args{one_nibble} || $args{one_nibble}
? $row_est <= $chunk_size * $o->get('chunk-size-limit')
: 0;
PTDEBUG && _d('One nibble:', $one_nibble ? 'yes' : 'no');
if ( $args{resume}
&& !defined $args{resume}->{lower_boundary}
&& !defined $args{resume}->{upper_boundary} ) {
PTDEBUG && _d('Resuming from one nibble table');
$one_nibble = 1;
}
my $index = _find_best_index(%args, mysql_index => $mysql_index);
if ( !$index && !$one_nibble ) {
die "There is no good index and the table is oversized.";
}
return {
row_est => $row_est, # nibble about this many rows
index => $index, # using this index
one_nibble => $one_nibble, # if the table fits in one nibble/chunk
};
}
sub _find_best_index {
my (%args) = @_;
my @required_args = qw(Cxn tbl TableParser);
@@ -3924,10 +3961,10 @@ sub _find_best_index {
sub _get_index_cardinality {
my (%args) = @_;
my @required_args = qw(Cxn tbl index Quoter);
my ($cxn, $tbl, $index, $q) = @args{@required_args};
my @required_args = qw(Cxn tbl index);
my ($cxn, $tbl, $index) = @args{@required_args};
my $sql = "SHOW INDEXES FROM " . $q->quote(@{$tbl}{qw(db tbl)})
my $sql = "SHOW INDEXES FROM $tbl->{name} "
. "WHERE Key_name = '$index'";
PTDEBUG && _d($sql);
my $cardinality = 1;
@@ -3941,22 +3978,25 @@ sub _get_index_cardinality {
sub get_row_estimate {
my (%args) = @_;
my @required_args = qw(Cxn tbl OptionParser TableParser Quoter);
my ($cxn, $tbl, $o, $tp, $q) = @args{@required_args};
my @required_args = qw(Cxn tbl);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($cxn, $tbl) = @args{@required_args};
if ( $args{where} ) {
PTDEBUG && _d('WHERE clause, using explain plan for row estimate');
my $table = $q->quote(@{$tbl}{qw(db tbl)});
my $sql = "EXPLAIN SELECT * FROM $table WHERE $args{where}";
if ( !$args{where} && exists $tbl->{tbl_status} ) {
PTDEBUG && _d('Using table status for row estimate');
return $tbl->{tbl_status}->{rows} || 0;
}
else {
PTDEBUG && _d('Use EXPLAIN for row estimate');
my $sql = "EXPLAIN SELECT * FROM $tbl->{name} "
. "WHERE " . ($args{where} || '1=1');
PTDEBUG && _d($sql);
my $expl = $cxn->dbh()->selectrow_hashref($sql);
PTDEBUG && _d(Dumper($expl));
return ($expl->{rows} || 0), $expl->{key};
}
else {
PTDEBUG && _d('No WHERE clause, using table status for row estimate');
return $tbl->{tbl_status}->{rows} || 0;
}
}
sub _prepare_sths {
@@ -4666,6 +4706,7 @@ sub next {
sub _iterate_files {
my ( $self ) = @_;
my $q = $self->{Quoter};
if ( !$self->{fh} ) {
my ($fh, $file) = $self->{file_itr}->();
@@ -4715,6 +4756,7 @@ sub _iterate_files {
return {
db => $self->{db},
tbl => $tbl,
name => $q->quote($self->{db}, $tbl),
ddl => $ddl,
};
}
@@ -4792,6 +4834,7 @@ sub _iterate_dbh {
return {
db => $self->{db},
tbl => $tbl,
name => $q->quote($self->{db}, $tbl),
ddl => $ddl,
tbl_status => $tbl_status,
};
@@ -6745,6 +6788,10 @@ sub main {
TableNibbler => $tn,
TableParser => $tp,
RowChecksum => $rc,
comments => {
bite => "checksum table",
nibble => "checksum chunk",
},
);
};
if ( $EVAL_ERROR ) {

View File

@@ -66,6 +66,18 @@ sub new {
# and if table can be nibbled in one chunk.
my $nibble_params = can_nibble(%args);
# Text appended to the queries in comments so caller can identify
# them in processlist, binlog, etc.
my %comments = (
bite => "bite table",
nibble => "nibble table",
);
if ( $args{comments} ) {
map { $comments{$_} = $args{comments}->{$_} }
grep { defined $args{comments}->{$_} }
keys %{$args{comments}};
}
my $where = $o->has('where') ? $o->get('where') : '';
my $tbl_struct = $tbl->{tbl_struct};
my $ignore_col = $o->has('ignore-columns')
@@ -85,7 +97,7 @@ sub new {
: join(', ', map { $q->quote($_) } @cols))
. " FROM $tbl->{name}"
. ($where ? " WHERE $where" : '')
. " /*checksum table*/";
. " /*$comments{bite}*/";
PTDEBUG && _d('One nibble statement:', $nibble_sql);
my $explain_nibble_sql
@@ -94,7 +106,7 @@ sub new {
: join(', ', map { $q->quote($_) } @cols))
. " FROM $tbl->{name}"
. ($where ? " WHERE $where" : '')
. " /*explain checksum table*/";
. " /*explain $comments{bite}*/";
PTDEBUG && _d('Explain one nibble statement:', $explain_nibble_sql);
$self = {
@@ -197,7 +209,7 @@ sub new {
. " AND " . $asc->{boundaries}->{'<='} # upper boundary
. ($where ? " AND ($where)" : '')
. ($args{order_by} ? " ORDER BY $order_by" : "")
. " /*checksum chunk*/";
. " /*$comments{nibble}*/";
PTDEBUG && _d('Nibble statement:', $nibble_sql);
my $explain_nibble_sql
@@ -209,7 +221,7 @@ sub new {
. " AND " . $asc->{boundaries}->{'<='} # upper boundary
. ($where ? " AND ($where)" : '')
. ($args{order_by} ? " ORDER BY $order_by" : "")
. " /*explain checksum chunk*/";
. " /*explain $comments{nibble}*/";
PTDEBUG && _d('Explain nibble statement:', $explain_nibble_sql);
my $limit = $chunk_size - 1;

View File

@@ -39,7 +39,7 @@ if ( !$dbh ) {
plan skip_all => 'Cannot connect to sandbox master';
}
else {
plan tests => 46;
plan tests => 48;
}
my $q = new Quoter();
@@ -94,6 +94,7 @@ sub make_nibble_iter {
one_nibble => $args{one_nibble},
resume => $args{resume},
order_by => $args{order_by},
comments => $args{comments},
%common_modules,
);
@@ -527,7 +528,7 @@ $ni = make_nibble_iter(
$ni->next();
is(
$ni->statements()->{nibble}->{Statement},
"SELECT `address_id`, `address`, `address2`, `district`, `city_id`, `postal_code` FROM `sakila`.`address` FORCE INDEX(`PRIMARY`) WHERE ((`address_id` >= ?)) AND ((`address_id` <= ?)) /*checksum chunk*/",
"SELECT `address_id`, `address`, `address2`, `district`, `city_id`, `postal_code` FROM `sakila`.`address` FORCE INDEX(`PRIMARY`) WHERE ((`address_id` >= ?)) AND ((`address_id` <= ?)) /*nibble table*/",
"--ignore-columns"
);
@@ -545,7 +546,7 @@ $ni->next();
is(
$ni->statements()->{nibble}->{Statement},
"SELECT `actor_id`, `film_id`, `last_update` FROM `sakila`.`film_actor` FORCE INDEX(`PRIMARY`) WHERE ((`actor_id` > ?) OR (`actor_id` = ? AND `film_id` >= ?)) AND ((`actor_id` < ?) OR (`actor_id` = ? AND `film_id` <= ?)) ORDER BY `actor_id`, `film_id` /*checksum chunk*/",
"SELECT `actor_id`, `film_id`, `last_update` FROM `sakila`.`film_actor` FORCE INDEX(`PRIMARY`) WHERE ((`actor_id` > ?) OR (`actor_id` = ? AND `film_id` >= ?)) AND ((`actor_id` < ?) OR (`actor_id` = ? AND `film_id` <= ?)) ORDER BY `actor_id`, `film_id` /*nibble table*/",
"Add ORDER BY to nibble SQL"
);
@@ -722,7 +723,7 @@ $ni = make_nibble_iter(
my $sql = $ni->statements()->{nibble}->{Statement};
is(
$sql,
"SELECT `c` FROM `test`.`t` WHERE c>'m' /*checksum table*/",
"SELECT `c` FROM `test`.`t` WHERE c>'m' /*bite table*/",
"One nibble SQL with where"
);
@@ -795,6 +796,43 @@ is_deeply(
"Resume from end"
);
# #############################################################################
# Customize bite and nibble statement comments.
# #############################################################################
$ni = make_nibble_iter(
db => 'sakila',
tbl => 'address',
argv => [qw(--tables sakila.address --chunk-size 10)],
comments => {
bite => "my bite",
nibble => "my nibble",
}
);
$ni->next();
is(
$ni->statements()->{nibble}->{Statement},
"SELECT `address_id`, `address`, `address2`, `district`, `city_id`, `postal_code`, `phone`, `last_update` FROM `sakila`.`address` FORCE INDEX(`PRIMARY`) WHERE ((`address_id` >= ?)) AND ((`address_id` <= ?)) /*my nibble*/",
"Custom nibble comment"
);
$ni = make_nibble_iter(
db => 'sakila',
tbl => 'address',
argv => [qw(--tables sakila.address --chunk-size 1000)],
comments => {
bite => "my bite",
nibble => "my nibble",
}
);
$ni->next();
is(
$ni->statements()->{nibble}->{Statement},
"SELECT `address_id`, `address`, `address2`, `district`, `city_id`, `postal_code`, `phone`, `last_update` FROM `sakila`.`address` /*my bite*/",
"Custom bite comment"
);
# #############################################################################
# Done.
# #############################################################################