Skip to content

Commit

Permalink
MDL-23682 new MySQL engine diagnostics + InnoDB is now used instead o…
Browse files Browse the repository at this point in the history
…f MyISAM in new installs if available + improved mysql transaction support
  • Loading branch information
skodak committed Aug 18, 2010
1 parent ca7b699 commit d35ece6
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 11 deletions.
6 changes: 6 additions & 0 deletions admin/index.php
Expand Up @@ -373,6 +373,12 @@
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');
Expand Down
1 change: 1 addition & 0 deletions lang/en/error.php
Expand Up @@ -341,6 +341,7 @@
$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';
Expand Down
29 changes: 28 additions & 1 deletion lib/ddl/mysql_sql_generator.php
Expand Up @@ -96,14 +96,41 @@ public function getResetSequenceSQL($table) {
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
* to create temporary table (inside one array)
*/
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;
}
Expand Down
10 changes: 10 additions & 0 deletions lib/dml/moodle_database.php
Expand Up @@ -236,6 +236,16 @@ public function export_dbconfig() {
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.
Expand Down
117 changes: 107 additions & 10 deletions lib/dml/mysqli_native_moodle_database.php
Expand Up @@ -116,6 +116,71 @@ protected function get_dblibrary() {
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()
Expand Down Expand Up @@ -143,6 +208,36 @@ public function get_configuration_hints() {
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.
Expand Down Expand Up @@ -1021,27 +1116,29 @@ public function release_session_lock($rowid) {
*
* MyISAM does not support support transactions.
*
* You can override this via the dbtransactions option.
*
* @return bool
*/
protected function transactions_supported() {
if (!is_null($this->transactions_supported)) {
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;
}
Expand Down

0 comments on commit d35ece6

Please sign in to comment.