Merge lp:~gryp/percona-toolkit/ptosc-lagwaiter-ptheartbeat into lp:percona-toolkit/2.2

Proposed by Kenny Gryp
Status: Superseded
Proposed branch: lp:~gryp/percona-toolkit/ptosc-lagwaiter-ptheartbeat
Merge into: lp:percona-toolkit/2.2
Diff against target: 448 lines (+301/-30)
6 files modified
bin/pt-online-schema-change (+23/-14)
bin/pt-table-checksum (+127/-16)
t/pt-online-schema-change/plugin.t (+1/-0)
t/pt-online-schema-change/samples/plugins/all_hooks.pm (+7/-0)
t/pt-table-checksum/plugin.t (+98/-0)
t/pt-table-checksum/samples/plugins/all_hooks.pm (+45/-0)
To merge this branch: bzr merge lp:~gryp/percona-toolkit/ptosc-lagwaiter-ptheartbeat
Reviewer Review Type Date Requested Status
Daniel Nichter Pending
Review via email: mp+216863@code.launchpad.net

This proposal supersedes a proposal from 2014-03-25.

This proposal has been superseded by a proposal from 2014-04-24.

Description of the change

Hi,

This merge request adds 2 features to 2 tools.

First of all, I have added --plugin to pt-table-checksum.
The necessary tests (similar to pt-osc) are added.

Then I have added a new --plugin call for pt-osc named 'get_slave_lag'.

