PT-1717 - resume pt-online-schema-change if it's interrupted

- Insert row with Job ID into the history table
- Update job row with progress, set 'done' to 'yes' when finished
  succesfully
This commit is contained in:
Sveta Smirnova
2024-02-21 15:22:40 +03:00
parent ab6e5aa1bb
commit c8c1b2483a
2 changed files with 106 additions and 20 deletions

View File

@@ -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'),
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;
@@ -10070,6 +10094,7 @@ sub main {
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;
},
);

View File

@@ -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.
# #############################################################################