# Comprendre la BDD Etherpad ## Se connecter à la base de données ### Sur `pica01-test` ``` docker exec -it etherpad-db bash mysql -u etherpad etherpad-lite -sN --default-character-set=utf8 -p ``` Le mot de passe est normalement `password2`, il est défini [ici](https://gitlab.utc.fr/picasoft/projets/services/etherpad-yearly/-/blob/master/secrets/etherpad-db.secrets.example) (MYSQL_PASSWORD) ### Sur la prod **À ne faire que si c'est absolument nécessaire** #### pad.picasoft.net (`pica02`) Mêmes étapes que précédemment, mais le mot de passe est dans `/DATA/docker/services/etherpad/secrets` #### week.pad.picasoft.net (`pica01`) ``` docker exec -it weekpad-db bash psql -U weekpad -d weekpad ``` Sur ce conteneur, vous êtes connecté direct en tant que root, donc `psql` vous demandera pas de mot de passe ## Structure de la BDD La structure est hyper simple. Dans la BDD `etherpad-lite`, il y a juste une table `store` avec 2 colonnes: `key` et `value`. ``` mysql> show databases; +--------------------+ | Database | +--------------------+ | etherpad-lite | | information_schema | +--------------------+ 2 rows in set (0.01 sec) mysql> show tables; +-------------------------+ | Tables_in_etherpad-lite | +-------------------------+ | store | +-------------------------+ 1 row in set (0.00 sec) mysql> describe store; +-------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+--------------+------+-----+---------+-------+ | key | varchar(100) | NO | PRI | NULL | | | value | longtext | NO | | NULL | | +-------+--------------+------+-----+---------+-------+ 2 rows in set (0.07 sec) ``` ## Structure des clés Les clés concernant les pads commencent par `pad:`. Vous pouvez avoir un aperçu avec ```sql select s.key from store s where s.key like "pad:%" limit 20; ``` Le `%` désigne n'importe quelle suite de caractères. **N'utilisez pas plusieurs `%` dans une même requête !** Cela serait à l'origine d'un nombre astronomique de possibilités, vu la taille de la BDD Etherpad, et donc un temps de calcul astronomique lui aussi. Pour un pad nommé `monpad`, il y a _normalement_: * une clé `pad:monpad` * une ou plusieurs clés `pad:monpad:revs:i` où `i` est compris entre 0 et le nombre de révisions `pad:monpad` contient **la dernière version** Si le pad vient d'être crée, il y a juste `pad:monpad` et `pad:monpad:revs:0` ## Comprendre le format des révisions J'ai crée un nouveau pad sur l'instance de test, nommé `newpad`, puis j'ai ajouté le texte ` de test` (Ctrl-V) juste après `Bienvenue sur Picapad`. Ceci a généré la révision suivante (et mis à jour `pad:newpad`) ``` mysql> select s.value from store s where s.key="pad:newpad:revs:1"; value {"changeset":"Z:18h>8=l*0+8$ de test","meta":{"author":"a.jkPhNoJhljvlAjjq","timestamp":1585588719641}} ``` Mais qu'est ce signifie `Z:18h>8=l*0+8$ de test` ? Documentation officielle: [Changeset Library](https://github.com/ether/etherpad-lite/blob/develop/doc/api/changeset_library.md) Pour comprendre que contient cette mystérieuse chaine de caractères, on va sur pad.test.picasoft.net et on ouvre une console web. {{ :technique:adminsys:etherpad:changeset_screenshot.png?direct |}} La chaine `Z:18h>8=l*0+8$ de test` signifie donc quelque chose comme > Pour passer de la révision 0 à la révision 1, on agrandit le document de 1601 à 1609 caractères. On se place au début. On parcours 21 caractères qui restent inchangés. Puis on ajoute les 8 caractères suivants: " de test" ## Quelques tests pour simuler une BDD corrompue Ces tests pourraient aider à comprendre pourquoi des pads en production ne fonctionnent pas ### Test 1: révision manquante Sur l'instance de test, on crée un pad nommé `newpad2`, puis on fait quelques modifications. Depuis la console mysql, on devrait avoir quelque chose comme: ```sql mysql> select s.key from store s where s.key like "pad:newpad2%" limit 15; pad2readonly:newpad2 pad:newpad2 pad:newpad2:revs:0 pad:newpad2:revs:1 pad:newpad2:revs:2 ``` On vérifie que tout fonctionne bien, puis on efface la révision 1: ```sql delete from store s where s.key="pad:newpad2:revs:1"; ``` On retourne sur le pad. Résultat: tout fonctionne toujours bien. On éteint puis on lance à nouveau `etherpad_app`. Résultat: le pad s'affiche toujours correctement, mais l'historique ne fonctionne plus ## Test 2: JSON corrompu Sur l'instance de test, on crée un pad nommé `newpad3`, puis on fait quelques modifications. On affiche le contenu de `pad:newpad3`: ```sql mysql> select s.value from store s where s.key="pad:newpad3"; {"atext":{"text":"Bienvenue sur Picapad de test, ... "savedRevisions":[]} ``` On va mettre à jour la valeur de cette clé avec du JSON invalide. Pour cela, on copie-colle le retour de la commande précédente sur un éditeur de texte, on remplace les `'` par `\'` puis on efface la première `{`. On met à jour le champ: ```sql mysql> update store set value='' where store.key='pad:newpad3'; ``` On redémarre `etherpad-app`. Résultat: le pad semble prendre du temps à charger, mais après quelques minutes, on tombe sur un `Bad Gateway`. Si on regarde les logs récents (`docker logs --since="5m" etherpad-app`), on retrouve une erreur du type ``` [2020-03-30 23:11:31.773] [ERROR] console - JSON-PROBLEM: ``` ## Faire un dump manuel de la BDD Le script nécessaire est préparé par le conteneur `db-backup` ([plus d'infos](https://gitlab.utc.fr/picasoft/projets/services/db-backup)). Il suffit de l'exécuter: ```bash amaldona@pica02:/DATA/BACKUP/etherpad$ docker exec -it db-backup bash root@08cbba05d797:/# ./etherpad-backup.sh ``` ## Réparer la base de données suite à un incident 2020-03-23: Les backups de la BDD Etherpad cessent de fonctionner 2020-03-30: On s'en rend compte suite à [l'incident](todo). Le dump de la BDD échoue: ``` root@08cbba05d797:/# ./etherpad-backup.sh => etherpad: Backup started: 2020.03.30.140224.sql mysqldump: Error 1194: Table 'store' is marked as crashed and should be repaired when dumping table `store` at row: 8147475 etherpad: Backup failed ``` On a réparé la table avec: ```sql REPAIR TABLE store; ``` https://dev.mysql.com/doc/refman/8.0/en/repair-table.html