Files
percona-toolkit/t/pt-archiver/samples/compact_col_vals.pm
2011-06-24 16:02:05 -06:00

176 lines
5.3 KiB
Perl

# This program is copyright 2010 Percona Inc.
# Feedback and improvements are welcome.
#
# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, version 2; OR the Perl Artistic License. On UNIX and similar
# systems, you can issue `man perlgpl' or `man perlartistic' to read these
# licenses.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
# Place, Suite 330, Boston, MA 02111-1307 USA.
package compact_col_vals;
# This mk-archiver plugin demonstrates how to compact a column's values.
# If a column has values {1, 3, 4, 9, 10} it is compacted to {1, 2, 3, 4, 5}
# (if $step=1). No other column values are changed. Column values are
# only compacted "downwards". So if $step=2, the value above are compacted
# to {1, 3, 4, 7, 9}.
#
# This modules does *not* allow any rows to be deleted. is_archivable()
# returns false for every row. Even if you specify --purge, the rows will
# not be purged. UPDATEs are made while the table is being nibbled.
# Options --dest and --file are not tested.
#
# If the compact column is AUTO_INCREMENT, you need to specify
# --no-safe-auto-incrment else the last row (i.e. the one with the highest
# auto inc value) will not be compacted.
#
# See compact_col_vals.sql for a before and after example.
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use constant MKDEBUG => $ENV{MKDEBUG} || 0;
use Data::Dumper;
$Data::Dumper::Indent = 1;
$Data::Dumper::Sortkeys = 1;
$Data::Dumper::Quotekeys = 0;
# ###########################################################################
# Customize these values for your tables.
# ###########################################################################
my $compact_column = 'id'; # column name to compact
my $step = 1; # amount by which column values should increase
# ###########################################################################
# Don't modify anything below here.
# ###########################################################################
sub new {
my ( $class, %args ) = @_;
my $o = $args{OptionParser};
my $q = $args{Quoter};
my $dbh = $args{dbh};
my $sth;
my $db_tbl = $q->quote($args{db}, $args{tbl});
my $sql = "UPDATE $db_tbl SET `$compact_column`=? "
. "WHERE `$compact_column`=?";
MKDEBUG && _d('sth:', $sql);
if ( !$o->get('dry-run') ) {
$sth = $dbh->prepare($sql);
}
else {
print "# compact_col_vals plugin\n$sql\n";
}
my $self = {
%args,
db_tbl => $db_tbl,
sth => $sth,
col_pos => undef,
next_val => 0,
};
return bless $self, $class;
}
sub before_begin {
my ( $self, %args ) = @_;
my $allcols = $args{allcols};
MKDEBUG && _d('allcols:', Dumper($allcols));
my $colpos = -1;
foreach my $col ( @$allcols ) {
$colpos++;
last if $col eq $compact_column;
}
if ( $colpos < 0 ) {
die "Column $compact_column not selected by mk-archiver: "
. join(', ', @$allcols);
}
MKDEBUG && _d('col pos:', $colpos);
$self->{col_pos} = $colpos;
return;
}
sub is_archivable {
my ( $self, %args ) = @_;
my $next_val = $self->{next_val};
my $row = $args{row};
my $val = $row->[$self->{col_pos}];
my $sth = $self->{sth};
MKDEBUG && _d('val:', $val);
if ( $next_val ){
if ( $val > $next_val ) {
MKDEBUG && _d('Updating', $val, 'to', $next_val);
$sth->execute($next_val, $val);
}
else {
MKDEBUG && _d('Val is OK');
}
}
else {
# This should happen once.
MKDEBUG && _d('First val:', $val);
$self->{next_val} = $val;
}
$self->{next_val}++;
MKDEBUG && _d('Next val should be', $self->{next_val});
# No rows are archivable because we're exploiting mk-archiver
# just for its ability to nibble the table. To be safe, return 0
# for every row so that any potential delete/purge operations
# will not happen.
return 0;
}
sub before_delete {
my ( $self, %args ) = @_;
# Because is_archivable() always returns 0, this sub should
# not be called by mk-archiver.
die "before_delete() was called but should not have been called!";
}
sub before_bulk_delete {
my ( $self, %args ) = @_;
# Because is_archivable() always returns 0, this sub should
# not be called by mk-archiver.
die "before_bulk_delete() was called but should not have been called!";
}
# Reset AUTO_INCREMENT to next, lowest value.
sub after_finish {
my ( $self ) = @_;
my $o = $self->{OptionParser};
my $sql = "ALTER TABLE $self->{db_tbl} AUTO_INCREMENT=$self->{next_val}";
if ( !$o->get('dry-run') ) {
MKDEBUG && _d($sql);
$self->{dbh}->do($sql);
}
else {
print "# compact_col_vals plugin\n$sql\n";
}
return;
}
sub _d {
my ($package, undef, $line) = caller 0;
@_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
map { defined $_ ? $_ : 'undef' }
@_;
print STDERR "# $package:$line $PID ", join(' ', @_), "\n";
}
1;