В прошлой статье мы узнали, как при помощи утилиты pg_filedump можно восстановить данные, или, по крайней мере, какую-то их часть, из полностью убитой базы PostgreSQL. При этом предполагалось, что мы откуда-то знаем номера сегментов, соответствующих таблице. Если мы знаем часть содержимого таблицы, ее сегменты действительно не сложно найти, например, простым grep'ом. Однако в более общем случае это не так-то просто сделать. К тому же, предполагалось, что мы знаем точную схему таблиц, что тоже далеко не факт. Так вот, недавно мы с коллегами сделали новый патч для pg_filedump, позволяющий решить названные проблемы.
Итак, допустим, мы хотим восстановить таблицу с именем test. Если имя таблицы мы не помним, это не страшно, так так используя описанный далее прием можно получить имена всех таблиц в базе. Информация о таблицах храниться в каталожной таблице pg_class, сегмент которой всегда имеет номер 1259.
Используя последнюю версию pg_filedump, мы можем прочитать pg_class следующим образом:
./pg_filedump -D name,oid,oid,oid,oid,oid,oid,~ /path/to/base/16384/1259 | grep COPY | grep test
Обратите внимание на список типов для декодирования, который мы передаем pg_filedump:
name,oid,oid,oid,oid,oid,oid,~
Тут мы в начале передаем имена типов первых семи столбцов таблицы (схема pg_class известна и описана в документации), а тильда говорит игнорировать остальные столбцы. В данном случае они нам все равно не интересны, незачем перечислять их все.
Пример вывода:
COPY: test 2200 16387 0 10 0 16385
COPY: test 2200 16387 0 10 0 16385
COPY: test_pkey 2200 0 0 10 403 16391
Последний столбец — это relfilenode, то есть номер сегмента. Он то нам и нужен! Запомним, 16385.
Но постойте-ка, ведь мы не знаем схему таблицы. Узнать ее нам поможет каталожная таблица pg_attribute, relfilenode которой захардкожен и равен 1249. Кстати, relfilenode всех каталожных таблиц вы можете подсмотреть в файле pg_class.h.
Открываем доку по pg_attribute, декодируем:
./pg_filedump -D oid,name,oid,int,smallint,~ /path/to/base/16384/1249 | grep COPY | grep 16385
Пример вывода:
COPY: 16385 k 23 -1 4
COPY: 16385 v 25 -1 -1
COPY: 16385 ctid 27 0 6
COPY: 16385 xmin 28 0 4
COPY: 16385 cmin 29 0 4
COPY: 16385 xmax 28 0 4
COPY: 16385 cmax 29 0 4
COPY: 16385 tableoid 26 0 4
Как видите, таблица имеет два столбца с именами k и v (остальные столбцы системные, они нужны для работы MVCC и вот этого всего). Здесь 23 и 25 — это atttypid, то есть, типы столбцов. Но как понять, что это за типы?
Ответ содержится в каталожной таблице pg_type (relfilenode = 1247, дока):
./pg_filedump -i -D name,~ /path/to/base/16384/1247 | grep -A5 -E 'OID: (23|25)'
Пример вывода:
XMIN: 1 XMAX: 0 CID|XVAC: 0 OID: 23
Block Id: 0 linp Index: 8 Attributes: 30 Size: 32
infomask: 0x0909 (HASNULL|HASOID|XMIN_COMMITTED|XMAX_INVALID)
t_bits: [0]: 0xff [1]: 0xff [2]: 0xff [3]: 0x07
COPY: int4
--
XMIN: 1 XMAX: 0 CID|XVAC: 0 OID: 25
Block Id: 0 linp Index: 10 Attributes: 30 Size: 32
infomask: 0x0909 (HASNULL|HASOID|XMIN_COMMITTED|XMAX_INVALID)
t_bits: [0]: 0xff [1]: 0xff [2]: 0xff [3]: 0x07
COPY: text
Итак, теперь у нас на руках есть вся необходимая информация. Таблица называется test, имеет relfilenode 16385 и содержит два столбца — k с типом int4 и v с типом text. Теперь мы можем сдампить ее содержимое, как было описано в предыдущей статье.
Надеюсь, что на практике эти знания вам никогда не понадобятся :) Если у вас есть вопросы или дополнения, буду рад ознакомиться с ними в комментариях!
Автор: Postgres Professional