<!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>