...

пятница, 10 марта 2017 г.

Еще одна новая фича pg_filedump: восстанавливаем каталог PostgreSQL



В прошлой статье мы узнали, как при помощи утилиты 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. Теперь мы можем сдампить ее содержимое, как было описано в предыдущей статье.


Надеюсь, что на практике эти знания вам никогда не понадобятся :) Если у вас есть вопросы или дополнения, буду рад ознакомиться с ними в комментариях!

Комментарии (0)

    Let's block ads! (Why?)

    Комментариев нет:

    Отправить комментарий