MDL-23682 new MySQL engine diagnostics + InnoDB is now used instead of MyISAM in new installs if available + improved mysql transaction support

This commit is contained in:
Petr Skoda 2010-08-18 16:47:00 +00:00
parent ca7b6997a6
commit d35ece6cce
5 changed files with 152 additions and 11 deletions

View File

@ -373,6 +373,12 @@ if ($showbloglevelupgrade) {
echo $OUTPUT->box(get_string('bloglevelupgradenotice', 'admin'), 'generalbox adminwarning');
}
// diagnose DB, especially the sloppy MyISAM tables
$diagnose = $DB->diagnose();
if ($diagnose !== NULL) {
echo $OUTPUT->box($diagnose, 'generalbox adminwarning');
}
// Alert if we are currently in maintenance mode
if (!empty($CFG->maintenance_enabled)) {
echo $OUTPUT->box(get_string('sitemaintenancewarning2', 'admin', "$CFG->wwwroot/$CFG->admin/settings.php?section=maintenancemode"), 'generalbox adminwarning');

View File

@ -341,6 +341,7 @@ $string['multiplerecordsfound'] = 'Multiple records found, only one record expec
$string['multiplerestorenotallow'] = 'Multiple restore execution not allowed!';
$string['mustbeloggedin'] = 'You must be logged in to do this';
$string['mustbeteacher'] = 'You must be a teacher to look at this page';
$string['myisamproblem'] = 'Database tables are using MyISAM database engine, it is recommended to use ACID compliant engine with full transaction support such as InnoDB.';
$string['needcopy'] = 'You need to copy something first!';
$string['needcoursecategroyid'] = 'Either course id or category must be specified';
$string['needphpext'] = 'You need to add {$a} support to your PHP installation';

View File

@ -96,6 +96,33 @@ class mysql_sql_generator extends sql_generator {
return array("ALTER TABLE $this->prefix$tablename AUTO_INCREMENT = $value");
}
/**
* Given one correct xmldb_table, returns the SQL statements
* to create it (inside one array)
*/
public function getCreateTableSQL($xmldb_table) {
// first find out if want some special db engine
$engine = null;
if (method_exists($this->mdb, 'get_dbengine')) {
$engine = $this->mdb->get_dbengine();
}
$sqlarr = parent::getCreateTableSQL($xmldb_table);
if (!$engine) {
// we rely on database defaults
return $sqlarr;
}
// let's inject the engine into SQL
foreach ($sqlarr as $i=>$sql) {
if (strpos($sql, 'CREATE TABLE ') === 0) {
$sqlarr[$i] .= " ENGINE = $engine";
}
}
return $sqlarr;
}
/**
* Given one correct xmldb_table, returns the SQL statements
@ -103,7 +130,7 @@ class mysql_sql_generator extends sql_generator {
*/
public function getCreateTempTableSQL($xmldb_table) {
$this->temptables->add_temptable($xmldb_table->getName());
$sqlarr = $this->getCreateTableSQL($xmldb_table);
$sqlarr = parent::getCreateTableSQL($xmldb_table); // we do not want the engine hack included in create table SQL
$sqlarr = preg_replace('/^CREATE TABLE (.*)/s', 'CREATE TEMPORARY TABLE $1', $sqlarr);
return $sqlarr;
}

View File

@ -236,6 +236,16 @@ abstract class moodle_database {
return $cfg;
}
/**
* Diagnose database and tables, this function is used
* to verify database and driver settings, db engine types, etc.
*
* @return string null means everything ok, string means problem found.
*/
public function diagnose() {
return null;
}
/**
* Connect to db
* Must be called before other methods.

View File

@ -116,6 +116,71 @@ class mysqli_native_moodle_database extends moodle_database {
return 'native';
}
/**
* Returns the current MySQL db engine.
*
* This is an ugly workaround for MySQL default engine problems,
* Moodle is designed to work best on ACID compliant databases
* with full transaction support. Do not use MyISAM.
*
* @return string or null MySQL engine name
*/
public function get_dbengine() {
if (isset($this->dboptions['dbengine'])) {
return $this->dboptions['dbengine'];
}
$engine = null;
if (!$this->external) {
// look for current engine of our config table (the first table that gets created),
// so that we create all tables with the same engine
$sql = "SELECT engine FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = '{$this->prefix}config'";
$this->query_start($sql, NULL, SQL_QUERY_AUX);
$result = $this->mysqli->query($sql);
$this->query_end($result);
if ($rec = $result->fetch_assoc()) {
$engine = $rec['engine'];
}
$result->close();
}
if ($engine) {
return $engine;
}
// get the default database engine
$sql = "SELECT @@storage_engine";
$this->query_start($sql, NULL, SQL_QUERY_AUX);
$result = $this->mysqli->query($sql);
$this->query_end($result);
if ($rec = $result->fetch_assoc()) {
$engine = $rec['@@storage_engine'];
}
$result->close();
if (!$this->external and $engine === 'MyISAM') {
// we really do not want MyISAM for Moodle, InnoDB or XtraDB is a reasonable defaults if supported
$sql = "SHOW STORAGE ENGINES";
$this->query_start($sql, NULL, SQL_QUERY_AUX);
$result = $this->mysqli->query($sql);
$this->query_end($result);
while ($res = $result->fetch_assoc()) {
if ($res['Engine'] === 'InnoDB' and $res['Support'] === 'YES') {
$engine = 'InnoDB';
break;
}
if ($res['Engine'] === 'XtraDB' and $res['Support'] === 'YES') {
$engine = 'XtraDB';
break;
}
}
$result->close();
}
return $engine;
}
/**
* Returns localised database type name
* Note: can be used before connect()
@ -143,6 +208,36 @@ class mysqli_native_moodle_database extends moodle_database {
return get_string('databasesettingssub_mysqli', 'install');
}
/**
* Diagnose database and tables, this function is used
* to verify database and driver settings, db engine types, etc.
*
* @return string null means everything ok, string means problem found.
*/
public function diagnose() {
$sloppymyisamfound = false;
$prefix = str_replace('_', '\\_', $this->prefix);
$sql = "SHOW TABLE STATUS WHERE Name LIKE BINARY '$prefix%'";
$this->query_start($sql, null, SQL_QUERY_AUX);
$result = $this->mysqli->query($sql);
$this->query_end($result);
if ($result) {
while ($arr = $result->fetch_assoc()) {
if ($arr['Engine'] === 'MyISAM') {
$sloppymyisamfound = true;
break;
}
}
$result->close();
}
if ($sloppymyisamfound) {
return get_string('myisamproblem', 'error');
} else {
return null;
}
}
/**
* Connect to db
* Must be called before other methods.
@ -1021,6 +1116,8 @@ class mysqli_native_moodle_database extends moodle_database {
*
* MyISAM does not support support transactions.
*
* You can override this via the dbtransactions option.
*
* @return bool
*/
protected function transactions_supported() {
@ -1028,20 +1125,20 @@ class mysqli_native_moodle_database extends moodle_database {
return $this->transactions_supported;
}
// Only will accept transactions if using InnoDB storage engine (more engines can be added easily BDB, Falcon...)
// this is all just guessing, might be better to just specify it in config.php
if (isset($this->dboptions['dbtransactions'])) {
$this->transactions_supported = $this->dboptions['dbtransactions'];
return $this->transactions_supported;
}
$this->transactions_supported = false;
$sql = "SELECT @@storage_engine";
$this->query_start($sql, NULL, SQL_QUERY_AUX);
$result = $this->mysqli->query($sql);
$this->query_end($result);
$engine = $this->get_dbengine();
if ($rec = $result->fetch_assoc()) {
if (in_array($rec['@@storage_engine'], array('InnoDB'))) {
$this->transactions_supported = true;
}
// Only will accept transactions if using compatible storage engine (more engines can be added easily BDB, Falcon...)
if (in_array($engine, array('InnoDB', 'INNOBASE', 'BDB', 'XtraDB', 'Aria', 'Falcon'))) {
$this->transactions_supported = true;
}
$result->close();
return $this->transactions_supported;
}