- PVSM.RU - https://www.pvsm.ru -
Сегодня я хотел бы вновь рассказать о некоторых патчах, принятых за последнее время в PostgreSQL (а также утилиту pg_filedump). Аналогичные статьи, опубликованные на Хабре ранее, набрали достаточно много плюсиков, что заставляет думать, что они представляют для кого-то интерес. Если вы пропустили предыдущие статьи, вот они — раз [1], два [2], три [3]. Несмотря на то, что рассмотренные патчи были написаны мной, не стоит забывать о вкладе людей, которые их ревьювили и тестировали. Проделанная этими людьми работа зачастую оказывается больше и сложнее работы самого автора. Особо активное участие в разработке рассмотренных пачтей приняли Федор Сигаев, Robert Haas, Tom Lane, Дмитрий Иванов, Григорий Смолкин, Andres Freund, Анастасия Лубенникова и Tels.
11. pg_filedump: возвращение ненулевого кода возврата в случае ошибок
Напомню, что утилита pg_filedump [4] предназначена для декодирования сегментов таблиц и вывода информации о заголовках страниц и кортежей. Было замечено, что при несовпадении контрольных сумм страниц с их содержимым, pg_filedump выводит соответствующее предупреждение, однако возвращает нулевой код возврата. Что как бы не совсем правильно, особенно если утилита используется в shell-скриптах.
Патч исправляет эту ситуацию. Теперь pg_filedump возвращает ненулевой код при обнаружении любых ошибок, как в контрольных суммах, так и любых других:
+/* Program exit code */
+static int exitCode = 0;
+
/***
* Function Prototypes
*/
@@ -191,6 +194,7 @@ ConsumeOptions(int numOptions, char **options)
{
rc = OPT_RC_INVALID;
printf("Error: Missing range start identifier.n");
+ exitCode = 1;
break;
}
@@ -205,6 +209,7 @@ ConsumeOptions(int numOptions, char **options)
rc = OPT_RC_INVALID;
printf("Error: Invalid range start identifier <%s>.n",
optionString);
+ exitCode = 1;
break;
}
(...и так далее...)
@@ -1746,5 +1823,5 @@ main(int argv, char **argc)
if (buffer)
free(buffer);
- exit(0);
+ exit(exitCode);
}
Патч: 1c9dd6b728810ea7d2f196e6e15064017e4b9eef [5]
12. Улучшение документации о внутреннем представлении типа timestamp
Документация к типу timestamp гласила:
When <type>timestamp</> values are stored as eight-byte integers
(currently the default), microsecond precision is available over
the full range of values. When <type>timestamp</> values are
stored as double precision floating-point numbers instead (a
deprecated compile-time option), the effective limit of precision
might be less than 6. <type>timestamp</type> values are stored as
seconds before or after midnight 2000-01-01. [...]
В ходе работы над рассмотренным в следующем раздеде патчем было замечено, что приведенный текст создает неверное представление. На самом деле, по умолчанию timestamp хранит время в микросекундах. Если же пользователь выбрал устаревшее представление в виде чисел с плавающей точкой, тогда действительно время хранится в секундах.
После недолгого обсуждения в рассылке вводящий в заблуждение кусок документации был переписан.
Патч: 44f7afba79348883da110642d230a13003b75f62 [6]
13. pg_filedump: частичное восстановление данных
Этот патч был подробно рассмотрен в заметке Пример восстановления таблиц PostgreSQL с помощью новой мега фичи pg_filedump [7], поэтому здесь я не буду на нем подробно останавливаться. TL;DR версия — теперь при помощи pg_filedump можно восстановить по крайней мере какую-то часть данных из таблицы, даже в случае, если инстанс PostgreSQL не запускается.
Патч: 52fa0201f97808d518c64bcb9696f2a350678aa5 [8]
14. pg_filedump: декодирование каталожных таблиц
Как и предыдущему патчу, этому была посвящена целая отельная статья Еще одна новая фича pg_filedump: восстанавливаем каталог PostgreSQL [9]. TL;DR версия для тех, кто все равно не собирается ее читать — раньше pg_filedump не поддерживал некоторые типы, используемые в каталожных таблицах. После применения этого патча стало возможным декодировать таблицы каталога, а следовательно и восстановить схему базы данных, если она нам не известна.
Патч: 5c5ba458fa154183d11d43218adf1504873728fd [10]
15а. Ускорение партицирования: исправление батлнека в find_tabstat_entry() / get_tabstat_entry()
В PostgreSQL 10, который на момент написания этих строк разрабатывается и находится в состоянии фичфриза, была добавлена возможность декларативного партицирования таблиц [11]. То есть, теперь таблицу можно разбить на несколько физических таблиц по хэшу или ренджам. Это было возможно и ранее при помощи наследования таблиц, но было менее удобно и в целом выглядело как грязный хак. Примеры использования декларативного партицирования можно найти здесь [12] и здесь [13].
Ну вот я и подумал, а создам-ка я побольше (скажем, 10 000) партиций и посмотрю, где будет тормозить. Теме профилирования кода на C/C++ ранее я посвящал целую статью [14], даже несколько, если считать статьи про DTrace [15], SystemTap [16] и HeapTrack [17]. Кроме того, на эту тему я делал доклад на HighLoad++ 2016 [18], видеозапись которого лежит на YouTube [19]. Поэтому на описании процесса здесь я подробно останавливаться не буду. Скажу только, что perf top показал два явных батлнека, которые вы можете видеть на иллюстрации в начале данной статьи.
Так вот, патч исправляет первый из этих батлнеков. Оказалось, что статистика по таблицам использует небольшой аллокатор памяти, построенный на списках. Поиск по идентификатору таблицы структуры PgStat_TableStatus, соответствующей таблице, производился путем сканирования этого списка, что работает не очень хорошо, когда таблиц 10 000. Добавление хэш-таблицы, отображающей идентификатор таблицы в указатель на структуру, моментально устранило батлнек.
Патч: 090010f2ec9b1f9ac1124dc628b89586f911b641 [20]
15б. Ускорение партицирования: исправление батлнека в find_all_inheritors()
Аналогичная проблема присутствовала и в процедуре рекурсивного поиска всех наследников заданной таблицы. Немногие знают, что PostgreSQL поддерживает множественное наследование таблиц [21]. Поэтому при обходе дочерних таблиц процедура проходит по списку ранее посещенных таблиц. Если очередной таблицы в списке нет, она в него добавляется. Если она там уже есть, у таблицы увеличивается счетчик родителей. Список всех дочерних таблиц и число их родителей возвращается из процедуры в качестве результата.
Как вы уже могли догадаться, батлнек снова был устранен добавлением хэш-таблицы для ускорения поиска по списку. По моим бенчмаркам два патча суммарно ускорили декларативное партицирование на 64%. Интересно, что патчи ускоряют его не только при большом количестве партиций, но и когда партиций всего лишь несколько штук. Хотя в последнем случае, конечно же, эффект не так заметен.
Патч: 827d6f977940952ebef4bd21fb0f97be4e20c0c4 [22]
Заключение
Как и ранее, цель всех этих статей — показать, что в разработке РСУБД, в частности PostgreSQL, несмотря на крайнюю интересность процесса, нет чего-то волшебного или прямо-таки непостижимо сложного. Хочется надеяться, что эта серия статей сможет мотивировать пару-тройку человек принять участие в разработке PostgreSQL, в качестве хобби, или же профессионально.
В частности, компания Postgres Professional, в которой я сейчас работаю, перманентно нанимает [23], притом, не только программистов, но и, к примеру, QA и DBA. Как уже было отмечено, качественные тестирование и code review в нашем деле зачастую оказываются важнее написания кода.
Автор: Postgres Professional
Источник [24]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/postgresql/251971
Ссылки в тексте:
[1] раз: https://habrahabr.ru/company/postgrespro/blog/308442/
[2] два: https://habrahabr.ru/company/postgrespro/blog/309488/
[3] три: https://habrahabr.ru/company/postgrespro/blog/310372/
[4] утилита pg_filedump: https://wiki.postgresql.org/wiki/Pg_filedump
[5] 1c9dd6b728810ea7d2f196e6e15064017e4b9eef: https://git.postgresql.org/gitweb/?p=pg_filedump.git;a=commitdiff;h=1c9dd6b728810ea7d2f196e6e15064017e4b9eef
[6] 44f7afba79348883da110642d230a13003b75f62: https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=44f7afba79348883da110642d230a13003b75f62
[7] Пример восстановления таблиц PostgreSQL с помощью новой мега фичи pg_filedump: https://habrahabr.ru/company/postgrespro/blog/319770/
[8] 52fa0201f97808d518c64bcb9696f2a350678aa5: https://git.postgresql.org/gitweb/?p=pg_filedump.git;a=commitdiff;h=52fa0201f97808d518c64bcb9696f2a350678aa5
[9] Еще одна новая фича pg_filedump: восстанавливаем каталог PostgreSQL: https://habrahabr.ru/company/postgrespro/blog/323644/
[10] 5c5ba458fa154183d11d43218adf1504873728fd: https://git.postgresql.org/gitweb/?p=pg_filedump.git;a=commitdiff;h=5c5ba458fa154183d11d43218adf1504873728fd
[11] декларативного партицирования таблиц: https://commitfest.postgresql.org/12/611/
[12] здесь: https://www.depesz.com/2017/02/06/waiting-for-postgresql-10-implement-table-partitioning/
[13] здесь: https://www.keithf4.com/postgresql-10-built-in-partitioning/
[14] посвящал целую статью: http://eax.me/c-cpp-profiling/
[15] DTrace: http://eax.me/dtrace/
[16] SystemTap: http://eax.me/systemtap/
[17] HeapTrack: http://eax.me/heaptrack/
[18] доклад на HighLoad++ 2016: http://www.highload.ru/2016/abstracts/2356.html
[19] лежит на YouTube: https://www.youtube.com/watch?v=0NU07havVD0
[20] 090010f2ec9b1f9ac1124dc628b89586f911b641: https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=090010f2ec9b1f9ac1124dc628b89586f911b641
[21] PostgreSQL поддерживает множественное наследование таблиц: https://www.postgresql.org/docs/current/static/ddl-inherit.html
[22] 827d6f977940952ebef4bd21fb0f97be4e20c0c4: https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=827d6f977940952ebef4bd21fb0f97be4e20c0c4
[23] перманентно нанимает: https://postgrespro.ru/jobs
[24] Источник: https://habrahabr.ru/post/325850/
Нажмите здесь для печати.