[erlang-questions] (not) understanding mnesia transactions

Dan Gudmundsson dgud@REDACTED
Thu Jun 18 12:05:53 CEST 2009


The problem here lies in how mnesia handles indexes and locks on indexes.

If you remove the index the code works as expected.
Except for io:format("Expecting ~p~n", [lists:seq(1, 10)]), which is wrong,
since you use dirty_update_counter which will be invoked
several times when there is a lock conflict on the write lock.

But back to the index lock problem.

Whether you use qlc or index_read in that query the same code will be invoked.

mnesia:index_read grabs a read lock on the rows it hits.
In your case when 5 parallel processes read the index for "url-1"
none is found, no locks are grabbed.

You then generate a unique key for each process, and write the record down,
that will succeed since they have unique keys.

This is bug in mnesia, 12 years old :-(

/Dan

Seth Falcon wrote:
> Chandru,
> 
> Thanks for the explanation.
> 
> * On 2009-06-17 at 23:57 +0100 Chandru wrote:
>> Your code works as you expect it to if you first acquire a write
>> lock on the table before you read from it.
> 
> Yes, that seems to fix it.
> 
>> So all your clients acquire read locks, decide that a record for a URL does
>> not exist, and create a record. I'm not sure what locks are acquired for
>> records which do not exist. I'm sure the answer lies in reading the mnesia
>> source code...
> 
> Makes some sense.  I guess the big piece that I was missing is that
> transactions can run concurrently and the programmer needs to manage
> the locking.  A more subtle point, is that the locking mechanism is
> such that once a lock is aquired it is kept for the remainder of the
> transaction (I think).
> 
> So in the following example from the mnesia man page, the call to
> mnesia:wread has the same effect as calling mnesia:lock and then
> mnesia:read.
> 
>    raise(Name, Amount) ->
>                   mnesia:transaction(fun() ->
>                       case mnesia:wread({person, Name}) of
>                           [P] ->
>                               Salary = Amount + P#person.salary,
>                               P2 = P#person{salary = Salary},
>                               mnesia:write(P2);
>                           _ ->
>                               mnesia:abort("No such person")
>                       end
>                   end).
> 
> 
> ________________________________________________________________
> erlang-questions mailing list. See http://www.erlang.org/faq.html
> erlang-questions (at) erlang.org
> 


More information about the erlang-questions mailing list