Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Сделать возможность создания дочерних таблиц в различных tablespace #11

Closed
socketpair opened this issue Apr 12, 2016 · 18 comments
Assignees
Milestone

Comments

@socketpair
Copy link

No description provided.

@funbringer
Copy link
Collaborator

@socketpair, не могли бы вы поделиться своим видением реализации этой фичи? Насколько я понимаю, основной профит заключается в том, чтобы раскидать партиции по нескольким tablespace, размещенным на разных физических устройствах, не так ли?

@1803
Copy link

1803 commented Aug 24, 2016

@funbringer, на самом деле идея не такая уж и плохая, т.к. на данный момент параметр полностью игнорируется.

Я считаю было бы достаточно наследовать табличное пространство родителя. В моем случае это связано с необходимостью разместить таблицу с bytea-полями в пространстве на менее производительных дисках.

Простой тест показывающий что tablespace не учитываются при создании дочерних таблиц:

create table ptt_tblspc_test
(
    p_id bigserial primary key,
    p_ts timestamp not null,
    p_datum text
)
tablespace tblspc_part;

select create_range_partitions
(
    'ptt_tblspc_test'::regclass,
    'p_ts', localtimestamp - interval '1 year',
    interval '1 month',
    10
);

select 
        pgcl.relname relnm, 
        coalesce(pgtblspc.spcname, 'pg_default') reltblspc
    from 
        pg_class pgcl 
            left join pg_tablespace pgtblspc on pgtblspc.oid = pgcl.reltablespace 
    where 
            relkind = 'r' 
        and relname ilike 'ptt_tblspc_test%';

Результат:

relnmreltblspc
ptt_tblspc_test_1pg_default
ptt_tblspc_test_2pg_default
ptt_tblspc_test_3pg_default
ptt_tblspc_test_4pg_default
ptt_tblspc_test_5pg_default
ptt_tblspc_test_6pg_default
ptt_tblspc_test_7pg_default
ptt_tblspc_test_8pg_default
ptt_tblspc_test_9pg_default
ptt_tblspc_test_10pg_default
ptt_tblspc_testtblspc_part

Edit:
Если будет реализован функционал #22 то можно возложить эту задачу на пользователя. Такой подход даст большую гибкость, т.к. вполне реальна ситуация, когда для больших объемов данных часть партиций будет размещаться в одном пространстве, часть в другом, а слепое наследование только вызовет лишний I/O.

@funbringer
Copy link
Collaborator

@1803, приветствую еще раз!

Абсолютно справедливо, текущая реализация не учитывает tablespace вообще, хотя логичнее было бы размещать именно в пространстве родителя.

По поводу "возложить на пользователя": планируется вызывать колбек уже после создания партиции. Безусловно, можно создать колбек, который будет выполнять ALTER TABLE ... SET TABLESPACE ..., но мне это видится более затратным, чем создание партиций сразу в нужном пространстве таблиц.

Кроме того, далеко не всем нужна такая гибкость ценой неизбежного выполнения лишних телодвижений (к примеру, создание колбеков с нетривиальной логикой для равномерного размещения в нескольких пространствах). Было бы логично предоставить отключаемый стандартный механизм, но его нужно продумать и аккуратно реализовать. Следовательно, будет возможность выбирать, что использовать. Впрочем, на этот счет можно будет еще подумать.

Функционал #22 мне лично нравится, и мы приступим к реализации сразу как освободимся от текущих задач (необходимо выкатить наши наработки в master). Он позволит решить проблему с tablespace своими руками тем, кому это нужно.

@funbringer funbringer added this to the Release 1.1 milestone Aug 31, 2016
@zilder zilder self-assigned this Sep 8, 2016
@zilder
Copy link
Collaborator

zilder commented Sep 16, 2016

Добрый вечер!

Добавил поддержку тейблспейсов в тестовой ветке callbacks. В частности теперь дочерние таблицы создаются автоматически в том же tablespace, что и родительская. Кроме того появился дополнительный параметр tablespace у функций создания секций:

append_range_partition(
    parent_relid    REGCLASS,
    partition_name  TEXT DEFAULT NULL,
    tablespace      TEXT DEFAULT NULL)
prepend_range_partition(
    parent_relid    REGCLASS,
    partition_name  TEXT DEFAULT NULL,
    tablespace      TEXT DEFAULT NULL)
add_range_partition(
    parent_relid    REGCLASS,
    p_start_value   ANYELEMENT,
    p_end_value     ANYELEMENT,
    partition_name  TEXT DEFAULT NULL,
    tablespace      TEXT DEFAULT NULL)

Также реализован функционал для добавления своего собственного callback-а, описанного в тикете #22. Не могли бы вы попробовать эту версию на своих кейсах? Устраивает ли такая реализация?

PS: Меня не будет в городе в ближайшие две недели и скорее всего не будет связи, поэтому смогу ответить уже после того, как вернусь.

@1803
Copy link

1803 commented Sep 26, 2016

