Bug 180870 - Remove old shadowdb manual replication code

r, a=myk
This commit is contained in:
bbaetz%student.usyd.edu.au 2002-12-20 23:35:29 +00:00
parent 9011f9db22
commit a3c47abf4b
13 changed files with 55 additions and 543 deletions

View File

@ -820,7 +820,7 @@ if ($my_create_htaccess) {
open HTACCESS, ">.htaccess";
print HTACCESS <<'END';
# don't allow people to retrieve non-cgi executable files or our private data
<FilesMatch ^(.*\.pl|localconfig|processmail|syncshadowdb|runtests.sh)$>
<FilesMatch ^(.*\.pl|localconfig|processmail|runtests.sh)$>
deny from all
</FilesMatch>
END
@ -1085,7 +1085,7 @@ WriteParams();
# These are the files which need to be marked executable
my @executable_files = ('processmail', 'whineatnews.pl', 'collectstats.pl',
'checksetup.pl', 'syncshadowdb', 'importxml.pl', 'runtests.sh');
'checksetup.pl', 'importxml.pl', 'runtests.sh');
# tell me if a file is executable. All CGI files and those in @executable_files
# are executable
@ -1648,13 +1648,6 @@ $table{milestones} =
sortkey smallint not null,
unique (product_id, value)';
$table{shadowlog} =
'id int not null auto_increment primary key,
ts timestamp,
reflected tinyint not null,
command mediumtext not null,
index(reflected)';
# GRM
$table{duplicates} =
'dupe_of mediumint(9) not null,
@ -3828,6 +3821,11 @@ if ($sth->rows == 0) {
}
}
# 2002-11-XX Bug 180870 - remove manual shadowdb replication code
if (TableExists('shadowlog')) {
print "Removing shadowlog table\n";
$dbh->do("DROP TABLE shadowlog");
}
#
# Final checks...

View File

