packages feed

acid-state-dist-0.1.0.0: test/OrderingRandom.hs

{-# LANGUAGE TypeFamilies #-}

import Data.Acid
import Data.Acid.Centered

import Control.Monad (when, forM_)
import Control.Concurrent (forkIO,threadDelay)
import Control.Concurrent.MVar (MVar, newEmptyMVar, putMVar, takeMVar, readMVar)
import System.Exit (exitSuccess, exitFailure)
import System.Directory (doesDirectoryExist, removeDirectoryRecursive)
import System.Random (mkStdGen, randomRs)

-- state structures
import NcCommon

-- helpers
delaySec :: Int -> IO ()
delaySec n = threadDelay $ n*1000*1000

cleanup :: FilePath -> IO ()
cleanup path = do
    sp <- doesDirectoryExist path
    when sp $ removeDirectoryRecursive path

-- actual test
randRange :: (Int,Int)
randRange = (100,100000)

numRands :: Int
numRands = 100

slave :: Int ->  MVar [Int] -> MVar () -> MVar () -> IO ()
slave ident res done alldone = do
    let rs = randomRs randRange $ mkStdGen ident :: [Int]
    acid <- enslaveStateFrom ("state/OrderingRandom/s" ++ show ident) "localhost" 3333 (NcState [])
    forM_ (take numRands rs) $ \r -> do
        threadDelay r
        update acid $ NcOpState r
    putMVar done ()
    -- wait for others
    _ <- readMVar alldone
    delaySec ident
    val <- query acid GetState
    putMVar res val
    print $ "slave quit ident " ++ show ident
    closeAcidState acid

main :: IO ()
main = do
    cleanup "state/OrderingRandom"
    acid <- openMasterStateFrom "state/OrderingRandom/m" "127.0.0.1" 3333 (NcState [])
    allDone <- newEmptyMVar
    -- start slaves
    s1Res <- newEmptyMVar
    s1Done <- newEmptyMVar
    _ <- forkIO $ slave 1 s1Res s1Done allDone
    threadDelay 1000 -- zmq-indentity could be the same if too fast
    s2Res <- newEmptyMVar
    s2Done <- newEmptyMVar
    _ <- forkIO $ slave 2 s2Res s2Done allDone
    -- manipulate state on master
    let rs = randomRs randRange $ mkStdGen 23 :: [Int]
    forM_ (take numRands rs) $ \r -> do
        threadDelay r
        update acid $ NcOpState r
    -- wait for slaves
    print "at wait"
    _ <- takeMVar s1Done
    _ <- takeMVar s2Done
    -- signal slaves done
    print "at done"
    putMVar allDone ()
    -- collect results
    print "at collect"
    vs1 <- takeMVar s1Res
    vs2 <- takeMVar s2Res
    vm <- query acid GetState
    -- check results
    print "at results"
    when (vs1 /= vs2) exitFailure
    when (vm /= vs1) exitFailure
    when (vm /= vs2) exitFailure
    closeAcidState acid
    exitSuccess