Не могли бы вы попробовать эту версию на своих кейсах? Устраивает ли такая реализация?

Пытаюсь собрать под Windows через msvc. Есть ряд трудностей. Если у вас уже есть версия которая собирается под Windows или рекомендации, то я с радостью приму ее. Под linux пока не тестировал.

Первая сборка отказывается работать. Пока к сожалению нет времени более глубоко разбираться в причинах.

После патча возникают следующие ошибки при компиляции:

1>d:\dev\pgext\pg_pathman_callbacks\pg_pathman_callbacks\pathman_callbacks\relation_info.c(672): error C4703: potentially uninitialized local pointer variable 'expected_str' used
1>d:\dev\pgext\pg_pathman_callbacks\pg_pathman_callbacks\pathman_callbacks\relation_info.c(501): error C4703: potentially uninitialized local pointer variable 'action_str' used

Инициализация этих переменных в NULL приводит к тому что create_range_partitions приводит к:

server process (PID 11948) was terminated by exception 0xC0000005 (STATUS_ACCESS_VIOLATION)

Буду разбираться дальше по мере наличия времени.

@1803
Copy link

1803 commented Sep 28, 2016

Отказался от msvc, собрал через gcc;
Там в makefile есть ссылка на win32ver.rc, которого нет ни в ветке ни в масере. Я убрал его оттуда, чтобы собралось.

Полученная dll крашит сервер с тем же кодом ошибки (0xC0000005) при попытке создать range_partition.
Собрал мастер, все ок, т.е. ошибка именно с колбеками связана.

Попробую добыть стек трейс, может он поможет.

UPD:
Трейсы 3-х потоков backend'а который крашится:
https://goo.gl/yiy2Ep
https://goo.gl/zPLBrF
https://goo.gl/MAUDJ2

Ключевое:

0, postgres.exe!hash_search+0x14
1, pg_pathman.dll!get_pathman_relation_info+0x23
2, pg_pathman.dll!invoke_on_partition_created_callback+0x37

@stalkerg
Copy link

Пожалуйста гляньте на /src/tools/msvc/gendef.pl тогда ваш патч будет не нужен.
Этот скрипт создаёт .def файл из .obj файлов и потом .def нужно скормить линковщику.

@funbringer
Copy link
Collaborator

funbringer commented Sep 28, 2016

to @1803

Инициализация этих переменных в NULL приводит к тому...

Что вы имеете в виду? Я правильно понимаю, что вы внесли какие-то исправления в код?

что create_range_partitions приводит к...

Что странно, потому что обе переменные не инициализированы только в тех случаях, когда исполнение запроса экстренно завершается вызовом elog(ERROR, ...), не доходя до разыменования. Насколько я понимаю, для MSVC определение pg_unreachable() есть:

#if defined(HAVE__BUILTIN_UNREACHABLE) && !defined(USE_ASSERT_CHECKING)
#define pg_unreachable() __builtin_unreachable()
#elif defined(_MSC_VER) && !defined(USE_ASSERT_CHECKING)
#define pg_unreachable() __assume(0)
#else
#define pg_unreachable() abort()
#endif

Поэтому поведение компилятора мне кажется странным. Впрочем, я не очень хорошо разбираюсь в вопросах сборки PostgreSQL под Windows. Во всяком случае, ошибки в данном коде нет. Следовательно, к падению в create_range_partitions() эти куски кода привести не могут.

Там в makefile есть ссылка на win32ver.rc, которого нет ни в ветке ни в масере. Я убрал его оттуда, чтобы собралось.

Этот файл лежит в исходниках самого PostgreSQL (src/port/win32ver.rc). pg_pathman для нашего дистрибутива собирается как contrib.

Собрал мастер, все ок, т.е. ошибка именно с колбеками связана.

Собирали так же, используя ваши исправления? Если так, то вполне возможно, что ошибка в ветке.

@1803
Copy link

1803 commented Sep 28, 2016

Забудьте про msvc.
Все собрано с помощью gcc, поэтому этих исправлений там нет (gcc собирает без ошибок).

Бекэнд крашится при вызове функции hash_search() из get_pathman_relation_info() которая вывывается в invoke_on_partition_created_callback():

