Bug #12992993 MYSQLHOTCOPY FAILS IF VIEW EXISTS
Problem description: mysqlhotcopy fails if a view presents in the database. Analysis: Before 5.5 'FLUSH TABLES <tbl_name> ... WITH READ LOCK' will able to get lock for all tables (i.e. base tables and view tables). In 5.5 onwards 'FLUSH TABLES <tbl_name> ... WITH READ LOCK' for 'view tables' will not work, because taking flush locks on view tables is not valid. Fix: Take flush lock for 'base tables' and read lock for 'view table' separately. Note: most of the patch has been backported from bug#13006947's patch
This commit is contained in:
parent
069f5c7eac
commit
37d22846c1
@ -272,23 +272,28 @@ if ( defined $opt{regexp} ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- get list of tables to hotcopy ---
|
# --- get list of tables and views to hotcopy ---
|
||||||
|
|
||||||
my $hc_locks = "";
|
my $hc_locks = "";
|
||||||
my $hc_tables = "";
|
my $hc_tables = "";
|
||||||
|
my $hc_base_tables = "";
|
||||||
|
my $hc_views = "";
|
||||||
|
my $num_base_tables = 0;
|
||||||
|
my $num_views = 0;
|
||||||
my $num_tables = 0;
|
my $num_tables = 0;
|
||||||
my $num_files = 0;
|
my $num_files = 0;
|
||||||
|
|
||||||
foreach my $rdb ( @db_desc ) {
|
foreach my $rdb ( @db_desc ) {
|
||||||
my $db = $rdb->{src};
|
my $db = $rdb->{src};
|
||||||
my @dbh_tables = get_list_of_tables( $db );
|
my @dbh_base_tables = get_list_of_tables( $db );
|
||||||
|
my @dbh_views = get_list_of_views( $db );
|
||||||
|
|
||||||
## filter out certain system non-lockable tables.
|
## filter out certain system non-lockable tables.
|
||||||
## keep in sync with mysqldump.
|
## keep in sync with mysqldump.
|
||||||
if ($db =~ m/^mysql$/i)
|
if ($db =~ m/^mysql$/i)
|
||||||
{
|
{
|
||||||
@dbh_tables = grep
|
@dbh_base_tables = grep
|
||||||
{ !/^(apply_status|schema|general_log|slow_log)$/ } @dbh_tables
|
{ !/^(apply_status|schema|general_log|slow_log)$/ } @dbh_base_tables
|
||||||
}
|
}
|
||||||
|
|
||||||
## generate regex for tables/files
|
## generate regex for tables/files
|
||||||
@ -303,11 +308,20 @@ foreach my $rdb ( @db_desc ) {
|
|||||||
|
|
||||||
## filter (out) tables specified in t_regex
|
## filter (out) tables specified in t_regex
|
||||||
print "Filtering tables with '$t_regex'\n" if $opt{debug};
|
print "Filtering tables with '$t_regex'\n" if $opt{debug};
|
||||||
@dbh_tables = ( $negated
|
@dbh_base_tables = ( $negated
|
||||||
? grep { $_ !~ $t_regex } @dbh_tables
|
? grep { $_ !~ $t_regex } @dbh_base_tables
|
||||||
: grep { $_ =~ $t_regex } @dbh_tables );
|
: grep { $_ =~ $t_regex } @dbh_base_tables );
|
||||||
|
|
||||||
|
## filter (out) views specified in t_regex
|
||||||
|
print "Filtering tables with '$t_regex'\n" if $opt{debug};
|
||||||
|
@dbh_views = ( $negated
|
||||||
|
? grep { $_ !~ $t_regex } @dbh_views
|
||||||
|
: grep { $_ =~ $t_regex } @dbh_views );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
## Now concatenate the base table and view arrays.
|
||||||
|
my @dbh_tables = (@dbh_base_tables, @dbh_views);
|
||||||
|
|
||||||
## get list of files to copy
|
## get list of files to copy
|
||||||
my $db_dir = "$datadir/$db";
|
my $db_dir = "$datadir/$db";
|
||||||
opendir(DBDIR, $db_dir )
|
opendir(DBDIR, $db_dir )
|
||||||
@ -347,15 +361,25 @@ foreach my $rdb ( @db_desc ) {
|
|||||||
|
|
||||||
$rdb->{files} = [ @db_files ];
|
$rdb->{files} = [ @db_files ];
|
||||||
$rdb->{index} = [ @index_files ];
|
$rdb->{index} = [ @index_files ];
|
||||||
my @hc_tables = map { quote_names("$db.$_") } @dbh_tables;
|
my @hc_base_tables = map { quote_names("$db.$_") } @dbh_base_tables;
|
||||||
|
my @hc_views = map { quote_names("$db.$_") } @dbh_views;
|
||||||
|
|
||||||
|
my @hc_tables = (@hc_base_tables, @hc_views);
|
||||||
$rdb->{tables} = [ @hc_tables ];
|
$rdb->{tables} = [ @hc_tables ];
|
||||||
|
|
||||||
$hc_locks .= ", " if ( length $hc_locks && @hc_tables );
|
$hc_locks .= ", " if ( length $hc_locks && @hc_tables );
|
||||||
$hc_locks .= join ", ", map { "$_ READ" } @hc_tables;
|
$hc_locks .= join ", ", map { "$_ READ" } @hc_tables;
|
||||||
$hc_tables .= ", " if ( length $hc_tables && @hc_tables );
|
|
||||||
$hc_tables .= join ", ", @hc_tables;
|
|
||||||
|
|
||||||
$num_tables += scalar @hc_tables;
|
$hc_base_tables .= ", " if ( length $hc_base_tables && @hc_base_tables );
|
||||||
|
$hc_base_tables .= join ", ", @hc_base_tables;
|
||||||
|
$hc_views .= ", " if ( length $hc_views && @hc_views );
|
||||||
|
$hc_views .= join " READ, ", @hc_views;
|
||||||
|
|
||||||
|
@hc_tables = (@hc_base_tables, @hc_views);
|
||||||
|
|
||||||
|
$num_base_tables += scalar @hc_base_tables;
|
||||||
|
$num_views += scalar @hc_views;
|
||||||
|
$num_tables += $num_base_tables + $num_views;
|
||||||
$num_files += scalar @{$rdb->{files}};
|
$num_files += scalar @{$rdb->{files}};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -467,7 +491,10 @@ if ( $opt{dryrun} ) {
|
|||||||
print "FLUSH TABLES /*!32323 $hc_tables */\n";
|
print "FLUSH TABLES /*!32323 $hc_tables */\n";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
print "FLUSH TABLES $hc_tables WITH READ LOCK\n";
|
# Lock base tables and views separately.
|
||||||
|
print "FLUSH TABLES $hc_base_tables WITH READ LOCK\n"
|
||||||
|
if ( $hc_base_tables );
|
||||||
|
print "LOCK TABLES $hc_views READ\n" if ( $hc_views );
|
||||||
}
|
}
|
||||||
|
|
||||||
print "FLUSH LOGS\n" if ( $opt{flushlog} );
|
print "FLUSH LOGS\n" if ( $opt{flushlog} );
|
||||||
@ -484,16 +511,24 @@ else {
|
|||||||
# flush tables to make on-disk copy up to date
|
# flush tables to make on-disk copy up to date
|
||||||
$start = time;
|
$start = time;
|
||||||
$dbh->do("FLUSH TABLES /*!32323 $hc_tables */");
|
$dbh->do("FLUSH TABLES /*!32323 $hc_tables */");
|
||||||
|
printf "Flushed tables ($hc_tables) in %d seconds.\n", time-$start unless $opt{quiet};
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$dbh->do("FLUSH TABLES $hc_tables WITH READ LOCK");
|
# Lock base tables and views separately, as 'FLUSH TABLES <tbl_name>
|
||||||
printf "Locked $num_tables tables in %d seconds.\n", time-$start unless $opt{quiet};
|
# ... WITH READ LOCK' (introduced in 5.5) would fail for views.
|
||||||
$hc_started = time; # count from time lock is granted
|
# Also, flush tables to make on-disk copy up to date
|
||||||
|
$dbh->do("FLUSH TABLES $hc_base_tables WITH READ LOCK")
|
||||||
|
if ( $hc_base_tables );
|
||||||
|
printf "Flushed $num_base_tables tables with read lock ($hc_base_tables) in %d seconds.\n",
|
||||||
|
time-$start unless $opt{quiet};
|
||||||
|
|
||||||
# flush tables to make on-disk copy up to date
|
|
||||||
$start = time;
|
$start = time;
|
||||||
|
$dbh->do("LOCK TABLES $hc_views READ") if ( $hc_views );
|
||||||
|
printf "Locked $num_views views ($hc_views) in %d seconds.\n",
|
||||||
|
time-$start unless $opt{quiet};
|
||||||
|
|
||||||
|
$hc_started = time; # count from time lock is granted
|
||||||
}
|
}
|
||||||
printf "Flushed tables ($hc_tables) in %d seconds.\n", time-$start unless $opt{quiet};
|
|
||||||
$dbh->do( "FLUSH LOGS" ) if ( $opt{flushlog} );
|
$dbh->do( "FLUSH LOGS" ) if ( $opt{flushlog} );
|
||||||
$dbh->do( "RESET MASTER" ) if ( $opt{resetmaster} );
|
$dbh->do( "RESET MASTER" ) if ( $opt{resetmaster} );
|
||||||
$dbh->do( "RESET SLAVE" ) if ( $opt{resetslave} );
|
$dbh->do( "RESET SLAVE" ) if ( $opt{resetslave} );
|
||||||
@ -802,14 +837,29 @@ sub get_list_of_tables {
|
|||||||
|
|
||||||
my $tables =
|
my $tables =
|
||||||
eval {
|
eval {
|
||||||
$dbh->selectall_arrayref('SHOW TABLES FROM ' .
|
$dbh->selectall_arrayref('SHOW FULL TABLES FROM ' .
|
||||||
$dbh->quote_identifier($db))
|
$dbh->quote_identifier($db) .
|
||||||
|
' WHERE Table_type = \'BASE TABLE\'')
|
||||||
} || [];
|
} || [];
|
||||||
warn "Unable to retrieve list of tables in $db: $@" if $@;
|
warn "Unable to retrieve list of tables in $db: $@" if $@;
|
||||||
|
|
||||||
return (map { $_->[0] } @$tables);
|
return (map { $_->[0] } @$tables);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub get_list_of_views {
|
||||||
|
my ( $db ) = @_;
|
||||||
|
|
||||||
|
my $views =
|
||||||
|
eval {
|
||||||
|
$dbh->selectall_arrayref('SHOW FULL TABLES FROM ' .
|
||||||
|
$dbh->quote_identifier($db) .
|
||||||
|
' WHERE Table_type = \'VIEW\'')
|
||||||
|
} || [];
|
||||||
|
warn "Unable to retrieve list of views in $db: $@" if $@;
|
||||||
|
|
||||||
|
return (map { $_->[0] } @$views);
|
||||||
|
}
|
||||||
|
|
||||||
sub quote_names {
|
sub quote_names {
|
||||||
my ( $name ) = @_;
|
my ( $name ) = @_;
|
||||||
# given a db.table name, add quotes
|
# given a db.table name, add quotes
|
||||||
|
Loading…
x
Reference in New Issue
Block a user