[Haskell-cafe] Replacing RDMS - global lock and STM preventing
retrying?
Mads Lindstrøm
mads_lindstroem at yahoo.dk
Sat Apr 26 10:22:48 EDT 2008
Hi
Marc Weber wrote:
> What would be the right way to go to replace RDBMS (postgres/ mysql) etc
> using haskell only for small to medium sized (web)applications?
> I guess one way to go is using STM.
> But what happens if you have some tables each row represented as TVar
> and you'd like to do a full backup? Some occasionally occuring updates
> on single rows will make the atomic action get all rows and write them
> to disk retry again and again? Is there a way to make the update action
> retry in this case?
> And then you can implement something like: Try it 20 times, if the aciton
> doesn't succeed aquire global lock ! Wow.
>
> Has anyone already implemented such a RDBMS replacement?
Have you looked at http://happs.org/ ?
Their HappS-State seems somewhat similar to what you are proposing.
> Anyone interested in working on this?
>
> Marc Weber
Another question is why do you want to we replace RDBMS-es?
Greetings,
Mads Lindstrøm
>
> One solution I came up within minutes :) I love haskell. You write it
> down fix error and it works :)
> Would you prefer another way to solve this?
>
> --packages: containers, binary, stm, mtl, random
> module Main where
> import System.IO.Unsafe
> import Random
> import Control.Concurrent
> import Control.Monad
> import Control.Concurrent.STM
> import Control.Monad.Trans
>
> -- running count of actions. if set to -1 a transaction has aquired global lock
> globalLock = unsafePerformIO $ newTVarIO (0::Int)
>
> modifyTVar tvar f = do
> v <- readTVar tvar
> writeTVar tvar $ f v
>
> -- of course this should be in it's own monad to force using this function
> -- myAtomically: aquires global lock
> -- of course I don't need 5 atomically calls, but this way an action will not be retried if only the global count changes
> myAtomically aquireGlobalLock stmAction =
> if aquireGlobalLock
> then do
> atomically $ do
> runningCount <- readTVar globalLock
> when (runningCount /= 0) retry
> writeTVar globalLock (negate 1)
> -- other actions should be retrying
> atomically $ do
> stmAction
> writeTVar globalLock 0
> else do
> atomically $ do
> runningCount <- readTVar globalLock
> when (runningCount == (negate 1)) retry
> modifyTVar globalLock (+1)
> atomically stmAction
> atomically $ modifyTVar globalLock (\x -> x -1)
>
> -- log utility printing start / stop of an action
> stsp :: (MonadIO m) => String -> m r -> m r
> stsp msg act = do
> liftIO $ putStrLn $ "start: " ++ msg
> r <- act
> liftIO $ putStrLn $ "stop: " ++ msg
> return r
>
> data Table rec = Table { table :: [TVar rec] }
>
> newTable rowcount = liftM Table $ mapM newTVarIO [(1::Int)..rowcount]
>
> dumpTable fn t = do
> dat <- myAtomically True $ mapM readTVar $ table t
> writeFile fn $ show dat
>
> disturb t@(Table (row:_)) = do
> stsp "disturbing" $ do
> v <- randomRIO (0,1000000)
> myAtomically False $ writeTVar row v
> threadDelay 1000000
> disturb t -- loop
>
> main = do
> stsp "application" $ do
> table <- newTable 100000
> forkIO $ disturb table
> stsp "dumping" $ dumpTable "dump" table
>
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
More information about the Haskell-Cafe
mailing list