Skip to content

mariadb

mydumper-0.6 views dump and restore

Hi readers, i hope you are listening to the MUSE Drones Album,

The mydumper-0.6.2 (the current stable version) is not dumping views… Thankfully, the 0.9 branch (not stable at now) will… (MyDumper – Add support for all schema objects)

The question is, how to safely backup theses views (without using a beta version of mydumper) ?

I search into the myloader.c source code how the regular tables have theirs schema restored, and luckily, in the following function :

void restore_data(MYSQL *conn, char *database, char *table, const char *filename, gboolean is_schema);

we can see that the content of the schema dump file is ready and executed without special verification :

// [...]
if (!is_schema)
    mysql_query(conn, "START TRANSACTION");

while (eof == FALSE) {
    if (read_data(infile, is_compressed, data, &eof)) {
        // Search for ; in last 5 chars of line
        if (g_strrstr(&data->str[data->len >= 5 ? data->len - 5 : 0], ";\n")) {
            if (mysql_real_query(conn, data->str, data->len)) {
                g_critical("Error restoring %s.%s from file %s: %s", db ? db : database, table, filename, mysql_error(conn));
                errors++;
                return;
            }
            query_counter++;
            if (!is_schema &&(query_counter == commit_count)) {
                query_counter= 0;
                if (mysql_query(conn, "COMMIT")) {
                    g_critical("Error committing data for %s.%s: %s", db ? db : database, table, mysql_error(conn));
                    errors++;
                    return;
                }
                mysql_query(conn, "START TRANSACTION");
            }

            g_string_set_size(data, 0);
        }
    } else {
        g_critical("error reading file %s (%d)", filename, errno);
        errors++;
        return;
    }
}
if (!is_schema && mysql_query(conn, "COMMIT")) {
    g_critical("Error committing data for %s.%s from file %s: %s", db ? db : database, table, filename, mysql_error(conn));
    errors++;
}
// [...]

That mean we can generate – by any way we want – a fake schema-dump file, but with a query creating a view.

For that,  i first thought of patching mydumper.c ; but as mydumper-0.9 (not stable at now) already support this feature, i will prefer another solution.

I’ve made a modest python script which list view and generate files named database.view_name-schema.sql into the mydumper dump dir. With that, myloader will consider thoses files as regular table schema create statements.

Please note that i force a DROP VIEW IF EXISTS into the dump file…

#!/usr/bin/python2.7 -u

import MySQLdb
import os

# settings
MARIADB_USER = 'a_readonly_user'
MARIADB_PASS = 'a_good_password_MU5E_D3AD_IN7ID3_%!@'
MARIADB_HOST = '127.0.0.1'
MARIADB_PORT = 3306
MARIADB_SCKT = ''  # empty for TCP , or path if socket (host must be localhost)
MYDUMPER_DUMP_DIR = '/tmp'  # the path of the dump already done by mydumper

# connection to the MariaDB server
mariadb_connection = MySQLdb.connect(
    host=MARIADB_HOST,
    user=MARIADB_USER,
    passwd=MARIADB_PASS,
    port=MARIADB_PORT,
    unix_socket=MARIADB_SCKT,
    db='information_schema',
)

# creating cursors
views_list_cursor = mariadb_connection.cursor()
show_create_view_cursor = mariadb_connection.cursor()

# ask MariaDB for the views list
views_list_cursor.execute("SELECT `table_schema`, `table_name` FROM `tables` WHERE `table_type` = 'VIEW'")

for database, view in views_list_cursor:
    # and handle each results
    show_create_view_cursor.execute("SHOW CREATE VIEW `{}`.`{}`".format(database, view))
    view, create_view_stmt, character_set_client, collation_connection = show_create_view_cursor.fetchone()
    dump_file = os.path.join(MYDUMPER_DUMP_DIR, '{}.{}-schema.sql'.format(database, view))
    assert not os.path.exists(dump_file)
    with open(dump_file, 'w') as f:
        fwrite('DROP VIEW IF EXISTS `{}`.`{}`;'.format(database, view))
        fwrite('\n\n')
        f.write(create_view_stmt)
        f.write(';')

# release cursors and close the MariaDB connection
views_list_cursor.close()
show_create_view_cursor.close()
mariadb_connection.close()

Feel free to make it PEP8, or with better error handling. Actually, the return code will be 0 only if everything seems good.

MariaDB, plugin-load et la table mysql.plugin

Bonne journée à tous en ce début de semaine et de mois 🙂
Bonne nouvelle, le futur album #Drones de MUSE va paraître en Juin 2015 ; et un single #Psycho risque de sortir dans quelques semaines.

Le problème

