Ссылка мертва. Именно поэтому вы не должны давать ссылки на ответы на сторонних сайтах, а давать полный ответ здесь.

ял, что mnesia не поддерживает функцию автоинкремента, как это делает MySQL или другие RDBMS. Счетчики, о которых говорилось в документации mnesia, не очень хорошо объяснены. Например, я обнаружил одну функцию во всей документации, которая управляет счетчиками

mnesia:dirty_update_counter({Tab::atom(),Key::any()}, Val::positive_integer())

Итак, это беспокоило меня некоторое время, потому что это работает с записями типа

{TabName, Key, Integer}
Это также неясно, и, возможно, потому, что ни одна книга erlang или документация по mnesia не дает пример, чтобы объяснить это. Это вынудило меня реализовать мои собственные API для манипулирования счетчиками. Поскольку я хотел иметь возможность получать доступ к своим записям и управлять ими с помощью счетчиков, мне пришлось включить поле с именем 'counter' в мои записи, а затем добавить запись в таблицу, которая должна иметь счетчики, я делаю это так:

#recordname{field1 = Val1,...,counter = auto_increment(?THIS_TABLE)}

Положение полей счетчика не имеет значения. API реализован следующим образом:

%% @doc this function is called whenever u are writing a new record in the table
%% by giving its result to the counter field in your record.
%% @end
%%
%% @spec auto_increment(TableName::atom()) -> integer() | exit(Reason)
auto_increment(TableName)-> case lists:member(counter,table_info(TableName,attributes)) of false -> erlang:exit({counter,field,not_found,in_table,TableName}); true -> table_info(TableName,size) + 1 end.
table_info(Tab,Item)-> F = fun({X,Y}) -> mnesia:table_info(X,Y) end, mnesia:activity(transaction,F,[{Tab,Item}],mnesia_frag).

Чтобы объяснить это, если поле счетчика не является атрибутом таблицы, я принудительно позволяю процессу, который пытается выполнить этот код, выйти с определенной причиной, поэтому, если программисты вызывают это в try ... catch или case ( поймать ...) тела, они легко увидят, что не так. Кроме того, я мог бы спросить, выполняется ли этот фрагмент кода в транзакции, используяmnesia:is_transaction() и если это возвращает истину, я звонюmnesia:abort/1, если false, я мог бы просто выйти с разумом. Также я использую mnesia_frag в функции активности mnesia, потому что эта реализация будет работать независимо от свойств фрагментации таблицы. Если я используюmnesia:transaction(Fun)фрагментированные таблицы станут несовместимыми, потому что этот вызов будет обращаться только к начальному фрагменту (базовой таблице).
Теперь, когда запись удалена из таблицы со счетчиками, нам нужно изменить порядок в таблице. Эта операция является дорогостоящей, так как требует итерации по всей таблице. Так как, если они удаляют запись с счетчиком = 5, запись с счетчиком = 6 должна стать счетчиком = 5 и так далее, следуя шаблону. Все записи, счетчики которых были больше удаленных, должны быть уменьшены. Таким образом, передав значение счетчика удалено и TableName, можно перебрать таблицу с помощью
mnesia:foldl/3 or mnesia:foldr/3 , the difference between these two comes in only with ordered table types
Вот функция, которая заботится об этом:

auto_decrement(Counter_deleted,TableName)->
    Attrs = table_info(TableName,attributes),
    case lists:member(counter,Attrs) of
        false -> erlang:exit({counter,field,not_found,in_table,TableName});
        true -> 
            Counter_position = position(counter,Attrs) + 1,         
            Iterator =  fun(Rec,_) when element(Counter_position,Rec) > Counter_deleted -> 
                            Count = element(Counter_position,Rec),
                            New_rec = erlang:setelement(Counter_position,Rec,Count - 1),
                            mnesia:write(TableName,New_rec,read),
                            [];
                        (_,_) -> []
                        end,
            Find = fun({Fun,Table}) -> mnesia:foldl(Fun, [],Table) end,
            mnesia:activity(transaction,Find,[{Iterator,TableName}],mnesia_frag)
    end.


Вы заметили, что у меня есть код, который помогает мне динамически находить положение поля счетчика по записи. Код, который помогает мне сделать это, показан ниже:

position(_,[]) -> -1;
position(Value,List)->
    find(lists:member(Value,List),Value,List,1).

find(false,_,_,_) -> -1;
find(true,V,[V|_],N)-> N;
find(true,V,[_|X],N)->
    find(V,X,N + 1).

find(V,[V|_],N)-> N;
find(V,[_|X],N) -> find(V,X,N + 1).


Это так, потому что этот модуль не должен знать какие-либо записи программистов, чтобы помочь ему с счетчиками. Поэтому для доступа к значению счетчика из записи с помощью функций манипулирования кортежем, таких какelement(N::integer(),Tuple::tuple())Я должен рассчитать его положение в кортеже представления записи, динамически.

These two functions have worked for me and are still working till auto_increment
is implemented in mnesia.

Например, используя qlc (понимание списка запросов) для запроса таблиц с динамическими ограничениями, рассмотрите следующие фрагменты кода ниже:

select(Q)->
    F = fun(QH) -> qlc:e(QH) end,
    mnesia:activity(transaction,F,[Q],mnesia_frag).

read_by_custom_validation(Validation_fun,From_table)->
    select(qlc:q([X || X <- mnesia:table(From_table),Validation_fun(X) == true])).

%% Applying the two functions....
find_records_with_counter(From_this,To_that) when 
is_integer(From_this),is_integer(To_that),To_that > From_this -> F = fun(#recordName{counter = N}) when N >= From_this,N =< To_That -> true; (_) -> false end, read_by_custom_validation(F,TableName).

В системе управления запасами это работает ...

([email protected])6> stock:get_items_in_range(1,4).
[#item{item_id = "D694",name = "cement",
       time_stamp = {"30/12/2010","11:29:10 am"},
       min_stock = 500,units = "bags",unit_cost = 20000,
       state = available,last_modified = undefined,
       category = "building material",counter = 1},
 #item{item_id = "131B",name = "nails",
       time_stamp = {"30/12/2010","11:29:10 am"},
       min_stock = 20000,units = "kgs",unit_cost = 1000,
       state = available,last_modified = undefined,
       category = "building material",counter = 2},
 #item{item_id = "FDD9",name = "iron sheets",
       time_stamp = {"30/12/2010","11:29:10 am"},
       min_stock = 20,units = "bars",unit_cost = 50000,
       state = available,last_modified = undefined,
       category = "building material",counter = 3},
 #item{item_id = "09D4",name = "paint",
       time_stamp = {"30/12/2010","11:29:10 am"},
       min_stock = 30000,units = "tins",unit_cost = 5000,
       state = available,last_modified = undefined,
       category = "building material",counter = 4}]
([email protected])7>

Это работает для меня. Пожалуйста, посоветуйте мне, как еще мне позаботиться о счетчиках. Или вы можете сказать мне, как вы справляетесь с ними по ту сторону.

Ответы на вопрос(1)

Ваш ответ на вопрос