moodle /admin/cli/mysql_compressed_rows.php

Language PHP Lines 203
MD5 Hash 491db49fed8ae1475e03994555c6e358 Estimated Cost $3,557 (why?)
Repository git://github.com/moodle/moodle.git View Raw File View Project SPDX
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * MySQL table row compression tool tool.
 *
 * @package   core
 * @copyright 2014 Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 * @author    Petr Skoda <petr.skoda@totaralms.com>
 */

define('CLI_SCRIPT', true);

require(__DIR__.'/../../config.php');
require_once($CFG->libdir . '/clilib.php');

if ($DB->get_dbfamily() !== 'mysql') {
    cli_error('This script is used for MySQL databases only.');
}

$engine = strtolower($DB->get_dbengine());
if ($engine !== 'innodb' and $engine !== 'xtradb') {
    cli_error('This script is for MySQL servers using InnoDB or XtraDB engines only.');
}

list($options, $unrecognized) = cli_get_params(
    array('help' => false, 'info' => false, 'list' => false, 'fix' => false, 'showsql' => false),
    array('h' => 'help', 'i' => 'info', 'l' => 'list', 'f' => 'fix', 's' => 'showsql')
);

if ($unrecognized) {
    $unrecognized = implode("\n  ", $unrecognized);
    cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
}

$help =
    "Script for detection of row size problems in MySQL InnoDB tables.

By default InnoDB storage table is using legacy Antelope file format
which has major restriction on database row size.
Use this script to detect and fix database tables with potential data
overflow problems.

Options:
-i, --info            Show database information
-l, --list            List problematic tables
-f, --fix             Attempt to fix all tables (requires SUPER privilege)
-s, --showsql         Print SQL statements for fixing of tables
-h, --help            Print out this help

Example:
\$ sudo -u www-data /usr/bin/php admin/cli/mysql_compressed_rows.php -l
";

/** @var mysql_sql_generator $generator */
$generator = $DB->get_manager()->generator;

$info = $DB->get_server_info();
$filepertable = $DB->get_record_sql("SHOW VARIABLES LIKE 'innodb_file_per_table'");
$filepertable = $filepertable ? $filepertable->value : '';
$fileformat = $DB->get_record_sql("SHOW VARIABLES LIKE 'innodb_file_format'");
$fileformat = $fileformat ? $fileformat->value : '';
$prefix = $DB->get_prefix();
$database = $CFG->dbname;

if (!empty($options['info'])) {
    echo "Database version:      " . $info['description'] . "\n";
    echo "Database name:         $database\n";
    echo "Database engine:       " . $DB->get_dbengine() . "\n";
    echo "innodb_file_per_table: $filepertable\n";
    echo "innodb_file_format:    $fileformat\n";

    exit(0);

} else if (!empty($options['list'])) {
    $problem = false;
    foreach ($DB->get_tables(false) as $table) {
        $columns = $DB->get_columns($table, false);
        $size = $generator->guess_antelope_row_size($columns);
        $format = $DB->get_row_format($table);
        if ($size <= $generator::ANTELOPE_MAX_ROW_SIZE) {
            continue;
        }

        echo str_pad($prefix . $table, 32, ' ', STR_PAD_RIGHT);
        echo str_pad($format, 11, ' ', STR_PAD_RIGHT);

        if ($format === 'Compact' or $format === 'Redundant') {
            $problem = true;
            echo " (needs fixing)\n";

        } else if ($format !== 'Compressed' and $format !== 'Dynamic') {
            echo " (unknown)\n";

        } else {
            echo "\n";
        }
    }

    if ($problem) {
        exit(1);
    }
    exit(0);

} else if (!empty($options['fix'])) {
    $fixtables = array();
    foreach ($DB->get_tables(false) as $table) {
        $columns = $DB->get_columns($table, false);
        $size = $generator->guess_antelope_row_size($columns);
        $format = $DB->get_row_format($table);
        if ($size <= $generator::ANTELOPE_MAX_ROW_SIZE) {
            continue;
        }
        if ($format === 'Compact' or $format === 'Redundant') {
            $fixtables[$table] = $table;
        }
    }

    if (!$fixtables) {
        echo "No changes necessary\n";
        exit(0);
    }

    if ($filepertable !== 'ON') {
        try {
            $DB->execute("SET GLOBAL innodb_file_per_table=1");
        } catch (dml_exception $e) {
            echo "Cannot enable GLOBAL innodb_file_per_table setting, use --showsql option and execute the statements manually.";
            throw $e;
        }
    }
    if ($fileformat !== 'Barracuda') {
        try {
            $DB->execute("SET GLOBAL innodb_file_format=Barracuda");
        } catch (dml_exception $e) {
            echo "Cannot change GLOBAL innodb_file_format setting, use --showsql option and execute the statements manually.";
            throw $e;
        }
    }

    if (!$DB->is_compressed_row_format_supported(false)) {
        echo "MySQL server is not compatible with compressed row format.";
        exit(1);
    }

    foreach ($fixtables as $table) {
        $DB->change_database_structure("ALTER TABLE {$prefix}$table ROW_FORMAT=Compressed");
        echo str_pad($prefix . $table, 32, ' ', STR_PAD_RIGHT) . " ... Compressed\n";
    }

    exit(0);

} else if (!empty($options['showsql'])) {
    $fixtables = array();

    foreach ($DB->get_tables(false) as $table) {
        $columns = $DB->get_columns($table, false);
        $size = $generator->guess_antelope_row_size($columns);
        $format = $DB->get_row_format($table);
        if ($size <= $generator::ANTELOPE_MAX_ROW_SIZE) {
            continue;
        }
        if ($format === 'Compact' or $format === 'Redundant') {
            $fixtables[$table] = $table;
        }
    }
    if (!$fixtables) {
        echo "No changes necessary\n";
        exit(0);
    }

    echo "Copy the following SQL statements and execute them using account with SUPER privilege:\n\n";
    echo "USE $database;\n";
    echo "SET SESSION sql_mode=STRICT_ALL_TABLES;\n";
    echo "SET GLOBAL innodb_file_per_table=1;\n";
    echo "SET GLOBAL innodb_file_format=Barracuda;\n";
    foreach ($fixtables as $table) {
        echo "ALTER TABLE {$prefix}$table ROW_FORMAT=Compressed;\n";
    }
    echo "\n";
    exit(0);

} else {
    echo $help;
    die;
}
Back to Top