Pull to refresh

Mnesia — изменение таблицы

Reading time3 min
Views7.2K
В Mnesia много всего полезного: хранит данные в формате Erlang, репликация, транзакции и т.д. и т.п. Но есть одна проблемка — как изменить структур таблицы?

При создании таблицы необходимо указать список полей. Не будем сейчас углубляться в рекомендации использовать запись (record) одноименную с таблицей. Важно, что при изменении списка полей по предлагаемому в документации варианту с использованием mnesia:transform_table (конвертирование полей и замена определения таблицы), похоже, придется останавливать работу системы, конвертировать таблицу, менять код приложения для работы с новым типом и запуск (тестирование).
Если посмотреть на любую SQL базу данных, то добавление поля — элементарная операция.
Для меня важно провести переход на новый тип без остановки всей системы. По крайнеё мере БД должна функционировать непрерывно.

Я исследовал чтение и запись в Mnesia. И вывод таков:
Mnesia жестко контролирует данные при записи. Записать можно только то, что объявлено в структуре таблицы, иначе ошибка. Контролируется имя записи и количеств элементов — т.е. ВСЕ.
Однако, при чтении Mnesia отдает то, что было записано, не сверяясь с текущим сконфигурированным списком полей и названием записи. А список полей можно изменить и без фактической трансформации записей при помощи не рекомендуемой формы mnesia:transform_table(Tab,ignore, Fildlist ).
Это форма предназначена, судя по документации, для пользовательской трансформации записей таблицы.
Посмотрим, как все это работает. Для примера создадим таблицу, запишем данные, а потом добавим новые поля и трансформируем с ignore:
-module(recordtest).
-compile(export_all).
-record(r1 ,{f1,f2}).
-record(r2 ,{f1,f2,f3,f4}).
dbtest()->
mnesia:create_table(r1,[{attributes, record_info(fields, r1)}]).
transform()->
mnesia:transform_table(r1,ignore,record_info(fields, r2), r2).


Испытаем:

14> mnesia:create_schema([node()]).
18> mnesia:start().
ok
19> recordtest:dbtest().
{atomic,ok}
20> mnesia:dirty_write(r1, {r1,l1,l2}).
ok
21> mnesia:dirty_write(r1, {r1,t1,t2,t3}).
** exception exit: {aborted,{bad_type,{r1,t1,t2,t3}}}
in function mnesia:abort/1
22> mnesia:dirty_write(r1, {r2,l1,l2}).
** exception exit: {aborted,{bad_type,{r2,l1,l2}}}
in function mnesia:abort/1
23> mnesia:dirty_read(r1, l1).
[{r1,l1,l2}]
24> mnesia:dirty_read(r1, l1).
[{r1,l1,l2}]

38> recordtest:transform().
{atomic,ok}
39> mnesia:dirty_read(r1, l1).
[{r1,l1,l2}]
40> mnesia:dirty_write(r1, {r2,l1,l2}).
** exception exit: {aborted,{bad_type,{r2,l1,l2}}}
in function mnesia:abort/1
41> mnesia:dirty_write(r1, {r2,a1,a2,a3,a4}).
ok
49> mnesia:dirty_read(r1, l1).
[{r1,l1,l2}]
50> mnesia:dirty_read(r1, a1).
[{r2,a1,a2,a3,a4}]


Теперь у нас в таблице записи обоих типов и мы их можем прочитать. Но если мы теперь попытаемся создать индекс на четвертом поле записи mnesia:add_table_index(r1,[l4]).
— получим фатальную ошибку, остановку mnesia. При следующем запуске этой базы снова произойдет ошибка. Поможет удаление файла r1.dcm — после этого mnesia запустится. Необходимо будет еще удалить определение таблицы из схемы.
Следовательно, пока все записи в таблицы не будут соответствовать спецификации индекса — ни в коем случае нельзя индексировать.

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

Если кто знаком с проблемой изменения таблиц в Mnesia — поделитесь. Информации о Mnesia очень мало.
Tags:
Hubs:
+6
Comments18

Articles