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 ne liste de diffusion de 2009 discutant exactement le 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.
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 de/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 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.
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 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 erreur invisible Tuple
Encore et encore.
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 messagesCREATE TABLE aaa AS (SELECT * FROM comments);
conduit à Segmentation fault
sur
heap_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 mémoire de ~ 9 Go.
SELECT COUNT(*) from comments;
a permis à VACUUM comments;
de se terminer, la même astuce ne fonctionne pas sur les autres tables.SELECT COUNT(*) from photos;
et VACUUM photos;
meurt maintenant avec ERROR: MultiXactId 302740528 has not been created yet -- apparent wraparound
- celui-ci hante chaque table, où les autres erreurs n'apparaissent plus.ON CONFLICT
VACUUM
lorsque la panique du noyau s'est produite, je crois que c'est ce qui reste qui cause des problèmes avec nonexistent MultiXactIds
Et invisible Tuple
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
VACUUM
. 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 /var/log
Pour les fichiers volumineux, mais j'ai blâmé PostgreSQL par erreur et essayé VACUUM FULL
, Seulement pour le trouver abandonné en raison du peu d'espace restant sur l'appareil. J'ai donc commencé VACUUM ordinaire et en reste là.( 16 décembre 2016 ) J'ai trouvé un moyen de se 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 ensuite SELECT ctid, * FROM comments;
. De cette façon, il crache le ctid
d'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, brise la page précédente, ce qui fait que la page 16442
A maintenant un tuple avec un horodatage invalide. Je ne sais pas ce que je fais mal ici.
( 16 décembre 2016 ) La tentative de pg_dump -Fc --table photos vw > photos.bak
Entraîne une erreur de segmentation après 1,3 Go ( sur probablement 800 Go ) écrit. 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 fait SELECT * FROM tablename LIMIT 10000 OFFSET 0
, Incrémentant le décalage et se rétrécissant autour des tuples morts, et il a avec succès les données dupliquées sur ma machine locale à l'exception des tuples ( J'espère que les seules ) que j'ai corrompues 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 espace de table slowdisk
sur un disque dur de 8 To. Lorsque j'essaie de CREATE 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 CHECKPOINT
a provoqué 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.
Eh bien, j'ai réussi à automatiser le processus de récupération de SELECT
et INSERT INTO
, ignorant les plages et attendant que le serveur tombe en panne. Je l'ai d'abord codé en Node - il a extrait des données intactes de comments
, et continue toujours.
Hier, j'ai décidé d'essayer Golang, et voici un dépôt avec le code Go: https://github.com/kaivi/pg_ripper Je vais le mettre à jour bientôt afin qu'il fonctionne vraiment autour des mauvais tuples, et ne renonce pas seulement à toute la gamme en contenant un.