Copyright | (c) 2011 MailRank, Inc. |
---|---|
License | BSD3 |
Maintainer | Bryan O'Sullivan <bos@serpentine.com>, Bas van Dijk <v.dijk.bas@gmail.com> |
Stability | experimental |
Portability | portable |
Safe Haskell | None |
Language | Haskell98 |
A high-performance striped pooling abstraction for managing flexibly-sized collections of resources such as database connections.
"Striped" means that a single Pool
consists of several
sub-pools, each managed independently. A single stripe is fine for
many applications, and probably what you should choose by default.
More stripes will lead to reduced contention in high-performance
multicore applications, at a trade-off of causing the maximum
number of simultaneous resources in use to grow.
- data Pool a
- data LocalPool a
- createPool :: IO a -> (a -> IO ()) -> Int -> NominalDiffTime -> Int -> IO (Pool a)
- withResource :: MonadBaseControl IO m => Pool a -> (a -> m b) -> m b
- takeResource :: Pool a -> IO (a, LocalPool a)
- tryWithResource :: forall m a b. MonadBaseControl IO m => Pool a -> (a -> m b) -> m (Maybe b)
- tryTakeResource :: Pool a -> IO (Maybe (a, LocalPool a))
- destroyResource :: Pool a -> LocalPool a -> a -> IO ()
- putResource :: LocalPool a -> a -> IO ()
- destroyAllResources :: Pool a -> IO ()
Documentation
:: IO a | Action that creates a new resource. |
-> (a -> IO ()) | Action that destroys an existing resource. |
-> Int | The number of stripes (distinct sub-pools) to maintain. The smallest acceptable value is 1. |
-> NominalDiffTime | Amount of time for which an unused resource is kept open. The smallest acceptable value is 0.5 seconds. The elapsed time before destroying a resource may be a little longer than requested, as the reaper thread wakes at 1-second intervals. |
-> Int | Maximum number of resources to keep open per stripe. The smallest acceptable value is 1. Requests for resources will block if this limit is reached on a single stripe, even if other stripes have idle resources available. |
-> IO (Pool a) |
Create a striped resource pool.
Although the garbage collector will destroy all idle resources when
the pool is garbage collected it's recommended to manually
destroyAllResources
when you're done with the pool so that the
resources are freed up as soon as possible.
withResource :: MonadBaseControl IO m => Pool a -> (a -> m b) -> m b Source
Temporarily take a resource from a Pool
, perform an action with
it, and return it to the pool afterwards.
- If the pool has an idle resource available, it is used immediately.
- Otherwise, if the maximum number of resources has not yet been reached, a new resource is created and used.
- If the maximum number of resources has been reached, this function blocks until a resource becomes available.
If the action throws an exception of any type, the resource is destroyed, and not returned to the pool.
It probably goes without saying that you should never manually destroy a pooled resource, as doing so will almost certainly cause a subsequent user (who expects the resource to be valid) to throw an exception.
takeResource :: Pool a -> IO (a, LocalPool a) Source
Take a resource from the pool, following the same results as
withResource
. Note that this function should be used with caution, as
improper exception handling can lead to leaked resources.
This function returns both a resource and the LocalPool
it came from so
that it may either be destroyed (via destroyResource
) or returned to the
pool (via putResource
).
tryWithResource :: forall m a b. MonadBaseControl IO m => Pool a -> (a -> m b) -> m (Maybe b) Source
Similar to withResource
, but only performs the action if a resource could
be taken from the pool without blocking. Otherwise, tryWithResource
returns immediately with Nothing
(ie. the action function is not called).
Conversely, if a resource can be borrowed from the pool without blocking, the
action is performed and it's result is returned, wrapped in a Just
.
tryTakeResource :: Pool a -> IO (Maybe (a, LocalPool a)) Source
A non-blocking version of takeResource
. The tryTakeResource
function
returns immediately, with Nothing
if the pool is exhausted, or
if a resource could be borrowed from the pool successfully.Just
(a,
LocalPool
a)
destroyResource :: Pool a -> LocalPool a -> a -> IO () Source
Destroy a resource. Note that this will ignore any exceptions in the destroy function.
putResource :: LocalPool a -> a -> IO () Source
Return a resource to the given LocalPool
.
destroyAllResources :: Pool a -> IO () Source
Destroy all resources in all stripes in the pool. Note that this will ignore any exceptions in the destroy function.
This function is useful when you detect that all resources in the
pool are broken. For example after a database has been restarted
all connections opened before the restart will be broken. In that
case it's better to close those connections so that takeResource
won't take a broken connection from the pool but will open a new
connection instead.
Another use-case for this function is that when you know you are done with the pool you can destroy all idle resources immediately instead of waiting on the garbage collector to destroy them, thus freeing up those resources sooner.