-- | Connection pool configuration.
module Arbiter.Core.PoolConfig
  ( PoolConfig (..)
  , defaultPoolConfig
  , poolConfigForWorkers
  ) where

import Control.Monad.IO.Class (MonadIO, liftIO)
import GHC.Conc (getNumCapabilities)

-- | Connection pool configuration.
data PoolConfig = PoolConfig
  { PoolConfig -> Int
poolSize :: Int
  -- ^ Maximum connections
  , PoolConfig -> Int
poolIdleTimeout :: Int
  -- ^ Idle timeout (seconds)
  , PoolConfig -> Maybe Int
poolStripes :: Maybe Int
  -- ^ Number of stripes (sub-pools). Reduces lock contention on connection checkout.
  --
  -- * @Nothing@: Auto-detect based on CPU count
  -- * @Just n@: Use n stripes
  }
  deriving stock (PoolConfig -> PoolConfig -> Bool
(PoolConfig -> PoolConfig -> Bool)
-> (PoolConfig -> PoolConfig -> Bool) -> Eq PoolConfig
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: PoolConfig -> PoolConfig -> Bool
== :: PoolConfig -> PoolConfig -> Bool
$c/= :: PoolConfig -> PoolConfig -> Bool
/= :: PoolConfig -> PoolConfig -> Bool
Eq, Int -> PoolConfig -> ShowS
[PoolConfig] -> ShowS
PoolConfig -> String
(Int -> PoolConfig -> ShowS)
-> (PoolConfig -> String)
-> ([PoolConfig] -> ShowS)
-> Show PoolConfig
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PoolConfig -> ShowS
showsPrec :: Int -> PoolConfig -> ShowS
$cshow :: PoolConfig -> String
show :: PoolConfig -> String
$cshowList :: [PoolConfig] -> ShowS
showList :: [PoolConfig] -> ShowS
Show)

-- | Default pool configuration: 10 connections, 300s idle timeout, 1 stripe.
--
-- Conservative defaults suitable for producer-only workloads. For worker pools,
-- use 'poolConfigForWorkers' to size the pool based on worker count.
defaultPoolConfig :: PoolConfig
defaultPoolConfig :: PoolConfig
defaultPoolConfig =
  PoolConfig
    { poolSize :: Int
poolSize = Int
10
    , poolIdleTimeout :: Int
poolIdleTimeout = Int
300
    , poolStripes :: Maybe Int
poolStripes = Int -> Maybe Int
forall a. a -> Maybe a
Just Int
1
    }

-- | Creates a pool configuration sized for a worker pool.
--
-- Sizing: @workerCount + 5@ connections (worker threads plus headroom for
-- dispatcher and heartbeats). Stripes set to min(capabilities, poolSize).
poolConfigForWorkers :: (MonadIO m) => Int -> m PoolConfig
poolConfigForWorkers :: forall (m :: * -> *). MonadIO m => Int -> m PoolConfig
poolConfigForWorkers Int
workerCnt = do
  caps <- IO Int -> m Int
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO Int
getNumCapabilities
  let size = Int
workerCnt Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
5
  -- Ensure stripes doesn't exceed pool size (resource-pool requirement)
  let stripes = Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
caps Int
size
  pure
    PoolConfig
      { poolSize = size
      , poolIdleTimeout = 300
      , poolStripes = Just stripes
      }