ON AN ON - Ghosts

On An On est formé par d'ex-membres du groupe Scattered : Nate Eiesland, Alissa Ricci et Ryne Estwing ont décidé d'essayer des choses qu'ils n'avaient pas l'habitude de faire avec leur ancien groupe et leur son déjà établi.

C'est avec le producteur de Broken Social Scene, Dave Newfeld, qu'ils enregistrent leur premier album, autour du morceau Ghosts :

There are spirits coming to find me
They're not stopping until it's done
I can feel them taking me over

I can see them from fifty-six miles away
But I can't hear what they're saying
They gotta believe me that I'll never forget you

Every day the ghosts are going to fly
Every way I know I'm going to try
To keep you alive, to keep you alive

Take me out into the night
It was all you didn't say, you had no fight
I was on the verge to scream
When you wouldn't scream about anything
I don't want to be your stupid fling or your magazine
That you look and turn the pages
Of someone else that you'll never love

And I was on the verge to scream
When you wouldn't scream about anything

Cela s'écoute très bien et cela va de l'avant. L'album Give In est sorti le 29 janvier 2013 chez Roll Call Records.

WordPress : résoudre le problème de la table wp_options à qui manquent une colonne Unique et une Primary Key

Chez Codeable, j'ai travaillé sur l'optimisation d'un site e-commerce propulsé par WooCommerce récemment, qui connaissait quelques problèmes de lenteur.

Sous phpMyAdmin, on trouvait également cette erreur:

Current selection does not contain a unique column

Si vous obtenez cette erreur, c'est que la structure de la table wp_options n'est pas à jour donc nous la vérifions avec wp-cli:

wp db query "DESCRIBE $(wp db prefix --allow-root)options" --allow-root

Le résultat obtenu nous montre qu'il n'y a pas de clé primaire (primary key) qui est normalement option_id et qu'il n'y a pas de restriction unique imposée sur la colonne option_name:

+--------------+---------------------+------+-----+---------+-------+
| Field        | Type                | Null | Key | Default | Extra |
+--------------+---------------------+------+-----+---------+-------+
| option_id    | bigint(20) unsigned | NO   |     | NULL    |       |
| option_name  | varchar(191)        | YES  |     | NULL    |       |
| option_value | longtext            | NO   |     | NULL    |       |
| autoload     | varchar(20)         | NO   |     | yes     |       |
+--------------+---------------------+------+-----+---------+-------+

Et c'est là que le bât blesse - voici à quoi ressemble la structure standard de la table wp-options:

+--------------+---------------------+------+-----+---------+----------------+
| Field        | Type                | Null | Key | Default | Extra          |
+--------------+---------------------+------+-----+---------+----------------+
| option_id    | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| option_name  | varchar(191)        | NO   | UNI | NULL    |                |
| option_value | longtext            | NO   |     | NULL    |                |
| autoload     | varchar(20)         | NO   | MUL | yes     |                |
+--------------+---------------------+------+-----+---------+----------------+

Ajouter la Primary Key manquante à wp_options

On ajoute à la colonne option_id la clé primaire qui lui manque:

wp db query "ALTER TABLE $(wp db prefix --allow-root)options MODIFY option_id INT AUTO_INCREMENT PRIMARY KEY;" --allow-root

Et on vérifie le résultat:

wp db query "DESCRIBE $(wp db prefix --allow-root)options" --allow-root

Ajouter la contrainte Unique qui manque à wp_options

Pour ajouter la contrainte UNIQUE à la colonne option_name, on lance:

wp db query "ALTER TABLE $(wp db prefix --allow-root)options ADD UNIQUE (option_name);" --allow-root

Là, il est possible que cela bloque, suivant ce qui se trouve dans votre table wp_options.

Résoudre le problème des doublons

Si vous obtenez une erreur comme :

ERROR 1062 (23000) at line 1: Duplicate entry 'jetpack_available_modules' for key 'option_name'

