[Haskell-cafe] Re: STM, IO and b-trees

ChrisK haskell at list.mightyreason.com
Tue Aug 21 20:39:26 EDT 2007

Thomas Conway wrote:
> 2. Separate the IO from the BTree-stuff.
> Conceptually keep a <code>TVar (Map Address ByteString)</code>. In the
> transaction, use this to find pages. If the page is not there, throw
> an exception containing the desired address. In a wrapper, catch the
> exception, read the page, add it to the map as a separate transaction
> then retry the original transaction. I say "conceptually" because
> something like <code>TArray Address (Maybe ByteString)</code>, or
> similar will yield much better concurrency. In general, you want to
> push the TVars down as far as possible.

This type of idea has been discussed before, see [1].  This lead to the AdvSTM
monad at [2].  The "Helper Thread Code" on that page provides

> newtype AdvSTM a = AdvSTM (ReaderT Env STM a) deriving (Functor,Monad,MonadPlus,Typeable)
> type Env = (CommitVar,RetryVar)
> type CommitVar = TVar (IO ()->IO ())
> type RetryVar = MVar (IO ()->IO ())

and MonadAdvancedSTM which gives onCommit and onRetry.

> class MonadAdvSTM m where
>   onCommit :: IO a -> m ()
>   onRetry :: IO a -> m ()

Any IO action passed to onCommit is scheduled to run if and and only if the
current atomic attempt succeeds.  This is the easy part and if that is all you
need then the "Just onCommit" section on [2] is much simpler.

Thus (orElseAdv fails works >> alsoWorks) will run all onCommit actions posted
by works and alsoWorks but will not run any onCommit actions posted by the
'fails' piece (because when fails retries it will be rolled back and the change
to the TVar will not be seen).

The onRetry is sneakier and uses unsafeIOToSTM to put the scheduled action into
a private MVar.  The runAdvSTM uses a final orElse to detect when the whole
action will retry and again uses unsafeIOToSTM to send the scheduled onRetry
actions to the (perhaps newly spawned) helper thread before the retry.

Thus (orElseAdv fails works >> alsoFails) will run all onRetry action posted by
any of the three pieces fails, works, and alsoFails.   The private MVar cannot
be replaced with a private TVar since the 'fails' piece gets rolled back before
running 'works'.

Exception handling needs to be improved (e.g. bracket or finally in the retry
helper thread and the ensure writeChan chan Nothing gets called if needed, etc.).

> 3. Have Fun
> STM is very cool, so make sure you enjoy making it all hang together. :-)

[1] http://www.haskell.org/pipermail/haskell-cafe/2006-November/019771.html
[2] http://haskell.org/haskellwiki/New_monads/MonadAdvSTM

More information about the Haskell-Cafe mailing list