@ -67,30 +67,14 @@ sub check_shadowdb {
if ($value eq "") {
return "";
}
if (!Param("updateshadowdb")) {
# Can't test this, because ConnectToDatabase uses the param, but
# we can't set this before testing....
return "";
}
&::SendSQL("SHOW DATABASES");
while (&::MoreSQLData()) {
my $n = &::FetchOneColumn();
if (lc($n) eq lc($value)) {
return "The $n database already exists. If that's really the name you want to use for the backup, please CAREFULLY make the existing database go away somehow, and then try again.";
}
}
# We trust the admin....
trick_taint($value);
&::SendSQL("CREATE DATABASE $value");
&::SendSQL("INSERT INTO shadowlog (command) VALUES ('SYNCUP')", 1);
return "";
}
sub check_shadowdbhost {
my ($value) = (@_);
if ($value && Param("updateshadowdb")) {
return "Sorry, you can't have the shadowdb on a different connection to the main database if you want Bugzilla to handle the replication for you.";
if (!Param('shadowdbhost')) {
return "You need to specify a host when using a shadow database";
}
# Can't test existance of this because ConnectToDatabase uses the param,
# but we can't set this before testing....
# This can really only be fixed after we can use the DBI more openly
return "";
}
@ -270,51 +254,11 @@ sub check_netmask {
default => 0
},
{
name => 'queryagainstshadowdb',
desc => 'If this is on, and the <tt>shadowdb</tt> parameter is set, then ' .
'certain queries will happen against the shadow database.',
type => 'b',
default => 0,
},
{
name => 'updateshadowdb',
desc => 'If this is on, and the <tt>shadowdb</tt> parameter is set, then ' .
'Bugzilla will use the old style of shadow database in which it ' .
'manually propogates changes to the shadow database. Otherwise, ' .
'Bugzilla will assume that the <tt>shadowdb</tt> database (if ' .
'any) is being updated via replication. <b>WARNING! This ' .
'manual replication is deprecated and is going away soon ' .
'(<u>BEFORE</u> the next stable Bugzilla release).</b> It has ' .
'several problems with data consistency, and replication is the ' .
'preferred option. If this parameter is on, and you disable it, ' .
'make sure that the shadow database is already set up for ' .
'replication, or queries will return stale data.',
type => 'b',
default => 1,
},
# This entry must be _after_ updateshadowdb, because check_shadowdbhost uses
# that
{
name => 'shadowdbhost',
desc => 'The host the shadow database is on. If blank, then then we ' .
'assume it\'s on the main database host (as defined in ' .
'localconfig) and ingore the <tt>shadowdbport</tt> and ' .
'<tt>shadowdbsock</tt> parameters below, which means that this ' .
'parameter <em>must be filled in</em> if your shadow database is ' .
'on a different instance of the mysql server, even if that ' .
'instance runs on the same machine as the main database. Note ' .
'that <tt>updateshadowdb</tt> must be off if the shadow database ' .
'is on a difference mysql instance, since Bugzilla can\'t ' .
'propogate changes between instances itself, and this should be ' .
'left blank if the shadow database is on the same instance, ' .
'since Bugzilla can then reuse the same database connection for '.
'better performance.',
desc => 'The host the shadow database is on.',
type => 't',
default => '',
checker => \&check_shadowdbhost,
},
{
@ -346,11 +290,12 @@ sub check_netmask {
{
name => 'shadowdb',
desc => 'If non-empty, then this is the name of another database in ' .
'which Bugzilla will keep a shadow read-only copy of everything. ' .
'which Bugzilla will use as a read-only copy of everything. ' .
'This is done so that long slow read-only operations can be used ' .
'against this db, and not lock up things for everyone else. ' .
'Turning on this parameter will create the given database ; be ' .
'careful not to use the name of an existing database with useful ' . 'data in it!',
'against this db, and not lock up things for everyone else. This ' .
'database is on the <tt>shadowdbhost</tt>, and must exist. ' .
'Bugzilla does not update it, if you use this paramater, then ' .
'you need to set up replication for your database',
type => 't',
default => '',
checker => \&check_shadowdb

View File

@ -69,8 +69,14 @@
write locking. What this means is that if someone needs to make a
change to a bug, they will lock the entire table until the operation
is complete. Locking for write also blocks reads until the write is
complete. The
<quote>shadowdb</quote>
complete. Note that more recent versions of mysql support row level
locking using different table types. These types are slower than the
standard type, and Bugzilla does not yet take advantage of features
such as transactions which would justify this speed decrease. The
Bugzilla team are, however, happy to hear about any experiences with
row level locking and Bugzilla</para>
<para>The <quote>shadowdb</quote>
parameter was designed to get around this limitation. While only a
single user is allowed to write to a table at a time, reads can
continue unimpeded on a read-only shadow copy of the database.
@ -85,23 +91,10 @@
Bugzilla bug changes and comments per day.</para>
<para>The value of the parameter defines the name of the
shadow bug database.
Set "shadowdb" to e.g. "bug_shadowdb" if you will be running a
*very* large installation of Bugzilla.
<note>
<para>Enabling "shadowdb" can adversely affect the stability of
your installation of Bugzilla. You should regularly check that your
database is in sync. It is often advisable to force a shadow
database sync nightly via
<quote>cron</quote>.
</para>
</note>
</para>
<para>If you use the "shadowdb" option, it is only natural that you
should turn the "queryagainstshadowdb" option on as well. Otherwise
you are replicating data into a shadow database for no reason!</para>
shadow bug database. You will need to set the host and port settings
from the params page, and set up replication in your database server
so that updates reach this readonly mirror. Consult your database
documentation for more detail.</para>
</step>
<step>

View File

@ -198,7 +198,6 @@
| products |
| profiles |
| profiles_activity |
| shadowlog |
| tokens |
| versions |
| votes |
@ -290,10 +289,6 @@ sshh... don't tell your users!)
profiles_activity: Need to know who did what when to who's profile? This'll
tell you, it's a pretty complete history.
shadowlog: I could be mistaken here, but I believe this table tells you when
your shadow database is updated and what commands were used to update it. We
don't use a shadow database at our site yet, so it's pretty empty for us.
versions: Version information for every product
votes: Who voted for what when

View File

@ -559,9 +559,7 @@ AllowOverride Limit
<para>There are important files and directories that should not be a
served by the HTTP server - most files in the
<quote>data</quote>
and
<quote>shadow</quote>
directories and the
directory and the
<quote>localconfig</quote>
file. You should configure your HTTP server to not serve
these files. Failure to do so will expose critical passwords and

View File

@ -69,8 +69,14 @@
write locking. What this means is that if someone needs to make a
change to a bug, they will lock the entire table until the operation
is complete. Locking for write also blocks reads until the write is
complete. The
<quote>shadowdb</quote>
complete. Note that more recent versions of mysql support row level
locking using different table types. These types are slower than the
standard type, and Bugzilla does not yet take advantage of features
such as transactions which would justify this speed decrease. The
Bugzilla team are, however, happy to hear about any experiences with
row level locking and Bugzilla</para>
<para>The <quote>shadowdb</quote>
parameter was designed to get around this limitation. While only a
single user is allowed to write to a table at a time, reads can
continue unimpeded on a read-only shadow copy of the database.
@ -85,23 +91,10 @@
Bugzilla bug changes and comments per day.</para>
<para>The value of the parameter defines the name of the
shadow bug database.
Set "shadowdb" to e.g. "bug_shadowdb" if you will be running a
*very* large installation of Bugzilla.
<note>
<para>Enabling "shadowdb" can adversely affect the stability of
your installation of Bugzilla. You should regularly check that your
database is in sync. It is often advisable to force a shadow
database sync nightly via
<quote>cron</quote>.
</para>
</note>
</para>
<para>If you use the "shadowdb" option, it is only natural that you
should turn the "queryagainstshadowdb" option on as well. Otherwise
you are replicating data into a shadow database for no reason!</para>
shadow bug database. You will need to set the host and port settings
from the params page, and set up replication in your database server
so that updates reach this readonly mirror. Consult your database
documentation for more detail.</para>
</step>
<step>

View File

@ -198,7 +198,6 @@
| products |
| profiles |
| profiles_activity |
| shadowlog |
| tokens |
| versions |
| votes |
@ -290,10 +289,6 @@ sshh... don't tell your users!)
profiles_activity: Need to know who did what when to who's profile? This'll
tell you, it's a pretty complete history.
shadowlog: I could be mistaken here, but I believe this table tells you when
your shadow database is updated and what commands were used to update it. We
don't use a shadow database at our site yet, so it's pretty empty for us.
versions: Version information for every product
votes: Who voted for what when

View File

@ -559,9 +559,7 @@ AllowOverride Limit
<para>There are important files and directories that should not be a
served by the HTTP server - most files in the
<quote>data</quote>
and
<quote>shadow</quote>
directories and the
directory and the
<quote>localconfig</quote>
file. You should configure your HTTP server to not serve
these files. Failure to do so will expose critical passwords and

View File

@ -101,11 +101,6 @@ foreach my $i (GetParamList()) {
WriteParams();
unlink "data/versioncache";
if (Param("updateshadowdb")) {
print "<PRE>";
system("./syncshadowdb", "-v");
print "</PRE>";
}
print "OK, done.<p>\n";
print "<a href=editparams.cgi>Edit the params some more.</a><p>\n";

View File

@ -109,19 +109,16 @@ $::dbwritesallowed = 1;
sub ConnectToDatabase {
my ($useshadow) = (@_);
$::dbwritesallowed = !$useshadow;
$useshadow = ($useshadow && Param("shadowdb") &&
Param("queryagainstshadowdb"));
my $useshadow_dbh = ($useshadow && Param("shadowdbhost") ne "");
my $name = $useshadow ? Param("shadowdb") : $::db_name;
$useshadow &&= Param("shadowdb");
my $connectstring;
if ($useshadow_dbh) {
if ($useshadow) {
if (defined $::shadow_dbh) {
$::db = $::shadow_dbh;
return;
}
$connectstring="DBI:mysql:host=" . Param("shadowdbhost") .
";database=$name;port=" . Param("shadowdbport");
";database=" . Param('shadowdb') . ";port=" . Param("shadowdbport");
if (Param("shadowdbsock") ne "") {
$connectstring .= ";mysql_socket=" . Param("shadowdbsock");
}
@ -130,7 +127,7 @@ sub ConnectToDatabase {
$::db = $::main_dbh;
return;
}
$connectstring="DBI:mysql:host=$::db_host;database=$name;port=$::db_port";
$connectstring="DBI:mysql:host=$::db_host;database=$::db_name;port=$::db_port";
if ($::db_sock ne "") {
$connectstring .= ";mysql_socket=$::db_sock";
}
@ -141,7 +138,7 @@ sub ConnectToDatabase {
Param("maintainer") . ". The error you should quote is: " .
$DBI::errstr;
if ($useshadow_dbh) {
if ($useshadow) {
$::shadow_dbh = $::db;
} else {
$::main_dbh = $::db;
@ -149,58 +146,17 @@ sub ConnectToDatabase {
}
sub ReconnectToShadowDatabase {
# This will connect us to the shadowdb if we're not already connected,
# but if we're using the same dbh for both the main db and the shadowdb,
# be sure to USE the correct db
if (Param("shadowdb") && Param("queryagainstshadowdb")) {
if (Param("shadowdb")) {
ConnectToDatabase(1);
if (!Param("shadowdbhost")) {
SendSQL("USE " . Param("shadowdb"));
}
}
}
sub ReconnectToMainDatabase {
if (Param("shadowdb") && Param("queryagainstshadowdb")) {
if (Param("shadowdb")) {
ConnectToDatabase();
if (!Param("shadowdbhost")) {
SendSQL("USE $::db_name");
}
}
}
my $shadowchanges = 0;
sub SyncAnyPendingShadowChanges {
if ($shadowchanges && Param("updateshadowdb")) {
my $pid;
FORK: {
if ($pid = fork) { # create a fork
# parent code runs here
$shadowchanges = 0;
return;
} elsif (defined $pid) {
# child process code runs here
my $redir = ($^O =~ /MSWin32/i) ? "NUL" : "/dev/null";
open STDOUT,">$redir";
open STDERR,">$redir";
exec("./syncshadowdb","--") or die "Unable to exec syncshadowdb: $!";
# the idea was that passing the second parameter tricks it into
# using execvp instead of running a shell. Not really necessary since
# there are no shell meta-characters, but it passes our tinderbox
# test that way. :) http://bugzilla.mozilla.org/show_bug.cgi?id=21253
} elsif ($! =~ /No more process/) {
# recoverable fork error, try again in 5 seconds
sleep 5;
redo FORK;
} else {
# something weird went wrong
die "Can't create background process to run syncshadowdb: $!";
}
}
}
}
# This is used to manipulate global state used by SendSQL(),
# MoreSQLData() and FetchSQLData(). It provides a way to do another
# SQL query without losing any as-yet-unfetched data from an existing
@ -248,7 +204,7 @@ sub SqlLog {
}
sub SendSQL {
my ($str, $dontshadow) = (@_);
my ($str) = (@_);
# Don't use DBI's taint stuff yet, because:
# a) We don't want out vars to be tainted (yet)
@ -262,12 +218,10 @@ sub SendSQL {
if ($iswrite && !$::dbwritesallowed) {
die "Evil code attempted to write '$str' to the shadow database";
}
if ($str =~ /^LOCK TABLES/i && $str !~ /shadowlog/ && $::dbwritesallowed) {
$str =~ s/^LOCK TABLES/LOCK TABLES shadowlog WRITE, /i;
}
# If we are shutdown, we don't want to run queries except in special cases
if (Param('shutdownhtml')) {
if ($0 =~ m:[\\/]((do)?editparams.cgi|syncshadowdb)$:) {
if ($0 =~ m:[\\/]((do)?editparams.cgi)$:) {
$::ignorequery = 0;
} else {
$::ignorequery = 1;
@ -284,19 +238,6 @@ sub SendSQL {
die "$str: " . $errstr;
}
SqlLog("Done");
if (!$dontshadow && $iswrite && Param("shadowdb") && Param("updateshadowdb")) {
my $q = SqlQuote($str);
my $insertid;
if ($str =~ /^(INSERT|REPLACE)/i) {
SendSQL("SELECT LAST_INSERT_ID()");
$insertid = FetchOneColumn();
}
SendSQL("INSERT INTO shadowlog (command) VALUES ($q)", 1);
if ($insertid) {
SendSQL("SET LAST_INSERT_ID = $insertid");
}
$shadowchanges++;
}
}
sub MoreSQLData {

View File

@ -395,14 +395,6 @@ while (MoreSQLData()) {
push(@groupstoadd, $id)
}
}
# Lock tables before inserting records for the new bug into the database
# if we are using a shadow database to prevent shadow database corruption
# when two bugs get created at the same time.
SendSQL("LOCK TABLES bugs WRITE, bug_group_map WRITE, longdescs WRITE, " .
"cc WRITE, keywords WRITE, dependencies WRITE, bugs_activity WRITE, " .
"fielddefs READ, profiles READ, keyworddefs READ") if Param("shadowdb");
# Add the bug report to the DB.
SendSQL($sql);
@ -465,8 +457,6 @@ if (UserInGroup("editbugs")) {
}
}
SendSQL("UNLOCK TABLES") if Param("shadowdb");
# Assemble the -force* strings so this counts as "Added to this capacity"
my @ARGLIST = ();
if (@cc) {

View File

@ -1,327 +0,0 @@
#!/usr/bonsaitools/bin/perl -w
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is the Bugzilla Bug Tracking System.
#
# The Initial Developer of the Original Code is Netscape Communications
# Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Terry Weissman <terry@mozilla.org>
# David Gardiner <david.gardiner@unisa.edu.au>
use strict;
use lib qw(.);
use Bugzilla::Config qw(:DEFAULT :admin);
require "globals.pl";
require "defparams.pl";
# Shut up misguided -w warnings about "used only once". "use vars" just
# doesn't work for me.
sub sillyness {
my $zz;
open SAVEOUT,">/dev/null";
$zz = $::db;
$zz = $::dbwritesallowed;
$zz = $::db_host;
$zz = $::db_port;
}
my $verbose = 0;
my $syncall = 0;
my $shutdown = 0;
my $tempdir = "data";
my $force = 0;
my $shutdown_msg = "Bugzilla is temporarily disabled while the database is backed up. Try again in a few minutes.";
sub Usage {
print "Usage: syncshadowdb [-v] [-syncall] [-shutdown] [-tempdir dirname] [-force]\n";
exit;
}
while (my $opt = shift @ARGV) {
if ($opt eq '-v') {
$verbose = 1;
} elsif ($opt eq '-syncall') {
$syncall = 1;
$verbose = 1;
} elsif ($opt eq '-shutdown') {
$shutdown = 1;
} elsif ($opt eq '-tempdir') {
my $dir = shift @ARGV;
if (-d $dir) {
$tempdir = $dir;
} else {
print "$dir does not exist or is not a directory. No syncing performed";
exit;
}
} elsif ($opt eq '-force') {
$force = 1;
} elsif ($opt eq '--') {
# do nothing - null parameter so we can use
# multi-param system() call in globals.pl
} else {
Usage();
}
}
$| = 1;
my $logtostderr = 0;
sub Verbose ($) {
my ($str) = (@_);
if ($verbose) {
if ($logtostderr) {
print STDERR $str, "\n";
} else {
print $str, "\n";
}
}
}
if (!Param("shadowdb")) {
Verbose("We don't have shadow databases turned on; no syncing performed.");
exit;
}
if (!Param("updateshadowdb")) {
Verbose("This shadow database is not set to be updated by Bugzilla.\nSee the mysql replication FAQ if you want to pause the main db until the\nshadowdb catches up");
# I could run the commands here, but that involves keeping a connection
# open to the main db and the shadowdb at the same time, and our current
# db stuff doesn't support that. Its not sufficient to reconnect, because
# the lock on the main db will be dropped when the connection closes...
exit 1;
}
if (Param("shutdownhtml") && ! $force) {
Verbose("Bugzilla was shutdown prior to running syncshadowdb. \n" .
" If you wish to sync anyway, use the -force command line option");
exit;
}
my $wasshutdown = "";
if ($shutdown) {
Verbose ("Shutting down bugzilla and waiting for connections to clear");
# Record the old shutdownhtml so it can be restored at the end (this will
# only be an issue if we are called using the -force command line param)
$wasshutdown = Param("shutdownhtml");
SetParam('shutdownhtml', $shutdown_msg);
WriteParams();
# Now we need to wait for existing connections to this database to clear. We
# do this by looking for connections to the main or shadow database using
# 'mysqladmin processlist'
my $cmd = "$::mysqlpath/mysqladmin -u $::db_user -h $::db_host -P $::db_port";
if ($::db_pass) { $cmd .= " -p$::db_pass"; }
if ($::db_sock) { $cmd .= " -S$::db_sock"; }
$cmd .= " processlist";
my $found_proc = 1;
# We need to put together a nice little regular expression to use in the
# following loop that'll tell us if the return from mysqladmin contains
# either the main or shadow database.
my @dbs = ($::db_name, Param("shadowdb"));
my $db_expr = "^\\s*(" . join ("\|", @dbs) . ")\\s*\$";
# Don't let this thing wait forever...
my $starttime = time();
while ($found_proc) {
$found_proc = 0;
open (PROC, $cmd . "|");
my @output = <PROC>;
close (PROC);
foreach my $line(@output) {
my @info = split (/\|/, $line);
# Ignore any line that doesn't have 9 pieces of info
# or contain Id (pretty printing crap)
if ($#info != 9 || $line =~ /Id/) { next }
if ($info[4] =~ m/$db_expr/) {
$found_proc = 1;
}
}
# If there are still active connections to Bugzilla 10 minutes after
# shutting it down, then something is wrong.
if ((time() - $starttime) > 600) {
# There should be a better way to notify the admin of something bad like
# this happening.
Verbose ("*** Waited for 10 minutes and there were still active \n" .
" connections to the bugzilla database. Giving up.");
SetParam('shutdownhtml', $wasshutdown);
WriteParams();
exit;
}
}
}
my $wasusing = Param("queryagainstshadowdb");
SetParam('queryagainstshadowdb', 1); # Force us to be able to use the
# shadowdb, even if other processes
# are not supposed to.
ConnectToDatabase(1);
Verbose("Acquiring lock");
if ( $syncall == 1) {
SendSQL("SELECT GET_LOCK('synclock', 2700)");
} else {
SendSQL("SELECT GET_LOCK('synclock', 1)");
}
if (!FetchOneColumn()) {
Verbose("Couldn't get the lock to do the shadow database syncing.");
exit;
}
my $shadowtable = "$::db_name.shadowlog";
if (!$syncall) {
Verbose("Looking for requests to sync the whole database.");
SendSQL("SELECT id FROM $shadowtable " .
"WHERE reflected = 0 AND command = 'SYNCUP'");
if (FetchOneColumn()) {
$syncall = 1;
}
}
if ($syncall) {
Verbose("Syncing up the shadow database by copying entire database in.");
if ($wasusing) {
SetParam('queryagainstshadowdb',0);
WriteParams();
if (! $shutdown) {
Verbose("Disabled reading from the shadowdb. Sleeping 10 seconds to let other procs catch up.");
sleep(10);
}
SetParam('queryagainstshadowdb', 1);
}
my @tables;
SendSQL("SHOW TABLES");
my $query = "";
while (MoreSQLData()) {
my $table = FetchOneColumn();
push(@tables, $table);
if ($query) {
$query .= ", $table WRITE";
} else {
$query = "LOCK TABLES $table WRITE";
}
}
if (@tables) {
Verbose("Locking entire shadow database");
SendSQL($query);
foreach my $table (@tables) {
Verbose("Dropping old shadow table $table");
SendSQL("DROP TABLE $table");
}
SendSQL("UNLOCK TABLES");
}
# Carefully lock the whole real database for reading, except for the
# shadowlog table, which we lock for writing. Then dump everything
# into the shadowdb database. Then mark everything in the shadowlog
# as reflected. Only then unlock everything. This sequence causes
# us to be sure not to miss anything or get something twice.
SendSQL("USE $::db_name");
SendSQL("SHOW TABLES");
@tables = ();
$query = "LOCK TABLES shadowlog WRITE";
while (MoreSQLData()) {
my $table = FetchOneColumn();
if ($table ne "shadowlog") {
$query .= ", $table READ";
push(@tables, $table);
}
}
Verbose("Locking entire database");
SendSQL($query);
my $tempfile = "$tempdir/tmpsyncshadow.$$";
Verbose("Dumping database to a temp file ($tempfile).");
my @ARGS = ("-u", $::db_user);
if ($::db_pass) { push @ARGS, "-p$::db_pass" }
if ($::db_sock) { push @ARGS, "-S$::db_sock" }
push @ARGS, "-l", "-e", $::db_name, @tables;
open SAVEOUT, ">&STDOUT"; # stash the original output stream
open STDOUT, ">$tempfile"; # redirect to file
select STDOUT; $| = 1; # disable buffering
system("$::mysqlpath/mysqldump", @ARGS);
open STDOUT, ">&SAVEOUT"; # redirect back to original stream
Verbose("Restoring from tempfile into shadowdb");
my $extra = "-u $::db_user";
if ($::db_pass) {
$extra .= " -p$::db_pass";
}
if ($::db_sock) {
$extra .= " -S$::db_sock";
}
if ($verbose) {
$extra .= " -v";
}
open(MYSQL, "/bin/cat $tempfile | $::mysqlpath/mysql $extra " .
Param("shadowdb") . "|") || die "Couldn't do db copy";
my $count = 0;
while (<MYSQL>) {
print ".";
$count++;
if ($count % 70 == 0) {
print "\n";
}
}
close(MYSQL);
unlink($tempfile);
Verbose("");
$::dbwritesallowed = 1;
# SendSQL("UPDATE shadowlog SET reflected = 1 WHERE reflected = 0", 1);
SendSQL("DELETE FROM shadowlog", 1);
SendSQL("UNLOCK TABLES");
if ($wasusing) {
Verbose("Reenabling other processes to read from the shadow db");
SetParam('queryagainstshadowdb', 1);
WriteParams();
}
if ($shutdown) {
Verbose("Restoring the original shutdown message (if any)");
SetParam('shutdownhtml', $wasshutdown);
WriteParams();
}
Verbose("OK, done.");
}
Verbose("Looking for commands to execute.");
$::dbwritesallowed = 1;
# Make us low priority, to not block anyone who is trying to actually use
# the shadowdb. Note that this is carefully coded to ignore errors; we want
# to keep going even on older mysqld's that don't have the
# SQL_LOW_PRIORITY_UPDATES option.
$::db->do("SET OPTION SQL_LOW_PRIORITY_UPDATES = 1");
while (1) {
SendSQL("SELECT id, command FROM $shadowtable WHERE reflected = 0 " .
"ORDER BY id LIMIT 1");
my ($id, $command) = (FetchSQLData());
if (!$id) {
last;
}
Verbose("Executing command in shadow db: $command");
SendSQL($command, 1);
SendSQL("UPDATE $shadowtable SET reflected = 1 WHERE id = $id", 1);
}
Verbose("Releasing lock.");
SendSQL("SELECT RELEASE_LOCK('synclock')");

View File

@ -53,5 +53,3 @@
</body>
</html>
[% CALL SyncAnyPendingShadowChanges() IF SyncAnyPendingShadowChanges %]