alors cela signifie qu'il existe des enregistrements option_name dupliqués, des doublons qui portent le même nom alors que chaque nom option_name devrait être unique.

On peut obtenir la liste des enregistrements option_name doublons avec cette requête:

wp db query "SELECT option_name, COUNT(*) optioncount FROM $(wp db prefix --allow-root)options GROUP BY option_name HAVING optioncount > 1 ORDER BY optioncount DESC;" --allow-root

Par ordre ascendant, voici la liste des doublons:

+---------------------------------------------+-------------+
| option_name                                 | optioncount |
+---------------------------------------------+-------------+
| jetpack_callables_sync_checksum             |       47123 |
| jetpack_sync_full_config                    |          50 |
| jetpack_sync_full_enqueue_status            |          43 |
| jpsq_sync_checkout                          |          10 |
| jetpack_sync_full__params                   |           5 |
| jetpack_sync_settings_sync_via_cron         |           4 |
| jetpack_sync_full__started                  |           4 |
+---------------------------------------------+-------------+

On peut supprimer automatiquement tous les doublons option_name de deux manières différentes, soit en utilisant la plus vieille valeuroption_id(donc la plus petite valeur d'ID), soit en utilisant la valeuroption_id la plus récente (plus grande valeur d'ID).

Garder le doublon option_name le plus ancien

Voici la requête SQL qui montre uniquement le plus ancien enregistrement (MIN) option_id pour chaque doublon de valeur option_name:

SELECT *
FROM wp options
WHERE option_id NOT IN
    (SELECT *
     FROM
       (SELECT MIN(n.option_id)
        FROM wp_options
        GROUP BY n.option_name) x)

Une fois que vous avez vérifié le résultat, on peut passer à la suppression.

Cette requête SQL garde l'enregistrement (MIN) option_id le plus ancien de tous les doublonsoption_name et supprime tous les enregistrements plus récents que la valeur trouvée:

DELETE
FROM wp options
WHERE option_id NOT IN
    (SELECT *
     FROM
       (SELECT MIN(n.option_id)
        FROM wp_options n
        GROUP BY n.option_name) x)

Voici l'équivalent wp-cli:

wp db query "DELETE FROM $(wp db prefix --allow-root)options WHERE option_id NOT IN (SELECT * FROM (SELECT MIN(n.option_id) FROM $(wp db prefix --allow-root)options n GROUP BY n.option_name) x)" --allow-root

Garder le doublon option_name le plus récent

Cette requête SQL ne montre que les enregistrements option_id les plus récents (MAX) pour tous les doublons option_name :

SELECT *
FROM wp_options
WHERE option_id NOT IN
    (SELECT *
     FROM
       (SELECT MAX(n.option_id)
        FROM wp_options n
        GROUP BY n.option_name) x)

Et voici la requête qui permet de garder les enregistrements option_id les plus récents (MAX) pour tous les doublons option_name en supprimant tous les doublons les plus anciens:

DELETE
FROM wp_options
WHERE option_id NOT IN
    (SELECT *
     FROM
       (SELECT MAX(n.option_id)
        FROM wp_options n
        GROUP BY n.option_name) x)

Voici l'équivalent wp-cli pour garder l'enregistrement option_name le plus récent:

wp db query "DELETE FROM $(wp db prefix --allow-root)options WHERE option_id NOT IN (SELECT * FROM (SELECT MAX(n.option_id) FROM $(wp db prefix --allow-root)options n GROUP BY n.option_name) x)" --allow-root

Vérifier les clés et contraintes de la table wp_options

Ajoutons de nouveau la contrainte UNIQUE sur la colonne option_name :

wp db query "ALTER TABLE $(wp db prefix --allow-root)options ADD UNIQUE (option_name);" --allow-root

Si vous n'obtenez pas d'erreur, vérifiez la table une nouvelle fois pour constater les changements:

