Помилка
Спроба видалити кортежі, що містять недійсні часові позначки
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';
закінчується в
ERROR: attempted to delete invisible tuple
Існує список розсилки з 2009 року, в якому обговорюється саме таке повідомлення про помилку, де це було виправлено ОП, але я не знаходжу пояснення того, як він це зробив або що може призвести до цієї помилки.
Я безпорадний через відсутність звернень до Google і через моє обмежене знання PostgreSQL.
Що призвело до корупції
У мене був сервер PostgreSQL 9.5.5 ( ~ 4TB, усі параметри за замовчуванням, за винятком збільшених лімітів пам'яті ), який працює на Debian 8, коли ядро ОС панікувало - ймовірно, під час перебудови / dev / md1, де знаходився swap. До цього PostgreSQL з’їв майже весь дисковий простір з файлом журналу на 400 ГБ. ОС ніколи не завантажувався знову, перевірка диска була в порядку, тому я завантажився з LiveCD і створив резервну копію кожного блокового пристрою на зображення, про всяк випадок. Я успішно відновив / каталог з / dev / md2, fsck показав чисту файлову систему, і я створив резервну копію папки PGDATA на зовнішній жорсткий диск.
Що я зробив для спроби відновлення
Після того, як я відформатував пристрої md та перевстановив ОС разом із свіжим postgresql-9.5, я зупинив сервер PostgreSQL, перемістив і порушив папку PGDATA користувачеві postgres і запустив сервер - все здавалося нормально, помилок не було.
Як тільки я почав pg_dumpall
, він помер разом із
Error message from server: ERROR: timestamp out of range
Я, природно, намагався видалити кривдні кортежі, лише в кінці кінців з тією ж invisible tuple
помилкою.
Те, що я спробував
По-перше, DELETE запити не вдалося через пошкоджені сторінки, тому я встановив наступні налаштування:
zero_damaged_pages = on
ignore_system_indexes = on
enable_indexscan = off
enable_bitmapscan = off
enable_indexonlyscan = off
Тепер я помітив, що коли я знову запускаю ті самі запити, сервер знову і знову нулює ті самі сторінки, не знаючи, що це означає:
invalid page in block 92800 of relation base/16385/16443; zeroing out page
Я спробував наступне у невизначеному порядку:
pg_resetxlog -D $PGDATA
зробив свою роботу без помилок чи повідомлень- Видалено всі індекси, включаючи обмеження pkey
CREATE TABLE aaa AS (SELECT * FROM comments);
веде доSegmentation fault
наheap_deform_tuple (tuple=tuple@entry=0x7f0d1be29b08, tupleDesc=tupleDesc@entry=0x7f0d1a35abe0, values=values@entry=0x7ffd57a5beb0, isnull=isnull@entry=0x7ffd57a65af0 "\001\001")
Він відтворюється і залишає основний відвал ~ 9 ГБ.SELECT COUNT(*) from comments;
дозволеноVACUUM comments;
виконати, той самий трюк не працює в інших таблицях.SELECT COUNT(*) from photos;
аVACUUM photos;
тепер помираєERROR: MultiXactId 302740528 has not been created yet -- apparent wraparound
- цей переслідує кожну таблицю, де інші помилки більше не з’являються.
Думки
БД забито великою кількістю ( можливо, дублікатів ) записів ізБД робив,ON CONFLICT
пунктомVACUUM
коли в ядрі настала паніка, я вважаю, що саме від неї виникає проблема, що викликає проблемиnonexistent MultiXactIds
іinvisible tuple
- Дані збирали за допомогою сканера протягом 2-х років, і я цілком нормально втрачаю деякі з них
- Зараз я роблю резервні копії
- Не було жодних реляційних обмежень між таблицями, а також жодних тригерів
Ось вихід 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
Оновлення
- ( 9 грудня 2016 р. ) Читаючи про неіснуючі MultiXactIds , я пам’ятав, що моя база даних на момент аварії не піддавалася операційному навантаженню, але вона обробляла
VACUUM
запит вручну . Я взяв веб-сервери та сканери в автономному режимі після того, як зрозумів, що на дисках залишилось лише 3% місця. Я повинен був перевірити/var/log
наявність великих файлів, але я помилково звинувачував PostgreSQL і намагавсяVACUUM FULL
лише знайти його перерваним через мало місця на пристрої. Тож я почав звичайний ВАКУУМ і залишив його. - ( 14 грудня 2016 р. ) Завантажено 9,5 гілки джерел PostgreSQL з Github, прокоментував блоки в heapam.c та multixact.c та склали його з надією, що він не викине ці помилки. Але сервер не запускався, оскільки його потрібно було налаштувати з тими ж прапорами, які використовувались в одному з APT. Налічувалося близько 47 прапорів, кожен з яких потребував залежності з не очевидною назвою, тому я відмовився від цієї ідеї.
( 16 грудня 2016 р. ) Я знайшов спосіб позбутися кортежів з недійсними часовими позначками, обнуляючи відповідні сторінки. Я спершу встановив такі параметри в
psql
:\set FETCH_COUNT 1 \pset pager off
Я тоді роблю
SELECT ctid, * FROM comments;
. Таким чином, він випльовуєctid
поганий кортеж до вмирання запиту. Потім я переходжу до заповнення цієї сторінки нулями:dd if=/dev/zero of=/var/lib/postgresql/9.5/main/base/16385/16443 bs=8K seek=92803 count=1 conv=notrunc
Але кожна сторона, нульова таким чином, розбиває попередню сторінку, в результаті чого на сторінці16442
зараз є кортеж з недійсною міткою часу. Не впевнений, що я тут роблю неправильно.( 16 грудня 2016 р. ) Спроба
pg_dump -Fc --table photos vw > photos.bak
призводить до помилки сегментації після написання 1,3 ГБ ( з, мабуть, 800 ГБ ). Ось журнал сервера: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
Ось короткий стек:
#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)
Я поняття не маю, як обійти це.
( 29 грудня 2016 р. ) Я написав утиліту, яка робить
SELECT * FROM tablename LIMIT 10000 OFFSET 0
, збільшуючи зміщення та звуження навколо мертвих кортежів, і вона успішно копіювала дані на моїй локальній машині, за винятком кортежів ( сподіваюся, єдиних ), які я вручну пошкодив. Також слід почекати, якщо сервер перезапуститься. Однак у мене не вистачало місця на моєму RAID, і я створив простір таблицьslowdisk
на 8TB HDD. Коли я намагаюсяCREATE DATABASE vwslow WITH TABLESPACE slowdisk
, це не буде робити з помилками: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;
Посібник
CHECKPOINT
призвів до однакових помилок.Перезапуск сервера усунув помилку контрольної точки і дозволив мені запустити свій інструмент. Відповість на моє запитання та опублікує код, якщо він працює.