L'erreur
Essayer de supprimer des tuples contenant des horodatages non valides avec
DELETE FROM comments WHERE date > '1 Jan 9999' OR date < '1 Jan 2000' OR date_found > '1 Jan 9999' OR date_found < '1 Jan 2000';
fini dans
ERROR: attempted to delete invisible tuple
Il y a une liste de diffusion de 2009 discutant exactement du même message d'erreur, où OP l'a corrigé, mais je ne trouve aucune explication sur la façon dont il l'a fait ou sur ce qui aurait pu conduire à cette erreur.
Je suis impuissant en raison du manque de hits sur Google et de ma connaissance limitée de PostgreSQL.
Ce qui a conduit à la corruption
J'ai eu un serveur PostgreSQL 9.5.5 ( ~ 4 To de données, tous les paramètres par défaut, à l'exception des limites de mémoire augmentées ) fonctionnant sur Debian 8, lorsque le noyau du système d'exploitation a paniqué - probablement lors de la reconstruction / dev / md1 où le swap était situé. Avant cela, PostgreSQL a consommé presque tout l'espace disque avec un fichier journal de 400 Go. Le système d'exploitation n'a plus jamais redémarré, les vérifications de disque étaient OK, j'ai donc démarré à partir d'un LiveCD et sauvegardé chaque périphérique de bloc sur des images, juste au cas où. J'ai réussi à reconstruire le répertoire / à partir de / dev / md2, fsck a montré un système de fichiers propre et j'ai sauvegardé le dossier PGDATA sur un disque dur externe.
Ce que j'ai fait pour tenter de récupérer
Après avoir formaté les périphériques md et réinstallé le système d'exploitation avec un nouveau postgresql-9.5, j'ai arrêté le serveur PostgreSQL, déplacé et tronqué le dossier PGDATA pour l'utilisateur de postgres et démarré le serveur - tout semblait bien, il n'y avait pas d'erreurs.
Dès que j'ai commencé pg_dumpall
, il est mort avec
Error message from server: ERROR: timestamp out of range
J'ai naturellement essayé de supprimer les tuples incriminés, pour finir avec la même invisible tuple
erreur encore et encore.
Ce que j'ai essayé
Tout d'abord, les requêtes DELETE ont échoué en raison de pages endommagées, j'ai donc défini les paramètres suivants:
zero_damaged_pages = on
ignore_system_indexes = on
enable_indexscan = off
enable_bitmapscan = off
enable_indexonlyscan = off
Maintenant, j'ai remarqué que lorsque j'exécute à nouveau les mêmes requêtes, le serveur remet à zéro les mêmes pages encore et encore, je ne sais pas ce que cela signifie:
invalid page in block 92800 of relation base/16385/16443; zeroing out page
J'ai essayé de suivre dans un ordre non défini:
pg_resetxlog -D $PGDATA
a fait son travail sans erreurs ni messages- Supprimé tous les index, y compris les contraintes pkey
CREATE TABLE aaa AS (SELECT * FROM comments);
conduit àSegmentation fault
leheap_deform_tuple (tuple=tuple@entry=0x7f0d1be29b08, tupleDesc=tupleDesc@entry=0x7f0d1a35abe0, values=values@entry=0x7ffd57a5beb0, isnull=isnull@entry=0x7ffd57a65af0 "\001\001")
Il est reproductible et laisse un vidage de mémoire de ~ 9 Go.SELECT COUNT(*) from comments;
autoriséVACUUM comments;
à terminer, la même astuce ne fonctionne pas sur les autres tables.SELECT COUNT(*) from photos;
etVACUUM photos;
meurt maintenant avecERROR: MultiXactId 302740528 has not been created yet -- apparent wraparound
- celui-ci hante chaque table, où d'autres erreurs n'apparaissent plus.
Pensées
DB était martelé par de nombreuses écritures ( peut-être en double ) avec laDB faisait uneON CONFLICT
clauseVACUUM
lorsque la panique du noyau s'est produite, je crois que c'est ce qui en reste qui cause des problèmes avecnonexistent MultiXactIds
etinvisible tuple
- Les données ont été collectées avec le robot sur une période de 2 ans et plus, et je suis tout à fait d'accord pour en perdre une partie
- Maintenant je fais des sauvegardes
- Il n'y avait aucune contrainte relationnelle entre les tables ni aucun déclencheur
Voici la sortie de pg_controldata dès maintenant:
pg_control version number: 942
Catalog version number: 201510051
Database system identifier: 6330224129664261958
Database cluster state: in production
pg_control last modified: Thu 08 Dec 2016 01:06:22 AM EET
Latest checkpoint location: 1562/8F9F8A8
Prior checkpoint location: 1562/8F7F460
Latest checkpoint's REDO location: 1562/8F9F8A8
Latest checkpoint's REDO WAL file: 000000010000156200000008
Latest checkpoint's TimeLineID: 1
Latest checkpoint's PrevTimeLineID: 1
Latest checkpoint's full_page_writes: on
Latest checkpoint's NextXID: 0/40781255
Latest checkpoint's NextOID: 67798231
Latest checkpoint's NextMultiXactId: 1
Latest checkpoint's NextMultiOffset: 0
Latest checkpoint's oldestXID: 615
Latest checkpoint's oldestXID's DB: 1
Latest checkpoint's oldestActiveXID: 0
Latest checkpoint's oldestMultiXid: 1
Latest checkpoint's oldestMulti's DB: 1
Latest checkpoint's oldestCommitTsXid:0
Latest checkpoint's newestCommitTsXid:0
Time of latest checkpoint: Thu 08 Dec 2016 01:06:22 AM EET
Fake LSN counter for unlogged rels: 0/1
Minimum recovery ending location: 0/0
Min recovery ending loc's timeline: 0
Backup start location: 0/0
Backup end location: 0/0
End-of-backup record required: no
wal_level setting: minimal
wal_log_hints setting: off
max_connections setting: 100
max_worker_processes setting: 8
max_prepared_xacts setting: 0
max_locks_per_xact setting: 64
track_commit_timestamp setting: off
Maximum data alignment: 8
Database block size: 8192
Blocks per segment of large relation: 131072
WAL block size: 8192
Bytes per WAL segment: 16777216
Maximum length of identifiers: 64
Maximum columns in an index: 32
Maximum size of a TOAST chunk: 1996
Size of a large-object chunk: 2048
Date/time type storage: 64-bit integers
Float4 argument passing: by value
Float8 argument passing: by value
Data page checksum version: 0
Mises à jour
- ( 9 décembre 2016 ) En lisant sur MultiXactIds inexistant , je me suis souvenu que ma base de données n'était pas sous charge opérationnelle au moment de l'accident, mais qu'elle traitait une
VACUUM
demande manuelle . J'ai mis les serveurs Web et les robots d'exploration hors ligne après avoir réalisé qu'il ne restait que 3% d'espace sur les disques. J'aurais dû vérifier les/var/log
fichiers volumineux, mais j'ai blâmé PostgreSQL par erreur et j'ai essayéVACUUM FULL
de le trouver avorté en raison du peu d'espace restant sur l'appareil. J'ai donc commencé VACUUM ordinaire et en reste là. - ( 14 décembre 2016 ) A téléchargé une branche 9.5 des sources PostgreSQL depuis Github, a commenté les blocs dans heapam.c et multixact.c et l'a compilé en espérant qu'il ne lèvera pas ces erreurs. Mais le serveur ne démarrait pas, car il devait être configuré avec les mêmes drapeaux que celui utilisé par APT. Il y avait environ 47 drapeaux, chacun nécessitant une dépendance avec un nom non évident, alors j'ai abandonné cette idée.
( 16 décembre 2016 ) J'ai trouvé un moyen de me débarrasser des tuples avec des horodatages invalides en remettant à zéro les pages pertinentes. J'ai d'abord défini les options suivantes dans
psql
:\set FETCH_COUNT 1 \pset pager off
Je fais alors
SELECT ctid, * FROM comments;
. De cette façon, il recrachectid
un mauvais tuple avant la fin de la requête. Je procède ensuite à remplir cette page avec des zéros:dd if=/dev/zero of=/var/lib/postgresql/9.5/main/base/16385/16443 bs=8K seek=92803 count=1 conv=notrunc
Mais chaque page, mise à zéro de cette façon, rompt la page précédente, ce qui donne à la page16442
un tuple avec un horodatage non valide. Je ne sais pas ce que je fais mal ici.( 16 décembre 2016 ) Tentative de
pg_dump -Fc --table photos vw > photos.bak
résultats en erreur de segmentation après 1,3 Go ( sur probablement 800 Go ) écrits. Voici le journal du serveur:2016-12-16 18:48:05 EET [19337-2] LOG: server process (PID 29088) was terminated by signal 11: Segmentation fault 2016-12-16 18:48:05 EET [19337-3] DETAIL: Failed process was running: COPY public.photos (id, owner_id, width, height, text, date, link, thumb, album_id, time_found, user_id, lat, long) TO stdout; 2016-12-16 18:48:05 EET [19337-4] LOG: terminating any other active server processes 2016-12-16 18:48:05 EET [19342-2] WARNING: terminating connection because of crash of another server process 2016-12-16 18:48:05 EET [19342-3] DETAIL: The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory. 2016-12-16 18:48:05 EET [19342-4] HINT: In a moment you should be able to reconnect to the database and repeat your command. 2016-12-16 18:48:05 EET [19337-5] LOG: all server processes terminated; reinitializing 2016-12-16 18:48:06 EET [29135-1] LOG: database system was interrupted; last known up at 2016-12-14 22:58:59 EET 2016-12-16 18:48:07 EET [29135-2] LOG: database system was not properly shut down; automatic recovery in progress 2016-12-16 18:48:07 EET [29135-3] LOG: invalid record length at 1562/A302F878 2016-12-16 18:48:07 EET [29135-4] LOG: redo is not required 2016-12-16 18:48:07 EET [29135-5] LOG: MultiXact member wraparound protections are now enabled 2016-12-16 18:48:07 EET [19337-6] LOG: database system is ready to accept connections 2016-12-16 18:48:07 EET [29139-1] LOG: autovacuum launcher started
Voici un bref stacktrace:
#0 pglz_decompress (source=source@entry=0x7fbfb6b99b13 "32;00/0ag4d/Jnz\027QI\003Jh3A.jpg", slen=<optimized out>, dest=dest@entry=0x7fbf74a0b044 "", rawsize=926905132) #1 0x00007fc1bf120c12 in toast_decompress_datum (attr=0x7fbfb6b99b0b) #2 0x00007fc1bf423c83 in text_to_cstring (t=0x7fbfb6b99b0b)
Je ne sais pas comment contourner cela.
( 29 décembre 2016 ) J'ai écrit un utilitaire qui
SELECT * FROM tablename LIMIT 10000 OFFSET 0
incrémente le décalage et se rétrécit autour des tuples morts, et il a réussi à dupliquer les données sur ma machine locale à l'exception des tuples ( j'espère les seuls ) que j'ai corrompus manuellement. Il est également censé attendre si le serveur redémarre. Cependant, je n'avais pas assez d'espace sur mon RAID et j'ai créé un espaceslowdisk
de table sur un disque dur de 8 To. Lorsque j'essaie de le faireCREATE DATABASE vwslow WITH TABLESPACE slowdisk
, il ne le fera pas avec des erreurs:2016-12-29 02:34:13 EET [29983-1] LOG: request to flush past end of generated WAL; request 950412DE/114D59, currpos 1562/A3030C70 2016-12-29 02:34:13 EET [29983-2] CONTEXT: writing block 58368001 of relation base/16385/16473 2016-12-29 02:34:13 EET [29983-3] ERROR: xlog flush request 950412DE/114D59 is not satisfied --- flushed only to 1562/A3030C70 2016-12-29 02:34:13 EET [29983-4] CONTEXT: writing block 58368001 of relation base/16385/16473 2016-12-29 02:34:13 EET [30005-44212] postgres@vw ERROR: checkpoint request failed 2016-12-29 02:34:13 EET [30005-44213] postgres@vw HINT: Consult recent messages in the server log for details. 2016-12-29 02:34:13 EET [30005-44214] postgres@vw STATEMENT: CREATE DATABASE vwslow WITH TABLESPACE slowdisk;
Le manuel a
CHECKPOINT
entraîné les mêmes erreurs.Un redémarrage du serveur a fait disparaître l'erreur de point de contrôle et m'a permis d'exécuter mon outil. Répondra à ma question et publiera le code si cela fonctionne.