<div dir="ltr">Ah, apologies, I missed this the first time around. Glad it helped.<div><br></div><div>Cheers,</div><div><br></div><div>David</div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On 31 July 2015 at 19:12, Michael Schröder <span dir="ltr"><<a href="mailto:mc.schroeder@gmail.com" target="_blank">mc.schroeder@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Ah, of course you're right, I forgot that masking /= completely uninterruptible. And yes, it does seem like the finalizer needs to be masked by default, in order to prevent the kind of race condition you describe. Should be an easy change. Thanks for pointing that out!<br></div><div class="HOEnZb"><div class="h5"><div class="gmail_extra"><br><div class="gmail_quote">On 31 July 2015 at 15:06, David Turner <span dir="ltr"><<a href="mailto:dct25-561bs@mythic-beasts.com" target="_blank">dct25-561bs@mythic-beasts.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Hi Michael,<div><br></div><div>I wholeheartedly agreed that <span style="font-family:monospace,monospace">timeout n $ atomicallyWithIO ...</span><font face="arial, helvetica, sans-serif"> is important, but that would generally work even if the finalizer ran masked wouldn't it? Most actions that block are interruptible.</font></div><div><font face="arial, helvetica, sans-serif"><br></font></div><div><font face="arial, helvetica, sans-serif">Put another way, I'd be interested to see how you could make </font><span style="font-family:monospace,monospace">serialize</span><font face="arial, helvetica, sans-serif"> safe without this. Something like this:</font></div><div><span style="font-family:monospace,monospace"><br></span></div><div><span><div><font face="monospace, monospace">serialize :: [Operation d] -> DatabaseHandle d -> IO ()</font></div><div><font face="monospace, monospace">serialize ops (DatabaseHandle _ h) =</font></div><div><font face="monospace, monospace"> withMVar h (\h -> forM_ ops $ B.hPut h . runPut . safePut)</font></div></span><div><font face="monospace, monospace"> `onException`</font></div><div><font face="monospace, monospace"> magicalFileRollback h</font></div></div><div><font face="monospace, monospace"><br></font></div><div><font face="arial, helvetica, sans-serif">(ignoring the tedious implementation of </font><span style="font-family:monospace,monospace">magicalFileRollback</span><span style="font-family:arial,helvetica,sans-serif">) doesn't look quite right as if you got an async exception in the tiny window between </span><span style="font-family:monospace,monospace">onException</span><span style="font-family:arial,helvetica,sans-serif"> exiting and </span><span style="font-family:monospace,monospace">serialize</span><span style="font-family:arial,helvetica,sans-serif"> exiting then the STM transaction would roll back but the file wouldn't. I'm not convinced I totally understand async exceptions so if you (or anyone else) can point out why this works I'd be very grateful.</span></div><div><span style="font-family:arial,helvetica,sans-serif"><br></span></div><div><span style="font-family:arial,helvetica,sans-serif">Cheers,</span></div><div><span style="font-family:arial,helvetica,sans-serif"><br></span></div><div><span style="font-family:arial,helvetica,sans-serif">David</span></div><div><span style="font-family:arial,helvetica,sans-serif"><br></span></div><div><span style="font-family:arial,helvetica,sans-serif"><br></span></div><div><span style="font-family:monospace,monospace"><br></span></div><div><span style="font-family:monospace,monospace"><br></span></div><div class="gmail_extra"><div class="gmail_quote"><div><div>On 31 July 2015 at 13:18, Michael Schröder <span dir="ltr"><<a href="mailto:mc.schroeder@gmail.com" target="_blank">mc.schroeder@gmail.com</a>></span> wrote:<br></div></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div><div dir="ltr"><div class="gmail_extra">Hi David, I appreciate your interest in my thesis!</div><div class="gmail_extra"><br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div>A finalizer which has non-atomic real-world effects needs to be quite careful about undoing those effects when exceptions are thrown. [...] If some of those <font face="monospace, monospace">B.hPut</font> calls succeed but then one fails (e.g. the disk is full) then the transaction will be rolled back, but the on-disk state will be left partially written. </div></blockquote><div><br></div><div>Yes, you are absolutely right! The example application lacks some of the safeguards one would expect in a production-ready system. It was intended to be more of a demonstration of how easily one can in principle build a database-like system on top of STM using finalizers. It still requires some engineering effort to make it entirely safe and practical. I should have documented this better—or just gone the extra mile and actually made it safe!<br></div><span><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div>Even if the finalizer did include exception handling to deal with this situation, what happens with asynchronous exceptions? Does the finalizer run with async exceptions masked? </div></blockquote><div><br></div></span><div>The finalizer does not run with async exceptions masked and you're right that one needs to be careful about how to deal with side-effects & async exceptions & cleanup within the finalizer—just like with any kind of I/O, really. In the TX example code, <font face="monospace, monospace">serialize</font> should probably use <font face="monospace, monospace">withMVarMasked</font> instead of <font face="monospace, monospace">withMVar</font>. But I don't think the finalizer should run with async exceptions masked by default. There are uses cases where you really do want the finalizer to be interruptible from another thread, e.g. if you want to be able to timeout the whole transaction (STM part + finalizer part, as in: <font face="monospace, monospace">timeout n $ atomicallyWithIO ...</font>)</div></div><br></div></div>
<br></div></div><span>_______________________________________________<br>
Haskell-Cafe mailing list<br>
<a href="mailto:Haskell-Cafe@haskell.org" target="_blank">Haskell-Cafe@haskell.org</a><br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" rel="noreferrer" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a><br>
<br></span></blockquote></div><br></div></div>
</blockquote></div><br></div>
</div></div><br>_______________________________________________<br>
Haskell-Cafe mailing list<br>
<a href="mailto:Haskell-Cafe@haskell.org">Haskell-Cafe@haskell.org</a><br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" rel="noreferrer" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a><br>
<br></blockquote></div><br></div>