diff --git a/html/inc/boinc_db.inc b/html/inc/boinc_db.inc
index 63ca43d5b4..ff3b4c20d4 100644
--- a/html/inc/boinc_db.inc
+++ b/html/inc/boinc_db.inc
@@ -1,7 +1,7 @@
.
+// A project can have one or more BOINC databases:
+// DB 0:
+// the main DB; read/write
+// identified in config file by db_host, db_name, db_user, db_passwd
+// db_host defaults to localhost
+// DB 1:
+// read-only replica; identified by
+// replica_db_host/name/user/passwd (must include all)
+// DB 2:
+// read-only replica; identified by
+// replica2_db_host/name/user/passwd (must include all)
+// ... and potentially more
+
function incs() {
$d = dirname(__FILE__);
require_once("$d/db_conn.inc");
@@ -24,122 +37,102 @@ function incs() {
incs();
-class BoincDb extends DbConn {
- static $instance;
+// class BoincDb represents a connection to a BOINC database.
+// All its members are static, so there's only 1 connection at a time.
+// get(n) establishes a connection to DB n,
+// or DB 0 if that fails or doesn't exit.
+// close() closes the connection.
- // connect to the database (possibly to a read-only replica)
- // NOTE: choice of replica can be made only at the page level.
- // If there's a page that's guaranteed to do only reads, put
- // BoincDb::get(true);
- // at the top of it.
- //
- // Specify a $fallback_mode that is used when $readonly is true:
- // 0: default, use db_user if no replica_db_user is specified,
- // first try replica_db_host (if specified) then db_host
- // 1: only use replica_db_user, first try replica_db_host then db_host
- // 2: only use replica_db_user, only try replica_db_host
- // can be set projectwide using
+class BoincDb {
+ static $instance; // a DbConn object, or null
+ static $dbnum; // which replica we're connected to
+
+ // connect to DB $dbnum (0, 1, ...)
+ // If the requested DB doesn't exist or connection fails, connect to DB 0.
+ // Set self::$instance; no return value
//
- static function get_aux($readonly, $fallback_mode = 0) {
- $config = get_config();
- $user = parse_config($config, '');
- $passwd = parse_config($config, '');
- $host = parse_config($config, '');
- $replica_host = parse_config($config, '');
- $name = parse_config($config, '');
- $fm = parse_config($config, '');
- if ($fm) {
- // override parameter with config.xml setting
- $fallback_mode = $fm;
- }
- if ($host == null) {
- $host = "localhost";
- }
+ static function get_aux($dbnum) {
$instance = new DbConn();
- if ($readonly) {
- if (($fallback_mode > 0) && (!$replica_host)) {
- error_log("BoincDb::get_aux(): required for \$fallback_mode > 0 (giving up)");
- $instance = null;
- self::$instance = $instance;
- return $instance;
- }
- $u = parse_config($config, '');
- $p = parse_config($config, '');
- $n = parse_config($config, '');
- if (($fallback_mode > 0) && (!$u || !$p || !$n)) {
- error_log("BoincDb::get_aux(): required for \$fallback_mode > 0 (giving up)");
- $instance = null;
- self::$instance = $instance;
- return $instance;
- } else {
- // use replica user if given or use normal user for $fallback_mode == 0
- if ($u) $user = $u;
- if ($p) $passwd = $p;
- if ($n) $name = $n;
- }
- // skip this block if no $replica_host is specified for $fallback_mode == 0
- if ($replica_host) {
- $retval = $instance->init_conn(
- $user, $passwd, $replica_host, $name, true
- );
+ self::$instance = null;
+ $config = get_config();
+ if ($dbnum) {
+ $r = $dbnum==1?'':strval($dbnum);
+ $host = parse_config($config, sprintf('', $r));
+ $name = parse_config($config, sprintf('', $r));
+ $user = parse_config($config, sprintf('', $r));
+ $passwd = parse_config($config, sprintf('', $r));
+ if ($host && $name && $user && $passwd) {
+ $retval = $instance->init_conn($user, $passwd, $host, $name);
if ($retval) {
- // needed for places where we do direct queries
- if (!$instance->do_query("use $name")) {
- error_log("BoincDb::get_aux(): Couldn't select database $name on $replica_host (giving up)");
- $instance = null;
- }
- self::$instance = $instance;
- return $instance;
- } elseif ($fallback_mode == 2) {
- // no fallback to master in this case
- error_log("BoincDb::get_aux(): Couldn't connect to $user@$replica_host (giving up)");
- $instance = null;
+ //error_log("BoincDb::get_aux(): connected to replica DB $dbnum");
self::$instance = $instance;
- return $instance;
- } else {
- error_log("BoincDb::get_aux(): Couldn't connect to $user@$replica_host (trying $user@$host next)");
+ self::$dbnum = $dbnum;
+ return;
}
}
+ // if can't connect to replica, fall through and try DB 0
}
- $retval = $instance->init_conn($user, $passwd, $host, $name, false);
- if (!$retval) {
- $instance = null;
- error_log("BoincDb::get_aux(): Couldn't connect to $user@$host (giving up)");
- } else {
- // needed for places where we do direct queries
- if (!$instance->do_query("use $name")) {
- error_log("BoincDb::get_aux(): Couldn't select database $name on $host (giving up)");
- $instance = null;
- }
+ $host = parse_config($config, '');
+ if (!$host) $host = 'localhost';
+ $user = parse_config($config, '');
+ $name = parse_config($config, '');
+ $passwd = parse_config($config, '');
+ if (!$name || !$user || !$passwd) {
+ error_log("BoincDb::get_aux(): must specify DB name, user, passwd");
+ return;
+ }
+ $retval = $instance->init_conn($user, $passwd, $host, $name);
+ if ($retval) {
+ //error_log("BoincDb::get_aux(): connected to DB $dbnum");
+ self::$instance = $instance;
+ self::$dbnum = 0;
+ return;
}
- self::$instance = $instance;
- return $instance;
+ error_log("BoincDb::get_aux(): Couldn't connect to DB $dbnum");
}
- // same, but
+ // connect to DB $dbnum, but first:
// 1) check for a cached connection
// 2) check whether the "stop_web" trigger file is present
//
- static function get($readonly = false, $fallback_mode = 0) {
+ // If there's a page that's guaranteed to do only reads, put
+ // BoincDb::get(true);
+ // at the top of it.
+ //
+ // Note: true == 1.
+ // You can also use 2, 3... to select other replicas
+ //
+ static function get($dbnum = 0) {
global $generating_xml;
- if (!isset(self::$instance)) {
- if (web_stopped()) {
- if ($generating_xml) {
- xml_error(-183, "project down for maintenance");
- } else {
- show_project_down();
- }
+ if (isset(self::$instance)) {
+ if (self::$dbnum == $dbnum) {
+ return self::$instance;
}
- self::get_aux($readonly, $fallback_mode);
- if (!self::$instance) {
- if ($generating_xml) {
- xml_error(-138, "Can't connect to database");
- } else {
- error_page("Can't connect to database");
- }
+ close();
+ }
+ if (web_stopped()) {
+ if ($generating_xml) {
+ xml_error(-183, "project down for maintenance");
+ } else {
+ show_project_down();
}
}
- return self::$instance;
+ self::get_aux($dbnum);
+ if (self::$instance) {
+ return self::$instance;
+ }
+ if ($generating_xml) {
+ xml_error(-138, "Can't connect to database");
+ } else {
+ error_page("Can't connect to database");
+ }
+ }
+
+ static function close() {
+ if (isset(self::$instance)) {
+ self::$instance->close();
+ self::$instance = null;
+ }
}
static function escape_string($string) {
diff --git a/html/inc/db.inc b/html/inc/db.inc
index 0238e80475..1c51d3b5b0 100644
--- a/html/inc/db.inc
+++ b/html/inc/db.inc
@@ -24,20 +24,7 @@ require_once("../inc/util_basic.inc");
// DEPRECATED; use boinc_db.inc instead.
// TODO: replace calls to these functions
-// use mysqli if available,
-// but let projects not use it if they want
-// (put in config.xml)
-//
-if (parse_bool(get_config(), "no_mysqli")) {
- define("MYSQLI", false);
-} else {
- if (class_exists("mysqli")) {
- define("MYSQLI", true);
- $mysqli = null;
- } else {
- define("MYSQLI", false);
- }
-}
+define("MYSQLI", true);
if (MYSQLI) {
function _mysql_connect($host, $user, $pass, $dbname) {
diff --git a/html/inc/db_conn.inc b/html/inc/db_conn.inc
index 7eb0fb70d0..b39ae8d36f 100644
--- a/html/inc/db_conn.inc
+++ b/html/inc/db_conn.inc
@@ -22,42 +22,40 @@ require_once("../inc/db.inc");
// Intended to be subclassed (e.g., BoincDb, BossaDb)
//
class DbConn {
- var $db_conn;
- var $db_name;
- var $readonly;
+ var $db_conn; // a mysqli object
+ var $db_name; // the DB name
- function init_conn($user, $passwd, $host, $name, $readonly) {
- if (MYSQLI) {
- $x = explode(":", $host);
- if (sizeof($x)>1) {
- $host = $x[0];
- $port = $x[1];
- } else {
- $port = null;
- }
- //if (version_compare(PHP_VERSION, '5.3.0') < 0) {
- if (1) { // don't use persistent connections for now
- $this->db_conn = @new mysqli($host, $user, $passwd, $name, $port);
- } else {
- $this->db_conn = @new mysqli("p:".$host, $user, $passwd, $name, $port);
- }
- // mysqli returns an object even if the connection is not established
- if (mysqli_connect_error()) {
- return false;
- }
- global $mysqli;
- $mysqli = $this->db_conn;
+ function init_conn($user, $passwd, $host, $name) {
+ $x = explode(":", $host);
+ if (sizeof($x)>1) {
+ $host = $x[0];
+ $port = $x[1];
} else {
- $this->db_conn = @mysql_pconnect($host, $user, $passwd);
+ $port = null;
+ }
+ try {
+ $this->db_conn = @new mysqli($host, $user, $passwd, $name, $port);
+ } catch(Exception $e) {
+ return false;
}
+ if (mysqli_connect_error()) {
+ return false;
+ }
+ global $mysqli;
+ $mysqli = $this->db_conn;
if (!$this->db_conn) {
return false;
}
$this->db_name = $name;
- $this->readonly = $readonly;
return true;
}
+ function close() {
+ if ($this->db_conn) {
+ $this->db_conn->close();
+ }
+ }
+
// in keeping with PHP/MySQL convention, return true (nonzero) on success.
// (This is the opposite of the BOINC convention)
//
@@ -65,11 +63,7 @@ class DbConn {
global $generating_xml;
$q = str_replace('DBNAME', $this->db_name, $q);
//echo "query: $q
\n";
- if (MYSQLI) {
- $ret = $this->db_conn->query($q);
- } else {
- $ret = mysql_query($q, $this->db_conn);
- }
+ $ret = $this->db_conn->query($q);
if (!$ret) {
if (!$generating_xml) {
echo "Database Error
\n";
@@ -85,11 +79,7 @@ class DbConn {
// # rows affected by last query
//
function affected_rows() {
- if (MYSQLI) {
- return $this->db_conn->affected_rows;
- } else {
- return mysql_affected_rows($this->db_conn);
- }
+ return $this->db_conn->affected_rows;
}
function get_list($table1, $table2, $joinfield1, $joinfield2, $classname, $fields, $where_clause, $order_clause, $limit) {
@@ -97,17 +87,10 @@ class DbConn {
$result = $this->do_query($query);
if (!$result) return null;
$x = array();
- if (MYSQLI) {
- while ($obj = $result->fetch_object($classname)) {
- $x[] = $obj;
- }
- $result->free();
- } else {
- while ($obj = mysql_fetch_object($result, $classname)) {
- $x[] = $obj;
- }
- mysql_free_result($result);
+ while ($obj = $result->fetch_object($classname)) {
+ $x[] = $obj;
}
+ $result->free();
return $x;
}
@@ -117,13 +100,8 @@ class DbConn {
if (!$result) {
return null;
}
- if (MYSQLI) {
- $obj = $result->fetch_object($classname);
- $result->free();
- } else {
- $obj = mysql_fetch_object($result, $classname);
- mysql_free_result($result);
- }
+ $obj = $result->fetch_object($classname);
+ $result->free();
return $obj;
}
@@ -140,17 +118,10 @@ class DbConn {
$result = $this->do_query($query);
if (!$result) return null;
$x = array();
- if (MYSQLI) {
- while ($obj = $result->fetch_object($classname)) {
- $x[] = $obj;
- }
- $result->free();
- } else {
- while ($obj = mysql_fetch_object($result, $classname)) {
- $x[] = $obj;
- }
- mysql_free_result($result);
+ while ($obj = $result->fetch_object($classname)) {
+ $x[] = $obj;
}
+ $result->free();
return $x;
}
@@ -192,35 +163,21 @@ class DbConn {
return $this->do_query($query);
}
function insert_id() {
- if (MYSQLI) {
- return $this->db_conn->insert_id;
- } else {
- return mysql_insert_id($this->db_conn);
- }
+ return $this->db_conn->insert_id;
}
function get_int($query, $field) {
$result = $this->do_query($query);
if (!$result) error_page("database error on query $query");
- if (MYSQLI) {
- $x = $result->fetch_object("StdClass");
- $result->free();
- } else {
- $x = mysql_fetch_object($result);
- mysql_free_result($result);
- }
+ $x = $result->fetch_object("StdClass");
+ $result->free();
if ($x) return $x->$field;
return false;
}
function get_double($query, $field) {
$result = $this->do_query($query);
if (!$result) error_page("database error on query $query");
- if (MYSQLI) {
- $x = $result->fetch_object("StdClass");
- $result->free();
- } else {
- $x = mysql_fetch_object($result);
- mysql_free_result($result);
- }
+ $x = $result->fetch_object("StdClass");
+ $result->free();
if ($x) return (double)$x->$field;
return false;
}
@@ -248,25 +205,13 @@ class DbConn {
return $this->do_query($query);
}
function base_escape_string($string) {
- if (MYSQLI) {
- return $this->db_conn->escape_string($string);
- } else {
- return mysql_real_escape_string($string);
- }
+ return $this->db_conn->escape_string($string);
}
function base_error() {
- if (MYSQLI) {
- return $this->db_conn->error;
- } else {
- return mysql_error($this->db_conn);
- }
+ return $this->db_conn->error;
}
function base_errno() {
- if (MYSQLI) {
- return $this->db_conn->errno;
- } else {
- return mysql_errno($this->db_conn);
- }
+ return $this->db_conn->errno;
}
function table_exists($table_name) {
$result = $this->do_query("show tables from DBNAME like '$table_name'");