wp db query "DESCRIBE $(wp db prefix --allow-root)options;" --allow-root

Kaboom! Votre table wp_options possède maintenant une PRIMARY KEY sur la colonne option_id et la contrainte UNIQUE sur la colonne option_name:

+--------------+---------------------+------+-----+---------+----------------+
| Field        | Type                | Null | Key | Default | Extra          |
+--------------+---------------------+------+-----+---------+----------------+
| option_id    | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| option_name  | varchar(191)        | NO   | UNI |         |                |
| option_value | longtext            | NO   |     | NULL    |                |
| autoload     | varchar(20)         | NO   |     | yes     |                |
+--------------+---------------------+------+-----+---------+----------------+

Je vous conseille de vérifier la structure de la table de temps à autre, notamment si vous constatez une prise de poids anormale en très peu de temps

MariaDB ne veut plus redémarrer : quelques solutions

Serveur dédié : installation de MariaDB 10.3 photo

Sur le serveur chinois que j'ai monté pour un de mes clients sur Codeable, le site a commencé à afficher des erreurs étranges : erreur 502 pour nginx sur certaines pages et des nombres étranges en lieu et place des données de la base de données.

Après un redémarrage des services PHP, nginx et mysql, je constate que MariaDB veut bien s'arrêter mais ne veut plus de lancer.

Voici ce que donne:

systemctl status mariadb.service

Résultat:

