pt-table-sync: Bail out if --lock-and-rename and MySQL <= 5.5

This commit is contained in:
Brian Fraser fraserb@gmail.com
2012-06-05 14:41:36 -03:00
parent b96e43419f
commit 1f4d99665f
2 changed files with 174 additions and 11 deletions

View File

@@ -1536,20 +1536,81 @@ sub new {
sub parse {
my ( $self, $str ) = @_;
my $result = sprintf('%03d%03d%03d', $str =~ m/(\d+)/g);
my @version_parts = $str =~ m/(\d+)/g;
@version_parts = map { $_ || 0 } @version_parts[0..2];
my $result = sprintf('%03d%03d%03d', @version_parts);
PTDEBUG && _d($str, 'parses to', $result);
return $result;
}
sub version_cmp {
my ($self, $dbh, $target, $cmp) = @_;
my $version = $self->version($dbh);
my $result;
if ( $cmp eq 'ge' ) {
$result = $self->{$dbh} ge $self->parse($target) ? 1 : 0;
}
elsif ( $cmp eq 'gt' ) {
$result = $self->{$dbh} gt $self->parse($target) ? 1 : 0;
}
elsif ( $cmp eq 'eq' ) {
$result = $self->{$dbh} eq $self->parse($target) ? 1 : 0;
}
elsif ( $cmp eq 'ne' ) {
$result = $self->{$dbh} ne $self->parse($target) ? 1 : 0;
}
elsif ( $cmp eq 'lt' ) {
$result = $self->{$dbh} lt $self->parse($target) ? 1 : 0;
}
elsif ( $cmp eq 'le' ) {
$result = $self->{$dbh} le $self->parse($target) ? 1 : 0;
}
else {
die "Asked for an unknown comparizon: $cmp"
}
PTDEBUG && _d($self->{$dbh}, $cmp, $target, ':', $result);
return $result;
}
sub version_ge {
my ( $self, $dbh, $target ) = @_;
return $self->version_cmp($dbh, $target, 'ge');
}
sub version_gt {
my ( $self, $dbh, $target ) = @_;
return $self->version_cmp($dbh, $target, 'gt');
}
sub version_eq {
my ( $self, $dbh, $target ) = @_;
return $self->version_cmp($dbh, $target, 'eq');
}
sub version_ne {
my ( $self, $dbh, $target ) = @_;
return $self->version_cmp($dbh, $target, 'ne');
}
sub version_lt {
my ( $self, $dbh, $target ) = @_;
return $self->version_cmp($dbh, $target, 'lt');
}
sub version_le {
my ( $self, $dbh, $target ) = @_;
return $self->version_cmp($dbh, $target, 'le');
}
sub version {
my ( $self, $dbh ) = @_;
if ( !$self->{$dbh} ) {
$self->{$dbh} = $self->parse(
$dbh->selectrow_array('SELECT VERSION()'));
}
my $result = $self->{$dbh} ge $self->parse($target) ? 1 : 0;
PTDEBUG && _d($self->{$dbh}, 'ge', $target, ':', $result);
return $result;
return $self->{$dbh};
}
sub innodb_version {
@@ -7215,6 +7276,7 @@ use constant PTDEBUG => $ENV{PTDEBUG} || 0;
use Time::Local qw(timegm timelocal);
use Digest::MD5 qw(md5_hex);
use B qw();
require Exporter;
our @ISA = qw(Exporter);
@@ -7232,6 +7294,7 @@ our @EXPORT_OK = qw(
any_unix_timestamp
make_checksum
crc32
encode_json
);
our $mysql_ts = qr/(\d\d)(\d\d)(\d\d) +(\d+):(\d+):(\d+)(\.\d+)?/;
@@ -7439,6 +7502,96 @@ sub crc32 {
return $crc ^ 0xFFFFFFFF;
}
my $got_json = eval { require JSON };
sub encode_json {
return JSON::encode_json(@_) if $got_json;
my ( $data ) = @_;
return (object_to_json($data) || '');
}
sub object_to_json {
my ($obj) = @_;
my $type = ref($obj);
if($type eq 'HASH'){
return hash_to_json($obj);
}
elsif($type eq 'ARRAY'){
return array_to_json($obj);
}
else {
return value_to_json($obj);
}
}
sub hash_to_json {
my ($obj) = @_;
my @res;
for my $k ( sort { $a cmp $b } keys %$obj ) {
push @res, string_to_json( $k )
. ":"
. ( object_to_json( $obj->{$k} ) || value_to_json( $obj->{$k} ) );
}
return '{' . ( @res ? join( ",", @res ) : '' ) . '}';
}
sub array_to_json {
my ($obj) = @_;
my @res;
for my $v (@$obj) {
push @res, object_to_json($v) || value_to_json($v);
}
return '[' . ( @res ? join( ",", @res ) : '' ) . ']';
}
sub value_to_json {
my ($value) = @_;
return 'null' if(!defined $value);
my $b_obj = B::svref_2object(\$value); # for round trip problem
my $flags = $b_obj->FLAGS;
return $value # as is
if $flags & ( B::SVp_IOK | B::SVp_NOK ) and !( $flags & B::SVp_POK ); # SvTYPE is IV or NV?
my $type = ref($value);
if( !$type ) {
return string_to_json($value);
}
else {
return 'null';
}
}
my %esc = (
"\n" => '\n',
"\r" => '\r',
"\t" => '\t',
"\f" => '\f',
"\b" => '\b',
"\"" => '\"',
"\\" => '\\\\',
"\'" => '\\\'',
);
sub string_to_json {
my ($arg) = @_;
$arg =~ s/([\x22\x5c\n\r\t\f\b])/$esc{$1}/g;
$arg =~ s/\//\\\//g;
$arg =~ s/([\x00-\x08\x0b\x0e-\x1f])/'\\u00' . unpack('H2', $1)/eg;
utf8::upgrade($arg);
utf8::encode($arg);
return '"' . $arg . '"';
}
sub _d {
my ($package, undef, $line) = caller 0;
@_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
@@ -7556,7 +7709,7 @@ my %dsn_for;
my $q = new Quoter();
sub main {
@ARGV = @_; # set global ARGV for this package
local @ARGV = @_; # set global ARGV for this package
# Reset global vars else tests will have weird results.
%dsn_for = ();
@@ -7564,6 +7717,7 @@ sub main {
# ########################################################################
# Get configuration information.
# ########################################################################
my $vp = new VersionParser();
my $o = new OptionParser();
$o->get_specs();
$o->get_opts();
@@ -7674,7 +7828,6 @@ sub main {
# Do the work.
# ########################################################################
my $tp = new TableParser( Quoter => $q );
my $vp = new VersionParser();
my $ms = new MasterSlave(VersionParser => $vp);
my $du = new MySQLDump( cache => 0 );
my $rt = new Retry();
@@ -7825,6 +7978,13 @@ sub lock_and_rename {
tbl => $dsns->[1]->{t},
};
my $vp = VersionParser->new();
my %options = ( DSNParser => $dp, OptionParser => $o );
if ( grep { $vp->version_lt($_->{dbh}, '5.5') } $src, $dst ) {
disconnect($src, $dst);
die "--lock-and-rename requires MySQL 5.5 or later";
}
if ( $o->get('verbose') ) {
print_header("# Lock and rename " . $dp->as_string($src->{dsn}));
}
@@ -9278,9 +9438,9 @@ In general, this tool is best suited when your tables have a primary key or
unique index. Although it can synchronize data in tables lacking a primary key
or unique index, it might be best to synchronize that data by another means.
At the time of this release, there is a potential bug using
L<"--lock-and-rename"> with MySQL 5.1, a bug detecting certain differences,
a bug using ROUND() across different platforms, and a bug mixing collations.
At the time of this release, due to bugs in earlier versions of MySQL,
L<"--lock-and-rename"> is disabled in versions earlier than 5.5. Consider
using L<"pt-online-schema-change"> instead.
The authoritative source for updated information is always the online issue
tracking system. Issues that affect this tool will be marked as such. You can

View File

@@ -22,6 +22,9 @@ my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
my $master_dbh = $sb->get_dbh_for('master');
my $slave_dbh = $sb->get_dbh_for('slave1');
if ( $vp->version_le($master_dbh, '5.5') ) {
plan skip_all => "This functionality doesn't work correctly on MySQLs earlier than 5.5";
}
if ( !$master_dbh ) {
plan skip_all => 'Cannot connect to sandbox master';
}
@@ -59,5 +62,5 @@ like($output, qr/COMMENT='test1'/, '--lock-and-rename worked');
# Done.
# #############################################################################
$sb->wipe_clean($master_dbh);
ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
is($sb->ok(), '', "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
exit;