Reason for this development is that a customer (issue #28725) wants to use the official percona toolkit packaged tools while using pt-heartbeat or tungsten to check slavelag. Both pt-osc and pt-tc need to have pt-heartbeat functionality which can be achieved with the --plugin and by overriding the $get_lag subroutine.

I have build an example plugin for both pt-osc and pt-tc in the following github branch: https://github.com/grypyrg/percona-toolkit-plugin-heartbeat/blob/master/pt-plugin-heartbeat.pm

I tried to do it as compatible as possible.
Implementing pt-heartbeat in the tools itself looked a bit more overkill and I think the plugin is a simple codechange which gives a lot of flexibility. Of course the flexibility means that this is not for novice users.

The changes that Daniel requested were implemented.

Kenny

To post a comment you must log in.
Revision history for this message
Daniel Nichter (daniel-nichter) wrote : Posted in a previous version of this proposal

This will make a good addition to the tool. Thanks for testing it. Before we merge, let's make the following changes:

1. Rename plugin hook to get-slave-lag

2. Rewrite code like:

my $get_lag;
if ( $plugin && $plugin->can('get-slave-lag') ) {
    $get_lag = $plugin->override_slavelag_check(oktorun => \$oktorun);
}
else {
    $get_lag = sub {...}
}

3. Break the code comments "# The plugin is able"... on/before 80 cols.

review: Needs Resubmitting

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'bin/pt-online-schema-change'
--- bin/pt-online-schema-change 2014-02-20 08:10:16 +0000
+++ bin/pt-online-schema-change 2014-04-23 11:30:39 +0000
@@ -8105,21 +8105,29 @@
8105 return;8105 return;
8106 };8106 };
81078107
8108 my $get_lag = sub {8108 my $get_lag;
8109 my ($cxn) = @_;8109 # The plugin is able to override the slavelag check so tools like
8110 my $dbh = $cxn->dbh();8110 # pt-heartbeat or other replicators (Tungsten...) can be used to
8111 if ( !$dbh || !$dbh->ping() ) {8111 # measure replication lag
8112 eval { $dbh = $cxn->connect() }; # connect or die trying8112 if ( $plugin && $plugin->can('get_slave_lag') ) {
8113 if ( $EVAL_ERROR ) {8113 $get_lag = $plugin->get_slave_lag(oktorun => \$oktorun);
8114 $oktorun = 0; # flag for cleanup tasks8114 } else {
8115 chomp $EVAL_ERROR;8115 $get_lag = sub {
8116 die "Lost connection to replica " . $cxn->name()8116 my ($cxn) = @_;
8117 . " while attempting to get its lag ($EVAL_ERROR)\n";8117 my $dbh = $cxn->dbh();
8118 if ( !$dbh || !$dbh->ping() ) {
8119 eval { $dbh = $cxn->connect() }; # connect or die trying
8120 if ( $EVAL_ERROR ) {
8121 $oktorun = 0; # flag for cleanup tasks
8122 chomp $EVAL_ERROR;
8123 die "Lost connection to replica " . $cxn->name()
8124 . " while attempting to get its lag ($EVAL_ERROR)\n";
8125 }
8118 }8126 }
8119 }8127 return $ms->get_slave_lag($dbh);
8120 return $ms->get_slave_lag($dbh);8128 };
8121 };8129 }
81228130
8123 $replica_lag = new ReplicaLagWaiter(8131 $replica_lag = new ReplicaLagWaiter(
8124 slaves => $slave_lag_cxns,8132 slaves => $slave_lag_cxns,
8125 max_lag => $o->get('max-lag'),8133 max_lag => $o->get('max-lag'),
@@ -11345,6 +11353,7 @@
11345 after_drop_old_table11353 after_drop_old_table
11346 before_drop_triggers11354 before_drop_triggers
11347 before_exit11355 before_exit
11356 get_slave_lag
1134811357
11349Each hook is passed different arguments. To see which arguments are passed11358Each hook is passed different arguments. To see which arguments are passed
11350to a hook, search for the hook's name in the tool's source code, like:11359to a hook, search for the hook's name in the tool's source code, like:
1135111360
=== modified file 'bin/pt-table-checksum'
--- bin/pt-table-checksum 2014-02-20 08:10:16 +0000
+++ bin/pt-table-checksum 2014-04-23 11:30:39 +0000
@@ -9223,6 +9223,30 @@
9223 my $slaves = []; # all slaves (that we can find)9223 my $slaves = []; # all slaves (that we can find)
9224 my $slave_lag_cxns; # slaves whose lag we'll check9224 my $slave_lag_cxns; # slaves whose lag we'll check
92259225
9226 # ########################################################################
9227 # Create --plugin.
9228 # ########################################################################
9229 my $plugin;
9230 if ( my $file = $o->get('plugin') ) {
9231 die "--plugin file $file does not exist\n" unless -f $file;
9232 eval {
9233 require $file;
9234 };
9235 die "Error loading --plugin $file: $EVAL_ERROR" if $EVAL_ERROR;
9236 eval {
9237 $plugin = pt_table_checksum_plugin->new(
9238 master_cxn => $master_cxn,
9239 explain => $o->get('explain'),
9240 quiet => $o->get('quiet'),
9241 resume => $o->get('resume'),
9242 Quoter => $q,
9243 TableParser => $tp,
9244 );
9245 };
9246 die "Error creating --plugin: $EVAL_ERROR" if $EVAL_ERROR;
9247 print "Created plugin from $file.\n";
9248 }
9249
9226 my $replica_lag; # ReplicaLagWaiter object9250 my $replica_lag; # ReplicaLagWaiter object
9227 my $replica_lag_pr; # Progress for ReplicaLagWaiter9251 my $replica_lag_pr; # Progress for ReplicaLagWaiter
9228 my $sys_load; # MySQLStatusWaiter object9252 my $sys_load; # MySQLStatusWaiter object
@@ -9447,6 +9471,11 @@
9447 # #####################################################################9471 # #####################################################################
9448 if ( $o->get('replicate-check') && $o->get('replicate-check-only') ) {9472 if ( $o->get('replicate-check') && $o->get('replicate-check-only') ) {
9449 PTDEBUG && _d('Will --replicate-check and exit');9473 PTDEBUG && _d('Will --replicate-check and exit');
9474
9475 # --plugin hook
9476 if ( $plugin && $plugin->can('before_replicate_check') ) {
9477 $plugin->before_replicate_check();
9478 }
94509479
9451 foreach my $slave ( @$slaves ) {9480 foreach my $slave ( @$slaves ) {
9452 my $diffs = $rc->find_replication_differences(9481 my $diffs = $rc->find_replication_differences(
@@ -9467,6 +9496,11 @@
9467 }9496 }
9468 }9497 }
94699498
9499 # --plugin hook
9500 if ( $plugin && $plugin->can('after_replicate_check') ) {
9501 $plugin->after_replicate_check();
9502 }
9503
9470 PTDEBUG && _d('Exit status', $exit_status, 'oktorun', $oktorun);9504 PTDEBUG && _d('Exit status', $exit_status, 'oktorun', $oktorun);
9471 return $exit_status;9505 return $exit_status;
9472 }9506 }
@@ -9545,23 +9579,31 @@
9545 return;9579 return;
9546 };9580 };
95479581
9548 my $get_lag = sub {9582 my $get_lag;
9549 my ($cxn) = @_;9583 # The plugin is able to override the slavelag check so tools like
9550 my $dbh = $cxn->dbh();9584 # pt-heartbeat or other replicators (Tungsten...) can be used to
9551 if ( !$dbh || !$dbh->ping() ) {9585 # measure replication lag
9552 PTDEBUG && _d('Lost connection to slave', $cxn->name(),9586 if ( $plugin && $plugin->can('get_slave_lag') ) {
9553 'while waiting for slave lag');9587 $get_lag = $plugin->get_slave_lag(oktorun => \$oktorun);
9554 eval { $dbh = $cxn->connect() }; # connect or die trying9588 } else {
9555 if ( $EVAL_ERROR ) {9589 $get_lag = sub {
9556 $oktorun = 0; # Fatal error9590 my ($cxn) = @_;
9557 chomp $EVAL_ERROR;9591 my $dbh = $cxn->dbh();
9558 die "Lost connection to replica " . $cxn->name()9592 if ( !$dbh || !$dbh->ping() ) {
9559 . " while attempting to get its lag ($EVAL_ERROR)";9593 PTDEBUG && _d('Lost connection to slave', $cxn->name(),
9594 'while waiting for slave lag');
9595 eval { $dbh = $cxn->connect() }; # connect or die trying
9596 if ( $EVAL_ERROR ) {
9597 $oktorun = 0; # Fatal error
9598 chomp $EVAL_ERROR;
9599 die "Lost connection to replica " . $cxn->name()
9600 . " while attempting to get its lag ($EVAL_ERROR)";
9601 }
9560 }9602 }
9561 }9603 return $ms->get_slave_lag($dbh);
9562 return $ms->get_slave_lag($dbh);9604 };
9563 };9605 }
95649606
9565 $replica_lag = new ReplicaLagWaiter(9607 $replica_lag = new ReplicaLagWaiter(
9566 slaves => $slave_lag_cxns,9608 slaves => $slave_lag_cxns,
9567 max_lag => $o->get('max-lag'),9609 max_lag => $o->get('max-lag'),
@@ -10169,6 +10211,19 @@
10169 };10211 };
1017010212
10171 # ########################################################################10213 # ########################################################################
10214 # Init the --plugin.
10215 # ########################################################################
10216
10217 # --plugin hook
10218 if ( $plugin && $plugin->can('init') ) {
10219 $plugin->init(
10220 slaves => $slaves,
10221 slave_lag_cxns => $slave_lag_cxns,
10222 repl_table => $repl_table,
10223 );
10224 }
10225
10226 # ########################################################################
10172 # Checksum each table.10227 # Checksum each table.
10173 # ########################################################################10228 # ########################################################################
1017410229
@@ -10272,6 +10327,12 @@
10272 @$all_cols;10327 @$all_cols;
10273 $tbl->{checksum_cols} = \@cols;10328 $tbl->{checksum_cols} = \@cols;
1027410329
10330 # --plugin hook
10331 if ( $plugin && $plugin->can('before_checksum_table') ) {
10332 $plugin->before_checksum_table(
10333 tbl => $tbl);
10334 }
10335
10275 # Finally, checksum the table.10336 # Finally, checksum the table.
10276 # The "1 while" loop is necessary because we're executing REPLACE10337 # The "1 while" loop is necessary because we're executing REPLACE
10277 # statements which don't return rows and NibbleIterator only10338 # statements which don't return rows and NibbleIterator only
@@ -10280,6 +10341,11 @@
10280 # from the done callback, uses this start time.10341 # from the done callback, uses this start time.
10281 $tbl->{checksum_results}->{start_time} = time;10342 $tbl->{checksum_results}->{start_time} = time;
10282 1 while $nibble_iter->next();10343 1 while $nibble_iter->next();
10344
10345 # --plugin hook
10346 if ( $plugin && $plugin->can('after_checksum_table') ) {
10347 $plugin->after_checksum_table();
10348 }
10283 }10349 }
10284 };10350 };
10285 if ( $EVAL_ERROR ) {10351 if ( $EVAL_ERROR ) {
@@ -12054,6 +12120,18 @@
12054tool will overwrite the PID file with the current PID. The PID file is12120tool will overwrite the PID file with the current PID. The PID file is
12055removed automatically when the tool exits.12121removed automatically when the tool exits.
1205612122
12123=item --plugin
12124
12125type: string
12126
12127Perl module file that defines a C<pt_table_checksum_plugin> class.
12128A plugin allows you to write a Perl module that can hook into many parts
12129of pt-table-checksum. This requires a good knowledge of Perl and
12130Percona Toolkit conventions, which are beyond this scope of this
12131documentation. Please contact Percona if you have questions or need help.
12132
12133See L<"PLUGIN"> for more information.
12134
12057=item --port12135=item --port
1205812136
12059short form: -P; type: int; group: Connection12137short form: -P; type: int; group: Connection
@@ -12402,6 +12480,39 @@
1240212480
12403=back12481=back
1240412482
12483=head1 PLUGIN
12484
12485The file specified by L<"--plugin"> must define a class (i.e. a package)
12486called C<pt_table_checksum_plugin> with a C<new()> subroutine.
12487The tool will create an instance of this class and call any hooks that
12488it defines. No hooks are required, but a plugin isn't very useful without
12489them.
12490
12491These hooks, in this order, are called if defined:
12492
12493 init
12494 before_replicate_check
12495 after_replicate_check
12496 get_slave_lag
12497 before_checksum_table
12498 after_checksum_table
12499
12500Each hook is passed different arguments. To see which arguments are passed
12501to a hook, search for the hook's name in the tool's source code, like:
12502
12503 # --plugin hook
12504 if ( $plugin && $plugin->can('init') ) {
12505 $plugin->init(
12506 slaves => $slaves,
12507 slave_lag_cxns => $slave_lag_cxns,
12508 repl_table => $repl_table,
12509 );
12510 }
12511
12512The comment C<# --plugin hook> precedes every hook call.
12513
12514Please contact Percona if you have questions or need help.
12515
12405=head1 DSN OPTIONS12516=head1 DSN OPTIONS
1240612517
12407These DSN options are used to create a DSN. Each option is given like12518These DSN options are used to create a DSN. Each option is given like
1240812519
=== modified file 't/pt-online-schema-change/plugin.t'
--- t/pt-online-schema-change/plugin.t 2013-03-01 00:27:39 +0000
+++ t/pt-online-schema-change/plugin.t 2014-04-23 11:30:39 +0000
@@ -56,6 +56,7 @@
56is_deeply(56is_deeply(
57 \@called,57 \@called,
58 [58 [
59 'PLUGIN get_slave_lag',
59 'PLUGIN init',60 'PLUGIN init',
60 'PLUGIN before_create_new_table',61 'PLUGIN before_create_new_table',
61 'PLUGIN after_create_new_table',62 'PLUGIN after_create_new_table',
6263
=== modified file 't/pt-online-schema-change/samples/plugins/all_hooks.pm'
--- t/pt-online-schema-change/samples/plugins/all_hooks.pm 2013-03-01 00:27:39 +0000
+++ t/pt-online-schema-change/samples/plugins/all_hooks.pm 2014-04-23 11:30:39 +0000
@@ -96,4 +96,11 @@
96 print "PLUGIN before_exit\n";96 print "PLUGIN before_exit\n";
97}97}
9898
99sub get_slave_lag {
100 my ($self, %args) = @_;
101 print "PLUGIN get_slave_lag\n";
102
103 return sub { return 0; };
104}
105
991;1061;
100107
=== added file 't/pt-table-checksum/plugin.t'
--- t/pt-table-checksum/plugin.t 1970-01-01 00:00:00 +0000
+++ t/pt-table-checksum/plugin.t 2014-04-23 11:30:39 +0000
@@ -0,0 +1,98 @@
1#!/usr/bin/env perl
2
3BEGIN {
4 die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
5 unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
6 unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
7};
8
9use strict;
10use warnings FATAL => 'all';
11use English qw(-no_match_vars);
12use Test::More;
13
14use PerconaTest;
15use Sandbox;
16require "$trunk/bin/pt-table-checksum";
17
18use Data::Dumper;
19$Data::Dumper::Indent = 1;
20$Data::Dumper::Sortkeys = 1;
21$Data::Dumper::Quotekeys = 0;
22
23my $dp = new DSNParser(opts=>$dsn_opts);
24my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
25my $master_dbh = $sb->get_dbh_for('master');
26
27if ( !$master_dbh ) {
28 plan skip_all => 'Cannot connect to sandbox master';
29}
30
31my $output;
32my $master_dsn = $sb->dsn_for('master');
33my $sample = "t/pt-table-checksum/samples";
34my $plugin = "$trunk/$sample/plugins";
35my $exit;
36my $rows;
37
38$master_dbh->prepare("drop database if exists percona")->execute();
39$master_dbh->prepare("create database percona")->execute();
40$master_dbh->prepare("create table if not exists percona.t ( a int primary key);")->execute();
41$master_dbh->prepare("insert into percona.t values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)")->execute();
42$master_dbh->prepare("analyze table percona.t;")->execute();
43
44# #############################################################################
45# all_hooks.pm
46# #############################################################################
47
48($output) = full_output(
49 sub { pt_table_checksum::main(
50 "$master_dsn",
51 '--databases', 'percona',
52 '--plugin', "$plugin/all_hooks.pm",
53 )},
54 stderr => 1,
55);
56
57my @called = $output =~ m/^PLUGIN \S+$/gm;
58
59is_deeply(
60 \@called,
61 [
62 'PLUGIN get_slave_lag',
63 'PLUGIN init',
64 'PLUGIN before_checksum_table',
65 'PLUGIN after_checksum_table',
66 ],
67 "Called all plugins on basic run"
68) or diag(Dumper($output));
69
70
71($output) = full_output(
72 sub { pt_table_checksum::main(
73 "$master_dsn",
74 '--replicate-check', '--replicate-check-only',
75 '--databases', 'percona',
76 '--plugin', "$plugin/all_hooks.pm",
77 )},
78 stderr => 1,
79);
80
81@called = $output =~ m/^PLUGIN \S+$/gm;
82
83is_deeply(
84 \@called,
85 [
86 'PLUGIN before_replicate_check',
87 'PLUGIN after_replicate_check',
88 ],
89 "Called all plugins on replicate-check run"
90) or diag(Dumper($output));
91
92
93# #############################################################################
94# Done.
95# #############################################################################
96$sb->wipe_clean($master_dbh);
97ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
98done_testing;
099
=== added directory 't/pt-table-checksum/samples/plugins'
=== added file 't/pt-table-checksum/samples/plugins/all_hooks.pm'
--- t/pt-table-checksum/samples/plugins/all_hooks.pm 1970-01-01 00:00:00 +0000
+++ t/pt-table-checksum/samples/plugins/all_hooks.pm 2014-04-23 11:30:39 +0000
@@ -0,0 +1,45 @@
1package pt_table_checksum_plugin;
2
3use strict;
4use warnings FATAL => 'all';
5use English qw(-no_match_vars);
6use constant PTDEBUG => $ENV{PTDEBUG} || 0;
7
8sub new {
9 my ($class, %args) = @_;
10 my $self = { %args };
11 return bless $self, $class;
12}
13
14sub init {
15 my ($self, %args) = @_;
16 print "PLUGIN init\n";
17}
18
19sub before_replicate_check {
20 my ($self, %args) = @_;
21 print "PLUGIN before_replicate_check\n";
22}
23
24sub after_replicate_check {
25 my ($self, %args) = @_;
26 print "PLUGIN after_replicate_check\n";
27}
28
29sub get_slave_lag {
30 my ($self, %args) = @_;
31 print "PLUGIN get_slave_lag\n";
32 return sub { return 0; };
33}
34
35sub before_checksum_table {
36 my ($self, %args) = @_;
37 print "PLUGIN before_checksum_table\n";
38}
39
40sub after_checksum_table {
41 my ($self, %args) = @_;
42 print "PLUGIN after_checksum_table\n";
43}
44
451;

Subscribers

People subscribed via source and target branches