● mariadb.service - MariaDB database server
   Loaded: loaded (/lib/systemd/system/mariadb.service; enabled; vendor preset: enabled)
   Active: failed (Result: exit-code) since Mon 2019-04-22 18:14:22 CST; 59s ago
  Process: 721 ExecStartPost=/bin/sh -c systemctl unset-environment _WSREP_START_POSITION (code=exited, status=0/SUCCESS)
  Process: 718 ExecStartPost=/etc/mysql/debian-start (code=exited, status=0/SUCCESS)
  Process: 12274 ExecStart=/usr/sbin/mysqld $MYSQLD_OPTS $_WSREP_NEW_CLUSTER $_WSREP_START_POSITION (code=exited, status=1/FAILURE)
  Process: 12179 ExecStartPre=/bin/sh -c [ ! -e /usr/bin/galera_recovery ] && VAR= ||   VAR=`/usr/bin/galera_recovery`; [ $? -eq 0 ]   && systemctl set-environment _WSREP_START_POSITION=$VAR || exit 1 (code=exited,
  Process: 12176 ExecStartPre=/bin/sh -c systemctl unset-environment _WSREP_START_POSITION (code=exited, status=0/SUCCESS)
  Process: 12173 ExecStartPre=/usr/bin/install -m 755 -o mysql -g root -d /var/run/mysqld (code=exited, status=0/SUCCESS)
 Main PID: 12274 (code=exited, status=1/FAILURE)
   Status: "MariaDB server is down"
systemd[1]: Starting MariaDB database server…
mysqld[12274]: 2019-04-22 18:14:19 140194687476288 [Note] /usr/sbin/mysqld (mysqld 10.1.26-MariaDB-0+deb9u1) starting as process 12274 …
systemd[1]: mariadb.service: Main process exited, code=exited, status=1/FAILURE
systemd[1]: Failed to start MariaDB database server.
systemd[1]: mariadb.service: Unit entered failed state.
systemd[1]: mariadb.service: Failed with result 'exit-code'.

Bon, chou blanc. Cela ne nous donne aucune information exploitable quand à l'erreur qui empêche le démarrage du service de base de données.

On regarde ensuite ce que nous donnent les logs de MariaDB:

tail -f /var/log/mysql/error.log

Résultat:

2019-04-22 18:14:19 140194687476288 [Note] InnoDB: Completed initialization of buffer pool
2019-04-22 18:14:19 140194687476288 [Note] InnoDB: Highest supported file format is Barracuda.
2019-04-22 18:14:19 140194687476288 [Note] InnoDB: 128 rollback segment(s) are active.
2019-04-22 18:14:19 140194687476288 [Note] InnoDB: Waiting for purge to start
2019-04-22 18:14:19 140194687476288 [Note] InnoDB:  Percona XtraDB (http://www.percona.com) 5.6.36-82.1 started; log sequence number 11397472969
2019-04-22 18:14:19 140194687476288 [Note] Plugin 'FEEDBACK' is disabled.
2019-04-22 18:14:19 140194687476288 [ERROR] mysqld: Can't change size of file (Errcode: 28 "No space left on device")
2019-04-22 18:14:19 140194687476288 [ERROR] Can't init tc log
2019-04-22 18:14:19 140194687476288 [ERROR] Aborting

Là, c'est beaucoup plus intéressant. Visiblement, deux erreurs majeures sont à l'origine du non-démarrage du service:

  • il n'y a plus d'espace disponible sur le disque dur du serveur,
  • le fichier /var/lib/mysql/tc.log ne peut pas être initialisé.

Après un petit df, il s'avère que le client a installé un plugin de sauvegarde qui a littéralement saturé tout l'espace disponible.

Après un petit ménage, il ne reste plus qu'à gérer la seconde erreur, Can't init tc log.

Le fichier /var/lib/mysql/tc.log peut parfois souffrir d'un problème de permission. Dans le cas du client, on l'archive par précaution:

mv /var/lib/mysql/tc.log /var/lib/mysql/tc_bakup.log

Puis on relance le serveur MariaDB:

service mysql start

On vérifie le statut du service:

service mysql status

qui nous retourne:

service mysql status
● mariadb.service - MariaDB database server
   Loaded: loaded (/lib/systemd/system/mariadb.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2019-04-22 18:17:22 CST; 1h 37min ago
  Process: 12467 ExecStartPost=/bin/sh -c systemctl unset-environment _WSREP_START_POSITION (code=exited, status=0/SUCCESS)
  Process: 12464 ExecStartPost=/etc/mysql/debian-start (code=exited, status=0/SUCCESS)
  Process: 12340 ExecStartPre=/bin/sh -c [ ! -e /usr/bin/galera_recovery ] && VAR= ||   VAR=`/usr/bin/galera_recovery`; [ $? -eq 0 ]   && systemctl set-environment _WSREP_START_POSITION=$VAR || exit 1 (code=exited,
  Process: 12337 ExecStartPre=/bin/sh -c systemctl unset-environment _WSREP_START_POSITION (code=exited, status=0/SUCCESS)
  Process: 12334 ExecStartPre=/usr/bin/install -m 755 -o mysql -g root -d /var/run/mysqld (code=exited, status=0/SUCCESS)
 Main PID: 12437 (mysqld)
   Status: "Taking your SQL requests now..."
    Tasks: 29 (limit: 4915)
   CGroup: /system.slice/mariadb.service
           └─12437 /usr/sbin/mysqld

Apr 22 18:17:20 iZuf6aj6jz83uxa0jgbgcrZ systemd[1]: Starting MariaDB database server...
Apr 22 18:17:21 iZuf6aj6jz83uxa0jgbgcrZ mysqld[12437]: 2019-04-22 18:17:21 139940495544896 [Note] /usr/sbin/mysqld (mysqld 10.1.26-MariaDB-0+deb9u1) starting as process 12437 ...
Apr 22 18:17:22 iZuf6aj6jz83uxa0jgbgcrZ systemd[1]: Started MariaDB database server.

A noter que l'erreur 502 de nginx n'était pas due à une mauvaise condiguration du server block mais bien d'un manque d'espace disque. C'est important à vérifier, avant de se lancer dans la dissection du fichier de configuration d'nginx (qui n'aurait pas réglé le problème dans ce cas précis).

Pin It on Pinterest

Spelling error report

The following text will be sent to our editors: