Mnesia: abruptly interrupted, round-robin transaction

I have 5 processes that insert / update the same 3 entries in the mnesia table. Each of these processes performs its insertions / updates in a single transaction.

I have 5 more processes that read these 3 records, also within the framework of one transaction.

If I lock the entire table as part of a multi-record transaction, I get {aborted, {circular, node ....}}. My intuition is that my use case is common and should not in itself lead to an aborted transaction. Can someone help me with my bone thinking? All I do is insert (or read) multiple lines in the cache (mnesia table) in one transaction.

The insertion of the three entries looks like this:

insert_keylist(Keys) -> F = fun() -> insert_iter(Keys) end, transactional_execute(F). insert_iter([]) -> ok; insert_iter([{Key, Value} | KVs]) -> insert(Key, Value), insert_iter(Kvs). insert(Key, Value) -> F = fun() -> case sc_store:lookup(Key) of {ok, _Value} -> sc_store:replace(Key, Value); {error, not_found} -> sc_store:insert(Key,Value) end end, transactional_execute(F). transactional_execute(F) -> case mnesia:is_transaction() of true -> F(); false -> try mnesia:sync_transaction(F) of {atomic, Result} -> Result; {aborted, Reason} -> {aborted, Reason} catch ErrorCl:Error -> {error, {ErrorCl, Error}} end end. 

sc_store: replace, insert and search look like this:

 replace(Key, Value) -> try case mnesia:wread({key_to_value, Key}) of [#key_to_value{} = Rec] -> mnesia:write(Rec#key_to_value{value = Value}); [] -> {error, not_found} end catch _Err:Reason -> {error, Reason} end. insert(Key, Value, Type, Scope, TTL, TTLMessage, Ref) -> try NowDT = calendar:now_to_datetime(erlang:now()), ok = mnesia:write(#key_to_value{key = Key, type = Type, scope = Scope, value = Value, create_time_dt = NowDT, ttl_secs = TTL, ttl_message = TTLMessage, ref = Ref}) catch _Error:Reason -> {error, Reason} end. lookup(Key) -> try case mnesia:read(key_to_value, Key) of [#key_to_value{type = Type, scope = Scope, value = Value}] -> {ok, {Value, Type, Scope}}; [] -> {error, not_found} end catch _Err:Reason -> {error, Reason} end. 
+2
source share
2 answers

In fact, it turns out the problem was using try / catch in mnesia operations inside a transaction. See here for more details.

+2
source

ME!
According to your code, the insert_keylist/1 function calls the transactional_execute/1 function with a loss. Inside the function: transactional_execute/1 , you ask mnesia to be already in the transaction, and if it is true, you execute fun F However, looking carefully at the pleasure of F, you see that it calls the function: transactional_execute/1 again through the iterative function: insert_iter/1 . Thus, it creates a transaction loop. Therefore, your problem arises because the process performs the largest function: insert_keylist/1 in the transaction, which creates a nested loop of transactions that are never executed, only they continue to ask mnesia if they are in the transaction, and yet accepts again they keep asking and asking and getting hung up without even being executed !!

Before we change your code, we did not see the functions in the functions: sc_store:replace/2 and sc_store:insert/1 . I will assume that these functions again do NOT create transactions within themselves !! I assume that they directly use the mnesia functions (this should be done in a transaction), for example: mnesia:write/1 , mnesia:read/1 , mnesia:write/3 etc Otherwise, if you created another transaction in these functions , for sure it will be a mnesia transaction mess! Now fix the code as shown below:

  %% This function will always be sure to be in a 
 %% mnesia transaction.  So no need to call
 %% transactional execute

 insert_iter ([]) -> ok;
 insert_iter ([{Key, Value} | KVs]) ->
    case sc_store: lookup (Key) of
         {ok, _Value} -> sc_store: replace (Key, Value);
         {error, not_found} -> sc_store: insert (Key, Value)
     end
     insert_iter (Kvs).

To require a single change, assuming that the sc_store:insert/1 and sc_store:replace/2 functions access mnesia's write and read functions directly, without creating any other transactions.

+2
source

Source: https://habr.com/ru/post/900375/


All Articles