Avec MariaDB <=10.0.16 ; lorsque vous utilisez des “storage engine” reposant sur des plugins (comme Spider, TokuDB) vous pouvez être confrontés à ce genre de message d’erreur dans mysqld.err lors du démarrage de mysqld :

150302 9:09:58 [Note] Plugin 'FEEDBACK' is disabled.
150302 9:09:58 [ERROR] Function 'TokuDB' already exists
150302 9:09:58 [Warning] Couldn't load plugin named 'TokuDB' with soname 'ha_tokudb.so'.
150302 9:09:58 [ERROR] Function 'TokuDB_trx' already exists
150302 9:09:58 [Warning] Couldn't load plugin named 'TokuDB_trx' with soname 'ha_tokudb.so'.
150302 9:09:58 [ERROR] Function 'TokuDB_lock_waits' already exists
150302 9:09:58 [Warning] Couldn't load plugin named 'TokuDB_lock_waits' with soname 'ha_tokudb.so'.
150302 9:09:58 [ERROR] Function 'TokuDB_locks' already exists
150302 9:09:58 [Warning] Couldn't load plugin named 'TokuDB_locks' with soname 'ha_tokudb.so'.
150302 9:09:58 [ERROR] Function 'TokuDB_file_map' already exists
150302 9:09:58 [Warning] Couldn't load plugin named 'TokuDB_file_map' with soname 'ha_tokudb.so'.
150302 9:09:58 [ERROR] Function 'TokuDB_fractal_tree_info' already exists
150302 9:09:58 [Warning] Couldn't load plugin named 'TokuDB_fractal_tree_info' with soname 'ha_tokudb.so'.
150302 9:09:58 [ERROR] Function 'TokuDB_fractal_tree_block_map' already exists
150302 9:09:58 [Warning] Couldn't load plugin named 'TokuDB_fractal_tree_block_map' with soname 'ha_tokudb.so'.

Cela est du au fait que mysqld tente une seconde fois de charger le même plugin (ici tokudb).

Fort probable, vous avez dans votre my.cnf une configuration comme :

plugin-load=ha_tokudb

La première fois que vous avez démarré mysqld avec ces instructions, et jusqu’à que MariaDB l’installe dans ses tables systèmes, rien à signaler dans le mysqld.err

Mais aussitôt que vous aurez – par exemple – instancié une table TokuDB, alors MariaDB ajoute TokuDB dans sa table mysql.plugin pour charger automatiquement l’extension au prochain chargement de mysqld (ce qui fera doublon à la configuration du my.cnf) :

MariaDB [mysql]> select * from mysql.plugin where dl = 'ha_tokudb.so';
+-------------------------------+--------------+
| name                          | dl           |
+-------------------------------+--------------+
| TokuDB                        | ha_tokudb.so |
| TokuDB_trx                    | ha_tokudb.so |
| TokuDB_lock_waits             | ha_tokudb.so |
| TokuDB_locks                  | ha_tokudb.so |
| TokuDB_file_map               | ha_tokudb.so |
| TokuDB_fractal_tree_info      | ha_tokudb.so |
| TokuDB_fractal_tree_block_map | ha_tokudb.so |
+-------------------------------+--------------+
7 rows in set (0.00 sec)

La solution court-terme

Retirer “plugin-load=ha_tokudb” de votre my.cnf

Le problème de la solution

Que se passera-t’il le jour où vous démarrerez mysqld avec un datadir complètement vide, dans le but, par exemple, de restaurer une sauvegarde ?

L’import échouera lorsque il rencontrera une table TokuDB, parce qu’il ne connaitra pas le “storage engine” (le plugin correspondant n’aura pas été chargé).

Il faudra alors soit :

  • remettre la configuration dans le my.cnf ; re-démarrer mysqld ; retirer la configuration du my.cnf ; et faire l’import de votre sauvegarde
  • penser à charger le plugin – manuellement – avant l’import – avec l’instruction suivante :
INSTALL SONAME 'ha_tokudb'

Des idées de solutions long-terme

MariaDB

MariaDB devrait accepter que my.cnf et mysql.plugin fassent référence au même plugin, et que MariaDB soit assez intelligent pour ignorer la situation, en se basant à minima sur le nom du fichier, ou un checksum du .so

MyDumper / MysqlDump

Les outils de sauvegarde (notamment ceux cités) devraient s’assurer qu’en tête des instructions qui seront exécutés pour restaurer un “backup” ; des routines soient présentes pour charger – si nécessaire – les plugins qui seront ultérieument nécessaire, notamment pour des tables et leurs “storage engine”.

 

Conclusions

J’ai poussé les idées en question auprès du support de MariaDB.

Voir aussi : https://mariadb.com/kb/en/mariadb/enabling-tokudb/