memcache-0.1.0.0: Database/Memcache/Server.hs
-- | Handles the connections between a memcache client and a single server.
module Database.Memcache.Server (
Server(sid), newServer, sendRecv, withSocket, close
) where
import Database.Memcache.SASL
import Database.Memcache.Types
import Database.Memcache.Wire
import Control.Exception
import Data.Hashable
import Data.Pool
import Data.Time.Clock (NominalDiffTime)
import Network.BSD (getProtocolNumber, getHostByName, hostAddress)
import Network.Socket (HostName, PortNumber(..), Socket)
import qualified Network.Socket as S
-- Connection pool constants.
-- TODO: make configurable
sSTRIPES, sCONNECTIONS :: Int
sKEEPALIVE :: NominalDiffTime
sSTRIPES = 1
sCONNECTIONS = 1
sKEEPALIVE = 300
-- | A memcached server connection.
data Server = Server {
sid :: {-# UNPACK #-} !Int,
pool :: Pool Socket,
_addr :: !HostName,
_port :: !PortNumber,
_auth :: !Authentication,
failed :: !Bool
-- TODO:
-- weight :: Double
-- tansport :: Transport (UDP vs. TCP)
-- poolLim :: Int (pooled connection limit)
-- cnxnBuf :: IORef ByteString
} deriving Show
instance Eq Server where
(==) x y = sid x == sid y
instance Ord Server where
compare x y = compare (sid x) (sid y)
-- | Create a new memcached connection.
newServer :: HostName -> PortNumber -> Authentication -> IO Server
newServer host port auth = do
pSock <- createPool connectSocket releaseSocket
sSTRIPES sKEEPALIVE sCONNECTIONS
return Server
{ sid = serverHash
, pool = pSock
, _addr = host
, _port = port
, _auth = auth
, failed = False
}
where
serverHash = hash (host, fromEnum port)
connectSocket = do
proto <- getProtocolNumber "tcp"
bracketOnError
(S.socket S.AF_INET S.Stream proto)
releaseSocket
(\s -> do
h <- getHostByName host
S.connect s (S.SockAddrInet port $ hostAddress h)
S.setSocketOption s S.KeepAlive 1
S.setSocketOption s S.NoDelay 1
authenticate s auth
return s
)
releaseSocket = S.close
-- | Send and receive a single request/response pair to the memcached server.
sendRecv :: Server -> Request -> IO Response
sendRecv svr msg = withResource (pool svr) $ \s -> do
send s msg
recv s
-- | Run a function with access to an server socket for using 'send' and
-- 'recv'.
withSocket :: Server -> (Socket -> IO a) -> IO a
withSocket svr = withResource $ pool svr
-- | Close the server connection. If you perform another operation after this,
-- the connection will be re-established.
close :: Server -> IO ()
close srv = destroyAllResources $ pool srv