[Haskell-cafe] STM Finalizers
dct25-561bs at mythic-beasts.com
Tue Aug 4 14:38:43 UTC 2015
Ah, apologies, I missed this the first time around. Glad it helped.
On 31 July 2015 at 19:12, Michael Schröder <mc.schroeder at gmail.com> wrote:
> 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>
>> 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)
>> 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.
>> On 31 July 2015 at 13:18, Michael Schröder <mc.schroeder at gmail.com>
>>> 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
>>>> 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
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the Haskell-Cafe