<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META content="text/html; charset=iso-8859-1" http-equiv=Content-Type>
<META name=GENERATOR content="MSHTML 8.00.6001.18943">
<STYLE></STYLE>
</HEAD>
<BODY>
<DIV><FONT size=2 face="Courier New">QuickChecking dets has turned up another 
race condition (this one found by the Chalmers ProTest team).</FONT></DIV>
<DIV><FONT size=2 face="Courier New"></FONT> </DIV>
<DIV><FONT size=2 face="Courier New">Calling open_file in one process can cause 
another process using the same table to see an inconsistent view of the data. 
The simplest example is illustrated by</FONT></DIV>
<DIV><FONT size=2 face="Courier New"></FONT> </DIV>
<DIV><FONT size=2 face="Courier New">bug1a() -><BR>    
dets:close(dets_table),<BR>    
file:delete(dets_table),<BR>    {ok,T} = 
dets:open_file(dets_table,[{type,bag}]),<BR>    spawn(fun() -> 
dets:open_file(dets_table,[{type,bag}]) end),<BR>    spawn(fun() 
-><BR>          
dets:insert(dets_table,[{0,0}]),<BR>          
io:format("~p\n",[get_contents(dets_table)])<BR>    
end).</FONT></DIV>
<DIV><FONT size=2 face="Courier New"></FONT> </DIV>
<DIV><FONT size=2 face="Courier New">which should always print [{0,0}], but 
sometimes prints []. get_contents just fetches the entire table 
contents:</FONT></DIV>
<DIV><FONT size=2 face="Courier New"></FONT> </DIV>
<DIV><FONT size=2 face="Courier New">get_contents(Name) 
-><BR>    
dets:traverse(Name,fun(X)->{continue,X}end).</FONT></DIV>
<DIV><FONT size=2 face="Courier New"></FONT> </DIV>
<DIV><FONT size=2 face="Courier New">Since the insertion and the traversal occur 
in the SAME process, one would expect the traversal to see the inserted data... 
but it doesn't always.</FONT></DIV>
<DIV><FONT size=2 face="Courier New"></FONT> </DIV>
<DIV><FONT size=2 face="Courier New">Presumably the same bug is visible in this 
example, where the change that's lost is a deletion instead:</FONT></DIV>
<DIV><FONT size=2 face="Courier New"></FONT> </DIV>
<DIV><FONT size=2 face="Courier New">bug1b() -><BR>    
dets:close(dets_table),<BR>    
file:delete(dets_table),<BR>    {ok,T} = 
dets:open_file(dets_table,[{type,bag}]),<BR>    
dets:insert(dets_table,{7,0}),<BR>    spawn(fun() -> 
dets:open_file(dets_table,[{type,bag}]) end),<BR>    spawn(fun() 
-><BR>          
dets:delete(dets_table,7),<BR>          
io:format("~p\n",[get_contents(dets_table)])<BR>    
end).</FONT></DIV>
<DIV><FONT size=2 face="Courier New"></FONT> </DIV>
<DIV><FONT size=2 face="Courier New">which should always print [], but sometimes 
prints [{7,0}].</FONT></DIV>
<DIV><FONT size=2 face="Courier New"></FONT> </DIV>
<DIV><FONT size=2 face=Arial><FONT face="Courier New">These examples do fail, 
but I'm afraid they fail pretty rarely--in the nature of race conditions, I 
suppose. It's a lot easier to provoke the failures with QuickCheck than by 
running bug1a and bug1b, because they have to be run so many times.</FONT> 
<FONT face="Courier New">When running them repeatedly, you also need to worry 
about one test case overlapping with the next. Here's a version of bug1a() with 
enough synchronization to prevent that:</FONT></FONT></DIV>
<DIV><FONT size=2 face="Courier New"></FONT> </DIV>
<DIV><FONT size=2 face="Courier New">bug1c() -><BR>    Self = 
self(),<BR>    spawn(fun() 
-><BR>           
[dets:close(dets_table) || _ <- 
"abcdefghijkl"],<BR>            file:delete(dets_table),<BR>            
Parent = 
self(),<BR>            
{ok,T} = 
dets:open_file(dets_table,[{type,bag}]),<BR>            
spawn(fun() -> 
dets:open_file(dets_table,[{type,bag}]),<BR>                           
Parent ! 
done<BR>                  
end),<BR>            spawn(fun() 
-><BR>                           
dets:insert(dets_table,[{0,0}]),<BR>                           io:format("~p\n",[get_contents(dets_table)]),<BR>                           
Parent ! 
done<BR>                  
end),<BR>            
receive done -> receive done -> ok end 
end,<BR>            Self 
! ok<BR>           
end),<BR>    receive ok -> ok end.</FONT></DIV>
<DIV><FONT size=2 face="Courier New"></FONT> </DIV>
<DIV><FONT size=2 face="Courier New">Running this 1,000 times will print [] a 
few times, revealing the bug.</FONT></DIV>
<DIV><FONT size=2 face="Courier New"></FONT> </DIV>
<DIV><FONT size=2 face="Courier New">Alternatively, compiling the attached file 
with options {d,'BUG_OPEN_FILE',true} and running QuickCheck on prop_parallel() 
provokes the bug within a few hundred tests. This needs the latest version of 
QuickCheck, 1.22, for the latest race condition testing code.</FONT></DIV>
<DIV><FONT size=2 face="Courier New"></FONT> </DIV>
<DIV><FONT size=2 face="Courier New">John</FONT></DIV></BODY></HTML>