if ((prel = get_pathman_relation_info(parent_oid)) == NULL)
{
    elog(ERROR,
     "Relation %s isn't partitioned by pg_pathman",
     get_rel_name(parent_oid));
}
get_pathman_relation_info(Oid relid)
{
    const PartRelationInfo *prel = hash_search(partitioned_rels,
                                               (const void *) &relid,
                                               HASH_FIND, NULL);

Последний вызов завершается с SEGFAULT.

Пожалуйста гляньте на /src/tools/msvc/gendef.pl тогда ваш патч будет не нужен.
Этот скрипт создаёт .def файл из .obj файлов и потом .def нужно скормить линковщику.

Спасибо, обязательно изучу этот вопрос.

@funbringer
Copy link
Collaborator

Забудьте про msvc.

Ок, как скажете.

Бекэнд крашится при вызове функции
hash_search() из get_pathman_relation_info() которая вывывается в invoke_on_partition_created_callback()

А в остальном pg_pathman у вас работает? Запросы к партицированной таблице? Чем собран сам постгрес?

@1803
Copy link

1803 commented Sep 28, 2016

А в остальном pg_pathman у вас работает?

Я плохо сформулировал все.

Я тестирую работоспособность pg_pathman-callbacks под Windows. Для тестов использовал 2 сборки:

Сначала PostgreSQL 9.5.4 x64: сборку от EnterpriseDB (compiled by Visual C++ build 1800, 64-bit). Когда появилась ошибка, я решил собрать сборку с дебагом, чтобы посомтреть трейсы.
Сборка с дебагом: PostgreSQL 9.5.4 on x86_64-w64-mingw32, compiled by gcc

Ошибка одинаковая проявляется в обоих версиях при попытке создать range partition (ничего другого даже не пробовал)

Пример:

create tablespace tblspc_part location 'd:\somepath\somefolder';

create extension pathman;

create table p(p_id bigserial, p_ts timestamp not null, p_dat text) tablespace tblspc_part;

select create_range_partitions('p'::regclass, 'p_ts'::text, timestamp'2015-08-01', interval '1 month', 2, true);

@funbringer
Copy link
Collaborator

Бекэнд крашится при вызове функции hash_search() из get_pathman_relation_info()

Я допускаю, что такое может быть, но это наводит меня на мысль, что либо вы как-то неправильно собираете (pg_pathman не может нормально проинициализироваться, не видит каких-либо символов postgres, перекрытых теми, что создал компилятор и т.д.), либо в этом коде действительно есть ошибка, что странно, потому что аналогичные вызовы расставлены по всему модулю для разнообразных нужд.

К сожалению, ваш кейс у меня не воспроизводится. Советую попробовать собрать именно с MSVC соответствующей версии, хотя это и проблематично. Я готов и сам попробовать, когда будет время и возможность.

Хочу уточнить еще раз: на ветке master партицирование работает у вас? Из ваших ответов я этого не понял, не сочтите за оскорбление.

@1803
Copy link

1803 commented Sep 28, 2016

на ветке master партицирование работает у вас?

Да, партиции создаются. Дальше пока не смотрел. Сейчас проверю все более тщательно.

Извините, не правильно понял ваш вопрос.

@1803
Copy link

1803 commented Sep 28, 2016

@funbringer судя по всему вы были правы. В мастере у меня не создается insert-триггер для родительской таблицы и все данные попадают в родительскую, хотя дочерние таблицы созданы. Самое интересное что я не могу найти где в коде создаются эти триггеры..

Думаю нужно начать тестировать на линуксе..

@funbringer
Copy link
Collaborator

В мастере у меня не создается insert-триггер для робительской таблицы

Так и должно быть, сейчас для вставки используется кастомная нода PartitionFilter.

и все данные попадают в родительскую

А вот так быть не должно, можете показать explain analyze для insert?

@1803
Copy link

1803 commented Sep 28, 2016

explain analyze insert into p(p_ts)
    values('2015-09-02 00:00:00'::timestamp without time zone);
-----
Insert on p  (cost=0.00..0.01 rows=1 width=0) (actual time=0.035..0.035 rows=0 loops=1)
  ->  Result  (cost=0.00..0.01 rows=1 width=0) (actual time=0.024..0.024 rows=1 loops=1)
Planning time: 0.026 ms
Execution time: 0.055 ms

@funbringer
Copy link
Collaborator

to @1803

У вас определенно неправильно работает pg_pathman. Для сравнения:

explain insert into p values(0, now(), NULL);
                              QUERY PLAN                               
-----------------------------------------------------------------------
 Insert on p  (cost=0.00..0.01 rows=1 width=0)
   ->  Custom Scan (PartitionFilter)  (cost=0.00..0.01 rows=1 width=0)
         ->  Result  (cost=0.00..0.01 rows=1 width=0)
(3 rows)

Как вы можете заметить, мой план отличается: между Insert и Result появляется наша проксирующая кастомная нода, которая перенаправляет кортеж в нужную партицию.

Попробуйте

set pg_pathman.enable = t;
set pg_pathman.enable_partitionfilter = t;

Если поведение не изменится, вам следует пересмотреть процедуру сборки под Windows, потому что это будет косвенно указывать на неправильную линковку символов, отвечающих за GUC.

@1803
Copy link

1803 commented Sep 28, 2016

@funbringer Идея с GUC была верная. Ошибка была моя. Почему-то я решил что файлы расширения должны называться pathman.control и pathman--1.0.sql (а не pg_pathman..) а с ними и сам extension. Поэтому видимо гуки не подхватывались.

Этим же была вызвана ошибка которая приводила к падению бэкэнда. (сейчас ветка callbacks успешно создает партиции)

Спасибо большое за помощь и извините за беспорядок который я тут развел. Пойду дальше тестировать..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants