diff --git a/bin/pt-online-schema-change b/bin/pt-online-schema-change index a7caaabe..e87bd6f7 100755 --- a/bin/pt-online-schema-change +++ b/bin/pt-online-schema-change @@ -8796,19 +8796,31 @@ sub main { my $cxn = $make_cxn->(dsn => $dsn); my $aux_cxn = $make_cxn->(dsn => $dsn, prev_dsn => $dsn); + my $hist_table = $q->quote($q->split_unquote($o->get('history-table'))); + my $job_id; + my $hist_sth; + my $done_sth; + if ( $o->get('history') ) { + my $got_json = eval { require JSON }; + if ( $EVAL_ERROR ) { + die("Option --history requires Perl JSON module.\n" + . "Install via cpanm:\n\tcpanm JSON\n" + . "Install via CPAN shell::\n\tperl -MCPAN -e shell\n\tinstall JSON\n" + . "Install on Debian/Ubuntu:\n\tapt install -y libjson-perl\n" + . "Install on RedHat/OEL/CentOS:\n\tyum -y install perl-JSON\n" + ); + } create_history_table( - dbh => $cxn->dbh(), - hist_table => $o->get('history-table'), + dbh => $cxn->dbh(), + hist_table => $hist_table, OptionParser => $o, TableParser => $tp, Quoter => $q, ); # parsing args here - use JSON; my $json = JSON->new->allow_nonref; my %opts = $o->opts(); - _d("DB: $db, tbl: $tbl"); my $opt_hash = {}; while ( my ($opt, $value) = each (%opts) ) { if ( $value->{got} ) { @@ -8816,10 +8828,22 @@ sub main { } } my $json_str = $json->encode($opt_hash); - print "$json_str\n"; - - #_d(Dumper($o->opts())); - + + my $insert_sth = $cxn->dbh()->prepare( + "INSERT INTO ${hist_table} (db, tbl, altr, args)" + . "VALUES(?, ?, ?, ?)" + ); + PTDEBUG && _d($insert_sth); + $insert_sth->execute($db, $tbl, $o->get('alter'), $json_str); + $job_id = $insert_sth->last_insert_id(); + $hist_sth = $cxn->dbh()->prepare( + "UPDATE ${hist_table} SET lower_boundary = ?, upper_boundary = ? " + . "WHERE job_id = ${job_id}" + ); + $done_sth = $cxn->dbh()->prepare( + "UPDATE ${hist_table} SET done = 'yes' " + . "WHERE job_id = ${job_id}" + ); } my $cluster = Percona::XtraDB::Cluster->new; @@ -10066,10 +10090,11 @@ sub main { # Exec and time the chunk checksum query. $tbl->{nibble_time} = exec_nibble( %args, - tries => $tries, - Retry => $retry, - Quoter => $q, - stats => \%stats, + tries => $tries, + Retry => $retry, + Quoter => $q, + stats => \%stats, + hist_sth => $hist_sth, ); PTDEBUG && _d('Nibble time:', $tbl->{nibble_time}); @@ -10174,6 +10199,9 @@ sub main { }, done => sub { if ( $o->get('execute') ) { + if ( $o->get('history') ) { + $done_sth->execute(); + } print ts("Copied rows OK.\n"); } }, @@ -12014,6 +12042,7 @@ sub exec_nibble { my $ub_quoted = $q->serialize_list(@{$boundary->{upper}}); my $chunk = $nibble_iter->nibble_number(); my $chunk_index = $nibble_iter->nibble_index(); + my $hist_sth = $args{hist_sth}; # Warn once per-table for these error codes if the error message @@ -12100,7 +12129,15 @@ sub exec_nibble { } } - # Success: no warnings, no errors. Return nibble time. + # Success: no warnings, no errors. Record and return nibble time. + if ( $hist_sth ) { + $hist_sth->execute( + # WHERE + @{$boundary->{lower}}, # upper boundary values + @{$boundary->{upper}}, # lower boundary values + ); + } + return $t_end - $t_start; }, ); diff --git a/t/pt-online-schema-change/pt-1717.t b/t/pt-online-schema-change/pt-1717.t index 7ed682a4..8ac11a15 100644 --- a/t/pt-online-schema-change/pt-1717.t +++ b/t/pt-online-schema-change/pt-1717.t @@ -45,15 +45,15 @@ $sb->load_file('master', "$sample/basic_no_fks_innodb.sql"); # 2. If table percona.pt_osc created when option present # 2.1.** Default name # 2.2.** Custom name -# 2.3.* Second run should not fail or modify this table (except inserting a row for new job) -# 2.4.* Case for binary index +# 2.3.** Second run should not fail or modify this table (except inserting a row for new job) +# 2.4.** Case for binary index # 2.5.** Second run for the binary index # 2.6.** Case for invalid existing table # 2.7.** Case for invalid existing table and binary index -# 3. Inserting db, tbl, alter, args +# 3.** Inserting db, tbl, alter, args # 4. Updating lower and upper boundaries # 4.1. In situation when pt-osc finishes correctly -# 4.1.1. `done` set to 'yes' +# 4.1.1.* `done` set to 'yes' # 4.2. In failures # 4.2.1. `done` set to 'no' @@ -87,15 +87,32 @@ is( ) or diag($output); $output = `/tmp/12345/use -N -e "select count(*) from information_schema.tables where TABLE_SCHEMA='percona' and table_name='pt_osc_history'"`; + is( $output + 0, 1, '--history table created when option --history was provided' ); +$output = `/tmp/12345/use -N -e "select count(*) from percona.pt_osc_history where db='pt_osc' and tbl='t' and altr='engine=innodb' and json_extract(args, '\$.alter') = 'engine=innodb' and done='yes'"`; + +is( + $output + 0, + 1, + 'Initial row with Job ID was inserted into --history table' +); + ($output, $exit) = full_output( sub { pt_online_schema_change::main(@args, "$dsn,D=pt_osc,t=t", - '--alter', 'engine=innodb', '--execute', '--history') } + '--alter', 'engine=innodb', '--execute', '--history', '--chunk-size=4') } +); + +$output = `/tmp/12345/use -N -e "select count(*) from percona.pt_osc_history where db='pt_osc' and tbl='t' and altr='engine=innodb' and json_extract(args, '\$.alter') = 'engine=innodb' and done='yes'"`; + +is( + $output + 0, + 2, + '--history table updated' ); is( @@ -138,6 +155,14 @@ like( '--history table created with BLOB data type for boundary columns with --binary-index' ); +$output = `/tmp/12345/use -N -e "select count(*) from percona.pt_osc_history where db='pt_osc' and tbl='t' and altr='engine=innodb' and json_extract(args, '\$.alter') = 'engine=innodb' and done='yes'"`; + +is( + $output + 0, + 1, + 'Initial row with Job ID was inserted into --history table with --binary-index' +); + ($output, $exit) = full_output( sub { pt_online_schema_change::main(@args, "$dsn,D=pt_osc,t=t", '--alter', 'engine=innodb', '--execute', '--history', '--binary-index') } @@ -146,7 +171,7 @@ like( is( $exit, 0, - 'second with option --binary-index finished OK' + 'second run with option --binary-index finished OK' ) or diag($output); $output = `/tmp/12345/use -N -e "select count(*) from information_schema.tables where TABLE_SCHEMA='percona' and table_name='pt_osc_history'"`; @@ -156,6 +181,14 @@ is( '--history table was created only once with --binary-index' ); +$output = `/tmp/12345/use -N -e "select count(*) from percona.pt_osc_history where db='pt_osc' and tbl='t' and altr='engine=innodb' and json_extract(args, '\$.alter') = 'engine=innodb' and done='yes'"`; + +is( + $output + 0, + 2, + '--history table with --binary-index updated' +); + ($output, $exit) = full_output( sub { pt_online_schema_change::main(@args, "$dsn,D=pt_osc,t=t", '--alter', 'engine=innodb', '--execute', '--history') } @@ -200,6 +233,14 @@ is( 'Custom --history table created' ); +$output = `/tmp/12345/use -N -e "select count(*) from pt_1717.pt_1717_history where db='pt_osc' and tbl='t' and altr='engine=innodb' and json_extract(args, '\$.alter') = 'engine=innodb' and done='yes'"`; + +is( + $output + 0, + 1, + 'Initial row with Job ID was inserted custom into --history table' +); + ($output, $exit) = full_output( sub { pt_online_schema_change::main(@args, "$dsn,D=pt_osc,t=t", '--alter', 'engine=innodb', '--execute', '--history', @@ -212,13 +253,21 @@ is( 'basic test with option --history-table finished OK when table already exists' ) or diag($output); -$output = `/tmp/12345/use -N -e "select count(*) from information_schema.tables where TABLE_SCHEMA='percona' and table_name='pt_osc_history'"`; +$output = `/tmp/12345/use -N -e "select count(*) from information_schema.tables where TABLE_SCHEMA='pt_1717' and table_name='pt_1717_history'"`; is( $output + 0, 1, 'Custom --history table was created only once' ); +$output = `/tmp/12345/use -N -e "select count(*) from pt_1717.pt_1717_history where db='pt_osc' and tbl='t' and altr='engine=innodb' and json_extract(args, '\$.alter') = 'engine=innodb' and done='yes'"`; + +is( + $output + 0, + 2, + 'Custom --history table updated' +); + # ############################################################################# # Done. # #############################################################################