Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Erlang : Mnesia : Lookup and update based on fields other than the key

I have a table in mnesia and I need to update individual fields in the records in it. According to Erlang : Mnesia : Updating a single field value in a row if I do something like:

update_a(Tab, Key, Value) ->
  fun() ->
    [P] = mnesia:wread({Tab, Key}),
    mnesia:write(Tab, P#rec{a=Value}, write)
  end.

Now as I understand, the above code reads a record P based on a Key, acquiring a write lock on the record, so that no other transactions modify this record while it is being read and written back (or in short, updated). So far so good.

Now my requirement is that I need to able to read records based on both the Key and one other field in the table and then perform an update on it. A function that will do this looking up is mnesia:match_object. The problem now is that, the function only supports a read lock, not a write lock, according to http://www.erlang.org/doc/man/mnesia.html#match_object-3.

The consequence of this is that, suppose in the above function I were to use mnesia:match_object, I will get a (group of) record(s), all with read locks. After I read the records, I need to perform some checks on the retrieved data and then write back the updated record only if a condition is satisfied. Now, assume there are two parallel transactions T1 and T2 initiated by two different sources running. Both T1 and T2 access the same record, at the same time. Since they are read locked, both T1 and T2 will be able to read the records parallely. Both T1 and T2 will perform the same check on the same record, and if the condition matches, both will proceed to execute the update. But, in my code, if T1 and T2 were to have executed serially, T1 would have made changes to the record and in T2, it would have read these changed records and the condition would have failed and no update would have been made.

In short, I need to write lock records that are returned by mnesia:match_object. The documentation clearly states only read lock is supported. Are there are any alternatives?

UPDATE: I've been experimenting a little bit, and a possible solution I thought could be to use compound keys. Suppose I have data written to a table like:

mnesia:transaction(fun() -> mnesia:write(mytable, #rec{i={1,2}, a=2, b=3}, write) end).

Is there any way to lookup entries, using don't cares?

I tried these, but both returned empty results:

mnesia:transaction(fun()-> mnesia:read(mytable, {1,'_'}, read) end).
mnesia:transaction(fun()-> mnesia:read(mytable, {1,_}, read) end).
like image 531
ErJab Avatar asked Dec 01 '09 10:12

ErJab


1 Answers

Even though it returns them under a read lock, you can still update them with write afterwards. The whole read/wread thing was just an optimization.

You can use an ordered_set table to implement this mnesia-trick on compound keys.

like image 154
Christian Avatar answered Sep 21 '22 01:09

Christian