1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * MySQL table row compression tool tool. 19 * 20 * @package core 21 * @copyright 2014 Totara Learning Solutions Ltd {@link http://www.totaralms.com/} 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 * @author Petr Skoda <petr.skoda@totaralms.com> 24 */ 25 26 define('CLI_SCRIPT', true); 27 28 require(__DIR__.'/../../config.php'); 29 require_once($CFG->libdir . '/clilib.php'); 30 31 if ($DB->get_dbfamily() !== 'mysql') { 32 cli_error('This script is used for MySQL databases only.'); 33 } 34 35 $engine = strtolower($DB->get_dbengine()); 36 if ($engine !== 'innodb' and $engine !== 'xtradb') { 37 cli_error('This script is for MySQL servers using InnoDB or XtraDB engines only.'); 38 } 39 40 list($options, $unrecognized) = cli_get_params( 41 array('help' => false, 'info' => false, 'list' => false, 'fix' => false, 'showsql' => false), 42 array('h' => 'help', 'i' => 'info', 'l' => 'list', 'f' => 'fix', 's' => 'showsql') 43 ); 44 45 if ($unrecognized) { 46 $unrecognized = implode("\n ", $unrecognized); 47 cli_error(get_string('cliunknowoption', 'admin', $unrecognized)); 48 } 49 50 $help = 51 "Script for detection of row size problems in MySQL InnoDB tables. 52 53 By default InnoDB storage table is using legacy Antelope file format 54 which has major restriction on database row size. 55 Use this script to detect and fix database tables with potential data 56 overflow problems. 57 58 Options: 59 -i, --info Show database information 60 -l, --list List problematic tables 61 -f, --fix Attempt to fix all tables (requires SUPER privilege) 62 -s, --showsql Print SQL statements for fixing of tables 63 -h, --help Print out this help 64 65 Example: 66 \$ sudo -u www-data /usr/bin/php admin/cli/mysql_compressed_rows.php -l 67 "; 68 69 /** @var mysql_sql_generator $generator */ 70 $generator = $DB->get_manager()->generator; 71 72 $info = $DB->get_server_info(); 73 $filepertable = $DB->get_record_sql("SHOW VARIABLES LIKE 'innodb_file_per_table'"); 74 $filepertable = $filepertable ? $filepertable->value : ''; 75 $fileformat = $DB->get_record_sql("SHOW VARIABLES LIKE 'innodb_file_format'"); 76 $fileformat = $fileformat ? $fileformat->value : ''; 77 $prefix = $DB->get_prefix(); 78 $database = $CFG->dbname; 79 80 if (!empty($options['info'])) { 81 echo "Database version: " . $info['description'] . "\n"; 82 echo "Database name: $database\n"; 83 echo "Database engine: " . $DB->get_dbengine() . "\n"; 84 echo "innodb_file_per_table: $filepertable\n"; 85 echo "innodb_file_format: $fileformat\n"; 86 87 exit(0); 88 89 } else if (!empty($options['list'])) { 90 $problem = false; 91 foreach ($DB->get_tables(false) as $table) { 92 $columns = $DB->get_columns($table, false); 93 $size = $generator->guess_antelope_row_size($columns); 94 $format = $DB->get_row_format($table); 95 if ($size <= $generator::ANTELOPE_MAX_ROW_SIZE) { 96 continue; 97 } 98 99 echo str_pad($prefix . $table, 32, ' ', STR_PAD_RIGHT); 100 echo str_pad($format, 11, ' ', STR_PAD_RIGHT); 101 102 if ($format === 'Compact' or $format === 'Redundant') { 103 $problem = true; 104 echo " (needs fixing)\n"; 105 106 } else if ($format !== 'Compressed' and $format !== 'Dynamic') { 107 echo " (unknown)\n"; 108 109 } else { 110 echo "\n"; 111 } 112 } 113 114 if ($problem) { 115 exit(1); 116 } 117 exit(0); 118 119 } else if (!empty($options['fix'])) { 120 $fixtables = array(); 121 foreach ($DB->get_tables(false) as $table) { 122 $columns = $DB->get_columns($table, false); 123 $size = $generator->guess_antelope_row_size($columns); 124 $format = $DB->get_row_format($table); 125 if ($size <= $generator::ANTELOPE_MAX_ROW_SIZE) { 126 continue; 127 } 128 if ($format === 'Compact' or $format === 'Redundant') { 129 $fixtables[$table] = $table; 130 } 131 } 132 133 if (!$fixtables) { 134 echo "No changes necessary\n"; 135 exit(0); 136 } 137 138 if ($filepertable !== 'ON') { 139 try { 140 $DB->execute("SET GLOBAL innodb_file_per_table=1"); 141 } catch (dml_exception $e) { 142 echo "Cannot enable GLOBAL innodb_file_per_table setting, use --showsql option and execute the statements manually."; 143 throw $e; 144 } 145 } 146 if ($fileformat !== 'Barracuda') { 147 try { 148 $DB->execute("SET GLOBAL innodb_file_format=Barracuda"); 149 } catch (dml_exception $e) { 150 echo "Cannot change GLOBAL innodb_file_format setting, use --showsql option and execute the statements manually."; 151 throw $e; 152 } 153 } 154 155 if (!$DB->is_compressed_row_format_supported(false)) { 156 echo "MySQL server is not compatible with compressed row format."; 157 exit(1); 158 } 159 160 foreach ($fixtables as $table) { 161 $DB->change_database_structure("ALTER TABLE `{$prefix}$table` ROW_FORMAT=Compressed"); 162 echo str_pad($prefix . $table, 32, ' ', STR_PAD_RIGHT) . " ... Compressed\n"; 163 } 164 165 exit(0); 166 167 } else if (!empty($options['showsql'])) { 168 $fixtables = array(); 169 170 foreach ($DB->get_tables(false) as $table) { 171 $columns = $DB->get_columns($table, false); 172 $size = $generator->guess_antelope_row_size($columns); 173 $format = $DB->get_row_format($table); 174 if ($size <= $generator::ANTELOPE_MAX_ROW_SIZE) { 175 continue; 176 } 177 if ($format === 'Compact' or $format === 'Redundant') { 178 $fixtables[$table] = $table; 179 } 180 } 181 if (!$fixtables) { 182 echo "No changes necessary\n"; 183 exit(0); 184 } 185 186 echo "Copy the following SQL statements and execute them using account with SUPER privilege:\n\n"; 187 echo "USE $database;\n"; 188 echo "SET SESSION sql_mode=STRICT_ALL_TABLES;\n"; 189 echo "SET GLOBAL innodb_file_per_table=1;\n"; 190 echo "SET GLOBAL innodb_file_format=Barracuda;\n"; 191 foreach ($fixtables as $table) { 192 echo "ALTER TABLE `{$prefix}$table` ROW_FORMAT=Compressed;\n"; 193 } 194 echo "\n"; 195 exit(0); 196 197 } else { 198 echo $help; 199 die; 200 } 201 202
title
Description
Body
title
Description
Body
title
Description
Body
title
Body