Błąd
Próba usunięcia krotek zawierających nieprawidłowe znaczniki czasu za pomocą
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';
kończy się w
ERROR: attempted to delete invisible tuple
Istnieje lista mailingowa z 2009 roku omawiająca dokładnie ten sam komunikat o błędzie, w którym OP to naprawił, ale nie znajduję wyjaśnienia, jak to zrobił ani co mogło doprowadzić do tego błędu.
Jestem bezradny z powodu braku trafień w Google i mojej ograniczonej wiedzy o PostgreSQL.
Co doprowadziło do korupcji
Miałem serwer PostgreSQL 9.5.5 ( ~ 4 TB danych, wszystkie ustawienia domyślne, z wyjątkiem zwiększonych limitów pamięci ) działający na Debianie 8, kiedy jądro systemu operacyjnego spanikowało - prawdopodobnie podczas przebudowy / dev / md1, gdzie zlokalizowano swap. Wcześniej PostgreSQL zjadł prawie całe miejsce na dysku za pomocą pliku dziennika o pojemności 400 GB. System operacyjny nigdy nie uruchomił się ponownie, sprawdzanie dysku przebiegło poprawnie, więc uruchomiłem system z płyty LiveCD i na wszelki wypadek wykonałem kopię zapasową każdego urządzenia blokowego na obrazy. Pomyślnie przebudowałem katalog / z / dev / md2, fsck pokazał czysty system plików i utworzyłem kopię zapasową folderu PGDATA na zewnętrznym dysku twardym.
Co zrobiłem, aby spróbować odzyskać
Po sformatowaniu urządzeń MD i ponownej instalacji systemu operacyjnego wraz ze świeżym postgresql-9.5 zatrzymałem serwer PostgreSQL, przeniosłem folder PGDATA do użytkownika postgres i uruchomiłem serwer - wszystko wydawało się w porządku, nie było błędów.
Jak tylko zacząłem pg_dumpall
, to umarło
Error message from server: ERROR: timestamp out of range
Oczywiście próbowałem usunąć krotki, ale w końcu ciągle pojawiał się ten sam invisible tuple
błąd.
Rzeczy, których próbowałem
Po pierwsze, usuwanie zapytań nie powiodło się z powodu uszkodzonych stron, więc ustawiłem następujące ustawienia:
zero_damaged_pages = on
ignore_system_indexes = on
enable_indexscan = off
enable_bitmapscan = off
enable_indexonlyscan = off
Teraz zauważyłem, że kiedy ponownie uruchamiam te same zapytania, serwer ciągle zeruje te same strony, nie jestem pewien, co to znaczy:
invalid page in block 92800 of relation base/16385/16443; zeroing out page
Próbowałem wykonać następujące czynności w nieokreślonej kolejności:
pg_resetxlog -D $PGDATA
wykonał swoją pracę bez żadnych błędów i komunikatów- Usunięto wszystkie indeksy, w tym ograniczenia klucza
CREATE TABLE aaa AS (SELECT * FROM comments);
prowadzi sięSegmentation fault
naheap_deform_tuple (tuple=tuple@entry=0x7f0d1be29b08, tupleDesc=tupleDesc@entry=0x7f0d1a35abe0, values=values@entry=0x7ffd57a5beb0, isnull=isnull@entry=0x7ffd57a65af0 "\001\001")
Jest odtwarzalny i pozostawia zrzut pamięci około 9 GB.SELECT COUNT(*) from comments;
wolnoVACUUM comments;
wykonać, ta sama sztuczka nie działa na innych stołach.SELECT COUNT(*) from photos;
aVACUUM photos;
teraz umieraERROR: MultiXactId 302740528 has not been created yet -- apparent wraparound
- ten nawiedza każdy stół, na którym nie pojawiają się inne błędy.
Myśli
DB był wbijany przez wiele ( prawdopodobnie zduplikowanych ) zapisów zDB robił,ON CONFLICT
klauzuląVACUUM
kiedy wystąpiła panika jądra, wierzę, że to, co z niego zostało, powoduje problemynonexistent MultiXactIds
iinvisible tuple
- Dane były gromadzone za pomocą robota przez ponad 2 lata i nie mam nic przeciwko utracie części z nich
- Teraz robię kopie zapasowe
- Nie było żadnych ograniczeń relacyjnych między tabelami ani żadnych wyzwalaczy
Oto dane wyjściowe pg_controldata:
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
Aktualizacje
- ( 9 grudnia 2016 r. ) Czytając o nieistniejącym MultiXactIds , przypomniałem sobie, że moja baza danych nie była obciążona operacyjnie w chwili awarii, ale przetwarzała ręczne
VACUUM
żądanie. Przeniosłem serwery i roboty indeksujące do trybu offline, gdy zdałem sobie sprawę, że na dyskach pozostało tylko 3% miejsca. Powinienem był sprawdzić, czy nie ma/var/log
dużych plików, ale przez pomyłkę obwiniłem PostgreSQL i próbowałemVACUUM FULL
, ale okazało się, że został przerwany z powodu małej ilości miejsca na urządzeniu. Więc zacząłem zwykłe VACUUM i zostawiłem to przy tym. - ( 14 grudnia 2016 r. ) Pobrałem 9,5 gałąź źródeł PostgreSQL z Github, skomentowałem bloki w heapam.c i multixact.c i skompilowałem go z nadzieją, że nie wyrzuci tych błędów. Ale serwer nie chce się uruchomić, ponieważ musiał być skonfigurowany z tymi samymi flagami, co te, które miałem z APT. Było około 47 flag, z których każda wymagała zależności o nieoczywistej nazwie, więc zrezygnowałem z tego pomysłu.
( 16 grudnia 2016 r. ) Znalazłem sposób na pozbycie się krotek z nieprawidłowymi znacznikami czasu poprzez wyzerowanie odpowiednich stron. Najpierw ustawiłem następujące opcje w
psql
:\set FETCH_COUNT 1 \pset pager off
To robię
SELECT ctid, * FROM comments;
. W ten sposób wypluwactid
złą krotkę przed zakończeniem zapytania. Następnie przechodzę do wypełniania tej strony zerami:dd if=/dev/zero of=/var/lib/postgresql/9.5/main/base/16385/16443 bs=8K seek=92803 count=1 conv=notrunc
Ale każda strona, wyzerowana w ten sposób, łamie poprzednią stronę, w wyniku czego strona16442
ma krotkę z niepoprawnym znacznikiem czasu. Nie jestem pewien, co robię źle tutaj.( 16 grudnia 2016 r. ) Próba
pg_dump -Fc --table photos vw > photos.bak
powoduje błąd segmentacji po napisaniu 1,3 GB ( z prawdopodobnie 800 GB ). Oto dziennik serwera: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
Oto krótki ślad stosu:
#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)
Nie mam pojęcia, jak to obejść.
( 29 grudnia 2016 r. ) Napisałem narzędzie, które robi to
SELECT * FROM tablename LIMIT 10000 OFFSET 0
, zwiększając przesunięcie i zawężając wokół martwych krotek i pomyślnie powielając dane na mojej lokalnej maszynie, z wyjątkiem krotek ( mam nadzieję, że jedyne ) ręcznie uszkodziłem. Ma także poczekać, aż serwer uruchomi się ponownie. Jednak na macierzy RAID nie miałem wystarczającej ilości miejsca i utworzyłem przestrzeń tabelslowdisk
na dysku twardym o pojemności 8 TB. Kiedy próbujęCREATE DATABASE vwslow WITH TABLESPACE slowdisk
, nie robi to z błędami: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;
Ręczne
CHECKPOINT
spowodowało te same błędy.Ponowne uruchomienie serwera sprawiło, że błąd punktu kontrolnego zniknął i pozwolił mi uruchomić moje narzędzie. Odpowie na moje pytanie i opublikuje kod, jeśli zadziała.
Odpowiedzi:
Udało mi się zautomatyzować proces odzyskiwania
SELECT
iINSERT INTO
pomijanie zakresów i oczekiwanie na awarię serwera. Najpierw zakodowałem go w węźle - zgrał nieuszkodzone danecomments
i nadal trwa.Wczoraj zdecydowałem się wypróbować Golang, a oto repozytorium z kodem Go: https://github.com/kaivi/pg_ripper Niedługo go zaktualizuję, aby naprawdę działał wokół złych krotek, a nie po prostu rezygnuje z całości zakres zawierający jeden.
źródło