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 updateshadowdb 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.',
+ type => 't',
+ default => '',
+ checker => \&check_shadowdbhost,
+ },
+
+ {
+ name => 'shadowdbport',
+ desc => 'The port the shadow database is on. Ignored if ' .
+ 'shadowdbhost is blank. Note: if the host is the local ' .
+ 'machine, then MySQL will ignore this setting, and you must ' .
+ 'specify a socket below.',
+ type => 't',
+ default => '3306',
+ checker => \&check_numeric,
+ },
+
+ {
+ name => 'shadowdbsock',
+ desc => 'The socket used to connect to the shadow database, if the host ' .
+ 'is the local machine. This setting is required because MySQL ' .
+ 'ignores the port specified by the client and connects using ' .
+ 'its compiled-in socket path (on unix machines) when connecting ' .
+ 'from a client to a local server. If you leave this blank, and ' .
+ 'have the database on localhost, then the shadowdbport ' .
+ 'will be ignored.',
+ type => 't',
+ default => '',
+ },
+
+ # This entry must be _after_ the shadowdb{host,port,sock} settings so that
+ # they can be used in the validation here
{
name => 'shadowdb',
desc => 'If non-empty, then this is the name of another database in ' .
@@ -253,21 +339,12 @@ sub check_netmask {
'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!',
+ 'careful not to use the name of an existing database with useful ' . 'data in it!',
type => 't',
default => '',
checker => \&check_shadowdb
},
- {
- name => 'queryagainstshadowdb',
- desc => 'If this is on, and the shadowdb is set, then queries will ' .
- 'happen against the shadow database.',
- type => 'b',
- default => 0,
- },
-
{
name => 'useLDAP',
desc => 'Turn this on to use an LDAP directory for user authentication ' .
diff --git a/doeditparams.cgi b/doeditparams.cgi
index de40075f10..4dd4f8b52c 100755
--- a/doeditparams.cgi
+++ b/doeditparams.cgi
@@ -101,9 +101,11 @@ foreach my $i (GetParamList()) {
WriteParams();
unlink "data/versioncache";
-print "";
-system("./syncshadowdb", "-v") if (Param("shadowdb"));
-print "";
+if (Param("updateshadowdb")) {
+ print "";
+ system("./syncshadowdb", "-v");
+ print "";
+}
print "OK, done.\n";
print "Edit the params some more.
\n";
diff --git a/globals.pl b/globals.pl
index 3a2ff71a99..89919e5c0b 100644
--- a/globals.pl
+++ b/globals.pl
@@ -20,7 +20,7 @@
# Contributor(s): Terry Weissman
# Dan Mosedale
# Jacob Steenhagen
-# Bradley Baetz
+# Bradley Baetz
# Christopher Aillon
# Joel Peshkin
@@ -107,29 +107,70 @@ $::dbwritesallowed = 1;
sub ConnectToDatabase {
my ($useshadow) = (@_);
- if (!defined $::db) {
- my $name = $::db_name;
- if ($useshadow && Param("shadowdb") && Param("queryagainstshadowdb")) {
- $name = Param("shadowdb");
- $::dbwritesallowed = 0;
+ $::dbwritesallowed = !$useshadow;
+ $useshadow = ($useshadow && Param("shadowdb") &&
+ Param("queryagainstshadowdb"));
+ my $useshadow_dbh = ($useshadow && Param("shadowdbhost") ne "");
+ my $name = $useshadow ? Param("shadowdb") : $::db_name;
+ my $connectstring;
+
+ if ($useshadow_dbh) {
+ if (defined $::shadow_dbh) {
+ $::db = $::shadow_dbh;
+ return;
+ }
+ $connectstring="DBI:mysql:host=" . Param("shadowdbhost") .
+ ";database=$name;port=" . Param("shadowdbport");
+ if (Param("shadowdbsock") ne "") {
+ $connectstring .= ";mysql_socket=" . Param("shadowdbsock");
}
- $::db = DBI->connect("DBI:mysql:host=$::db_host;database=$name;port=$::db_port", $::db_user, $::db_pass)
- || die "Bugzilla is currently broken. Please try again later. " .
- "If the problem persists, please contact " . Param("maintainer") .
- ". The error you should quote is: " . $DBI::errstr;
+ } else {
+ if (defined $::main_dbh) {
+ $::db = $::main_dbh;
+ return;
+ }
+ $connectstring="DBI:mysql:host=$::db_host;database=$name;port=$::db_port";
+ if ($::db_sock ne "") {
+ $connectstring .= ";mysql_socket=$::db_sock";
+ }
+ }
+ $::db = DBI->connect($connectstring, $::db_user, $::db_pass)
+ || die "Bugzilla is currently broken. Please try again " .
+ "later. If the problem persists, please contact " .
+ Param("maintainer") . ". The error you should quote is: " .
+ $DBI::errstr;
+
+ if ($useshadow_dbh) {
+ $::shadow_dbh = $::db;
+ } else {
+ $::main_dbh = $::db;
}
}
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")) {
- SendSQL("USE " . Param("shadowdb"));
- $::dbwritesallowed = 0;
+ ConnectToDatabase(1);
+ if (!Param("shadowdbhost")) {
+ SendSQL("USE " . Param("shadowdb"));
+ }
+ }
+}
+
+sub ReconnectToMainDatabase {
+ if (Param("shadowdb") && Param("queryagainstshadowdb")) {
+ ConnectToDatabase();
+ if (!Param("shadowdbhost")) {
+ SendSQL("USE $::db_name");
+ }
}
}
my $shadowchanges = 0;
sub SyncAnyPendingShadowChanges {
- if ($shadowchanges) {
+ if ($shadowchanges && Param("updateshadowdb")) {
my $pid;
FORK: {
if ($pid = fork) { # create a fork
@@ -218,7 +259,7 @@ sub SendSQL {
my $iswrite = ($str =~ /^(INSERT|REPLACE|UPDATE|DELETE)/i);
if ($iswrite && !$::dbwritesallowed) {
- die "Evil code attempted to write stuff to the shadow database.";
+ 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;
@@ -242,7 +283,7 @@ sub SendSQL {
die "$str: " . $errstr;
}
SqlLog("Done");
- if (!$dontshadow && $iswrite && Param("shadowdb")) {
+ if (!$dontshadow && $iswrite && Param("shadowdb") && Param("updateshadowdb")) {
my $q = SqlQuote($str);
my $insertid;
if ($str =~ /^(INSERT|REPLACE)/i) {
@@ -537,7 +578,7 @@ sub GetVersionTable {
}
if (time() - $mtime > 3600) {
use Token;
- Token::CleanTokenTable();
+ Token::CleanTokenTable() if $::dbwritesallowed;
GenerateVersionTable();
}
require 'data/versioncache';
diff --git a/syncshadowdb b/syncshadowdb
index cb806bbe09..23d53a6f34 100755
--- a/syncshadowdb
+++ b/syncshadowdb
@@ -38,6 +38,8 @@ sub sillyness {
open SAVEOUT,">/dev/null";
$zz = $::db;
$zz = $::dbwritesallowed;
+ $zz = $::db_host;
+ $zz = $::db_port;
}
my $verbose = 0;
@@ -98,6 +100,15 @@ if (!Param("shadowdb")) {
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");
@@ -115,8 +126,9 @@ if ($shutdown) {
# 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";
- if ($::db_pass) { $cmd .= " -p$::db_pass" }
+ 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
@@ -240,6 +252,7 @@ if ($syncall) {
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
@@ -251,10 +264,13 @@ if ($syncall) {
if ($::db_pass) {
$extra .= " -p$::db_pass";
}
+ if ($::db_sock) {
+ $extra .= " -S$::db_sock";
+ }
if ($verbose) {
$extra .= " -v";
}
- open(MYSQL, "cat $tempfile | $::mysqlpath/mysql $extra " .
+ open(MYSQL, "/bin/cat $tempfile | $::mysqlpath/mysql $extra " .
Param("shadowdb") . "|") || die "Couldn't do db copy";
my $count = 0;
while () {