[erlang-patches] Mnesia index becomes corrupted if deleting an nonexisting object

Bartłomiej Puzoń <>
Thu Jun 28 21:22:57 CEST 2012

Dear OTP team,

======= Description

Let's have the following record:
-record(r, {key,index,data}).

test()->                                                                                                                              mnesia:delete_table(r),
 mnesia:create_table(r, [{type, bag},
                         {attributes, record_info(fields,r)}]),            
 mnesia:add_table_index(r, index),

 %% Lets insert a random record to our table
 Record1 = #r{key = k, index = i, data = 1},
 mnesia:dirty_write(r, Record1),

 %% This should return [{r,k,i,1}] and it does
 mnesia:dirty_index_read(r, i, #r.index)

 %% Now lets try to delete something that is not in the table, but
 %% shares the same key and index
 Record2 = #r{key = k, index = i, data = 2},
 mnesia:dirty_delete_object(r, Record2),

 %% And now our big finale. This call, which is exactly the same
 %% as the previous index read, should give the same results
 mnesia:dirty_index_read(r, i, #r.index).
 %% BUT it returns [] instead. Somehow the index got changed even thoug
 %% we never touched the table itself

After a period of witch-hunting the culprit turned out to be hiding in mnesia_index:

119 del_object_bag(Tab, Key, Obj, Pos, Ixt, undefined) ->
120    IxKey = element(Pos, Obj),                                        
121    Old = [X || X <-  mnesia_lib:db_get(Tab, Key), element(Pos, X) =:= IxKey],
122    del_object_bag(Tab, Key, Obj, Pos, Ixt, Old);
123 %% If Tab type is bag we need remove index identifier if Tab
124 %% contains less than 2 elements.
125 del_object_bag(_Tab, Key, Obj, Pos, Ixt, Old) when length(Old) < 2 ->
126     del_ixes(Ixt, [Obj], Pos, Key);                                    
127 del_object_bag(_Tab, _Key, _Obj, _Pos, _Ixt, _Old) -> ok.

Our call to dirty_delete_object results in mnesia_index:del_object_bag being called as follows:
As you can see, the object we are deleting and the object that is in the table (last argument) are
different. However, mnesia_index still happily deletes the index.

======= Links
Github: bpuzon/otp, branch: fix_mnesia_index_drop
Git command: git fetch git://github.com/bpuzon/otp.git fix_mnesia_index_drop

Bartłomiej Puzoń
Erlang Solutions

More information about the erlang-patches mailing list