| 1 |
<?php |
| 2 |
|
| 3 |
if (!defined('ABSPATH')) { |
| 4 |
exit; |
| 5 |
} |
| 6 |
|
| 7 |
/** |
| 8 |
* Plugin-table storage-engine drift correction. |
| 9 |
* |
| 10 |
* Walks every plugin table and ALTERs anything that is not InnoDB back to InnoDB. |
| 11 |
* Plugin tables are uniformly InnoDB by design: crash-safe, no MyISAM "table is full" |
| 12 |
* (.MYI 4 GiB) failure mode, no table-level locking on high-traffic logsv2 writes. |
| 13 |
* Hosting migrations and manual SQL restores periodically revert tables to MyISAM; |
| 14 |
* this component is the centralised place that reverts them back. |
| 15 |
* |
| 16 |
* Reachable from {@see ABJ_404_Solution_DatabaseUpgradeSelfHeal::verifyAndRepairCurrentSite()} |
| 17 |
* and from {@see ABJ_404_Solution_DatabaseUpgradeDailyMaintenance::runDatabaseMaintenanceTasks()} |
| 18 |
* via the coordinator delegate map. |
| 19 |
*/ |
| 20 |
class ABJ_404_Solution_DatabaseUpgradeEngineNormalization extends ABJ_404_Solution_DatabaseUpgradeComponent { |
| 21 |
|
| 22 |
/** @return void */ |
| 23 |
function updateTableEngineToInnoDB() { |
| 24 |
$result = $this->viewRead->getTableEngines(); |
| 25 |
$resultRows = isset($result['rows']) && is_array($result['rows']) ? $result['rows'] : []; |
| 26 |
if (empty($resultRows)) { |
| 27 |
return; |
| 28 |
} |
| 29 |
|
| 30 |
foreach ($resultRows as $row) { |
| 31 |
if (!is_array($row)) { |
| 32 |
continue; |
| 33 |
} |
| 34 |
$tableName = array_key_exists('table_name', $row) ? (string)$row['table_name'] : |
| 35 |
(array_key_exists('TABLE_NAME', $row) ? (string)$row['TABLE_NAME'] : ''); |
| 36 |
$engine = array_key_exists('engine', $row) ? (string)$row['engine'] : |
| 37 |
(array_key_exists('ENGINE', $row) ? (string)$row['ENGINE'] : ''); |
| 38 |
|
| 39 |
// All plugin tables use InnoDB: crash-safe, no row-count ceiling, no table-level |
| 40 |
// locking. The former MyISAM special-case for logsv2 ("OPTIMIZE TABLE is slow |
| 41 |
// otherwise") no longer applies -- OPTIMIZE TABLE on InnoDB has been equivalent to |
| 42 |
// ALTER TABLE ... ENGINE=InnoDB since MySQL 5.6 (rebuilds tablespace in-place). |
| 43 |
// InnoDB also eliminates the MyISAM-specific "table is full" failure mode on sites |
| 44 |
// with disk pressure (MyISAM .MYI files cannot grow past 4 GiB by default). |
| 45 |
if (strtolower($engine) === 'innodb') { |
| 46 |
continue; |
| 47 |
} |
| 48 |
|
| 49 |
$this->logger->infoMessage("Updating " . $tableName . " to InnoDB."); |
| 50 |
$query = 'alter table `' . $tableName . '` engine = InnoDB;'; |
| 51 |
|
| 52 |
$result = $this->dbCore->queryAndGetResults($query, array("log_errors" => false)); |
| 53 |
$this->logger->infoMessage("I changed an engine: " . $query); |
| 54 |
$lastError = isset($result['last_error']) && is_string($result['last_error']) ? $result['last_error'] : ''; |
| 55 |
|
| 56 |
if ($lastError !== '' && |
| 57 |
strpos($lastError, 'Index column size too large') !== false) { |
| 58 |
|
| 59 |
// delete the indexes, try again, and create the indexes later. |
| 60 |
$this->upgrades()->schemaDiffUpgrade()->deleteIndexes($tableName); |
| 61 |
|
| 62 |
$this->dbCore->queryAndGetResults($query, |
| 63 |
array("ignore_errors" => array("Unknown storage engine"))); |
| 64 |
$this->logger->infoMessage("I tried to change an engine again: " . $query); |
| 65 |
} |
| 66 |
} |
| 67 |
} |
| 68 |
} |
| 69 |
|