[Haskell-cafe] STM Finalizers

Michael Schröder mc.schroeder at gmail.com
Fri Jul 31 18:12:24 UTC 2015


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!

On 31 July 2015 at 15:06, David Turner <dct25-561bs at mythic-beasts.com>
wrote:

> Hi Michael,
>
> I wholeheartedly agreed that timeout n $ atomicallyWithIO ... is
> important, but that would generally work even if the finalizer ran masked
> wouldn't it? Most actions that block are interruptible.
>
> Put another way, I'd be interested to see how you could make serialize safe
> without this. Something like this:
>
> serialize :: [Operation d] -> DatabaseHandle d -> IO ()
> serialize ops (DatabaseHandle _ h) =
>     withMVar h (\h -> forM_ ops $ B.hPut h . runPut . safePut)
>   `onException`
>     magicalFileRollback h
>
> (ignoring the tedious implementation of magicalFileRollback) doesn't look
> quite right as if you got an async exception in the tiny window between
> onException exiting and serialize 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.
>
> Cheers,
>
> David
>
>
>
>
> On 31 July 2015 at 13:18, Michael Schröder <mc.schroeder at gmail.com> wrote:
>
>> Hi David, I appreciate your interest in my thesis!
>>
>> 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 B.hPut 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.
>>>
>>
>> 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!
>>
>>
>>> 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?
>>>
>>
>> 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, serialize should probably use
>> withMVarMasked instead of withMVar. 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: timeout n $ atomicallyWithIO ...)
>>
>>
>> _______________________________________________
>> Haskell-Cafe mailing list
>> Haskell-Cafe at haskell.org
>> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20150731/b244ed05/attachment.html>


More information about the Haskell-Cafe mailing list