packages feed

pool 0.0.0 → 0.0.1

raw patch · 2 files changed

+56/−27 lines, 2 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Data.Pool: createPoolCheckAlive :: (MonadIO m, MonadPeelIO m) => IO a -> (a -> IO ()) -> Int -> (Pool a -> m b) -> (a -> IO Bool) -> m b
+ Data.Pool: withPoolAllocate :: MonadPeelIO m => Pool a -> (a -> m b) -> m b

Files

Data/Pool.hs view
@@ -3,18 +3,19 @@ module Data.Pool     ( -- * Using pools       createPool+    , createPoolCheckAlive     , withPool     , withPool'+    , withPoolAllocate     , Pool       -- * Diagnostics     , PoolStats (..)     , poolStats     ) where -import Control.Concurrent.STM (atomically)-import Control.Concurrent.STM.TVar-    (TVar, newTVarIO, readTVar, writeTVar)+import Data.IORef (IORef, newIORef, atomicModifyIORef, readIORef) import Control.Exception (throwIO, Exception)+import qualified Control.Exception as E import Data.Typeable import qualified Control.Monad.IO.Peel as I import qualified Control.Exception.Peel as I@@ -28,8 +29,10 @@  data Pool a = Pool     { poolMax :: Int-    , poolData :: TVar (PoolData a)+    , poolData :: IORef (PoolData a)     , poolMake :: IO a+    , poolFree :: a -> IO ()+    , poolCheckAlive :: a -> IO Bool     }  data PoolStats = PoolStats@@ -39,22 +42,31 @@     }  poolStats :: Pool a -> IO PoolStats-poolStats (Pool m td _) = do-    d <- atomically $ readTVar td-    return $ PoolStats m (length $ poolAvail d) (poolCreated d)+poolStats p = do+    d <- readIORef $ poolData p+    return $ PoolStats (poolMax p) (length $ poolAvail d) (poolCreated d)  createPool :: (MonadIO m, I.MonadPeelIO m)            => IO a -> (a -> IO ()) -> Int -> (Pool a -> m b) -> m b-createPool mk fr mx f = do-    pd <- liftIO $ newTVarIO $ PoolData [] 0-    I.finally (f $ Pool mx pd mk) $ liftIO $ do-        PoolData ress _ <- atomically $ readTVar pd+createPool mk fr mx f = createPoolCheckAlive mk fr mx f $ const $ return True++createPoolCheckAlive+    :: (MonadIO m, I.MonadPeelIO m)+    => IO a -> (a -> IO ()) -> Int -> (Pool a -> m b)+    -> (a -> IO Bool) -- ^ is the resource alive?+    -> m b+createPoolCheckAlive mk fr mx f ca = do+    pd <- liftIO $ newIORef $ PoolData [] 0+    I.finally (f $ Pool mx pd mk fr ca) $ liftIO $ do+        PoolData ress _ <- readIORef pd         mapM_ fr ress  data PoolExhaustedException = PoolExhaustedException     deriving (Show, Typeable) instance Exception PoolExhaustedException +-- | This function throws a 'PoolExhaustedException' when no resources are+-- available. See 'withPoolAllocate' to avoid this. withPool' :: (MonadIO m, I.MonadPeelIO m) => Pool a -> (a -> m b) -> m b withPool' p f = do     x <- withPool p f@@ -62,17 +74,27 @@         Nothing -> liftIO $ throwIO PoolExhaustedException         Just x' -> return x' +-- | Same as @withPool'@, but instead of throwing a 'PoolExhaustedException'+-- when there the maximum number of resources are created and allocated, it+-- allocates a new resource, passes it to the subprocess and then frees it.+withPoolAllocate :: I.MonadPeelIO m => Pool a -> (a -> m b) -> m b+withPoolAllocate p f = do+    x <- withPool p f+    case x of+        Just x' -> return x'+        Nothing ->+            I.bracket+                (liftIO $ poolMake p)+                (liftIO . poolFree p)+                f+ withPool :: (MonadIO m, I.MonadPeelIO m)          => Pool a -> (a -> m b) -> m (Maybe b) withPool p f = I.block $ do-    eres <- liftIO $ atomically $ do-        pd <- readTVar $ poolData p-        let (pd', eres) =-                case poolAvail pd of-                    (x:xs) -> (pd { poolAvail = xs }, Right x)-                    [] -> (pd, Left $ poolCreated pd)-        writeTVar (poolData p) pd'-        return eres+    eres <- liftIO $ atomicModifyIORef (poolData p) $ \pd ->+        case poolAvail pd of+            x:xs -> (pd { poolAvail = xs }, Right x)+            [] -> (pd, Left $ poolCreated pd)     case eres of         Left pc ->             if pc >= poolMax p@@ -81,13 +103,20 @@                     (liftIO $ poolMake p)                     (insertResource 1)                     (liftM Just . I.unblock . f)-        Right res -> I.finally+        Right res -> do+            isAlive <- liftIO $ E.try $ E.unblock $ poolCheckAlive p res+            case isAlive :: Either E.SomeException Bool of+                Right True ->+                    I.finally                         (liftM Just $ I.unblock $ f res)                         (insertResource 0 res)+                _ -> do+                    -- decrement the poolCreated count and then start over+                    liftIO $ atomicModifyIORef (poolData p) $ \pd ->+                        (pd { poolCreated = poolCreated pd - 1}, ())+                    I.unblock $ withPool p f   where-    insertResource i x = liftIO $ atomically $ do-        pd <- readTVar $ poolData p-        writeTVar (poolData p)-            pd { poolAvail = x : poolAvail pd-               , poolCreated = i + poolCreated pd-               }+    insertResource i x = liftIO $ atomicModifyIORef (poolData p) $ \pd ->+        (pd { poolAvail = x : poolAvail pd+                , poolCreated = i + poolCreated pd+                }, ())
pool.cabal view
@@ -1,5 +1,5 @@ name:            pool-version:         0.0.0+version:         0.0.1 license:         BSD3 license-file:    LICENSE author:          Michael Snoyman <michael@snoyman.com>