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.