Mnesia:意外地中止,循环交易 [英] Mnesia: unexpectedly getting aborted, cyclic transactions

查看:132
本文介绍了Mnesia:意外地中止,循环交易的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有5个进程在mnesia表中插入/更新相同的3个记录。这些进程中的每一个都在单个事务中进行插入/更新。



我有5个其他进程读取这些相同的3个记录,也在一个事务中。



除非我将整个表作为多记录事务的一部分进行锁定,否则我将收到{aborted,{cyclic,node ....}}错误。我的直觉是我的用例是普通的,不应该导致中止的事务。有人可以用我的骨头思维帮助我吗?我所做的就是在一个事务中插入(或读取)多个行的缓存(mnesia表)。



插入3条记录看起来像这样

  insert_keylist(Keys) - > 
F = fun() - > insert_iter(Keys)end,
transactional_execute(F)。

insert_iter([]) - >
ok;
insert_iter([{K​​ey,Value} | KVs]) - >
insert(Key,Value),
insert_iter(Kvs)。

insert(Key,Value) - >
F =
fun() - >
case sc_store:lookup(Key)
{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()
true - > F();
false - >
try mnesia:sync_transaction(F)of
{atomic,Result} - >结果;
{aborted,Reason} - > {aborted,Reason}
catch
ErrorCl:Error - > {error,{ErrorCl,Error}}
end
end。

sc_store:替换,插入和查找如下:

  replace(Key,Value) - > 
try
case mnesia:wread({key_to_value,Key})
[#key_to_value {} = Rec] - >
mnesia:write(Rec#key_to_value {value = Value});
[] - >
{error,not_found}
end
catch
_Err:原因 - >
{error,Reason}
结束。

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:原因 - >
{error,Reason}
结束。

lookup(Key) - >
try
case mnesia:read(key_to_value,Key)
[#key_to_value {type = Type,scope = Scope,value = Value}] - >
{ok,{Value,Type,Scope}};
[] - >
{error,not_found}
end
catch
_Err:原因 - > {error,Reason}
结束。


解决方案

其实,事实证明问题是使用try / catch在一个交易内的运行内的运行。有关详情,请参阅此处


I have a 5 processes that insert/update the same 3 records in a mnesia table. Each of these processes does its insert/updates within a single transaction.

I have 5 other process that read these very same 3 records, also within a single transaction.

Unless I lock the entire table as part of the multi-record transaction, I get an {aborted, {cyclic, node....}} error. My intuition is that my use-case is ordinary and should not, in of itself, result in in an aborted transaction. Can someone help me with my bone-headed thinking? All I am doing is inserting (or reading) multiple rows in a cache (mnesia table) in one transaction.

Inserting the 3 records 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 lookup are is as follows:

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.

解决方案

Actually, turns out the problem was using try/catch around mnesia operations within a transaction. See here for more.

这篇关于Mnesia:意外地中止,循环交易的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