{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
module Network.TLS.SessionManager (
Config(..)
, defaultConfig
, newSessionManager
) where
import Basement.Block (Block)
import Data.ByteArray (convert)
import Control.Exception (assert)
import Control.Reaper
import Data.ByteString (ByteString)
import Data.IORef
import Data.OrdPSQ (OrdPSQ)
import qualified Data.OrdPSQ as Q
import Network.TLS
#if !MIN_VERSION_tls(1,5,0)
import Network.TLS.Compression
#endif
import qualified System.Clock as C
import Network.TLS.Imports
data Config = Config {
Config -> Int
ticketLifetime :: !Int
, Config -> Int
pruningDelay :: !Int
, Config -> Int
dbMaxSize :: !Int
}
defaultConfig :: Config
defaultConfig :: Config
defaultConfig = Config :: Int -> Int -> Int -> Config
Config {
ticketLifetime :: Int
ticketLifetime = Int
86400
, pruningDelay :: Int
pruningDelay = Int
6000
, dbMaxSize :: Int
dbMaxSize = Int
1000
}
toKey :: ByteString -> Block Word8
toKey :: ByteString -> SessionIDCopy
toKey = ByteString -> SessionIDCopy
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
convert
toValue :: SessionData -> SessionDataCopy
#if MIN_VERSION_tls(1,5,0)
#if MIN_VERSION_tls(1,5,3)
toValue :: SessionData -> SessionDataCopy
toValue (SessionData Version
v CipherID
cid Word8
comp Maybe HostName
msni ByteString
sec Maybe Group
mg Maybe TLS13TicketInfo
mti Maybe ByteString
malpn Int
siz [SessionFlag]
flg) =
Version
-> CipherID
-> Word8
-> Maybe HostName
-> SessionIDCopy
-> Maybe Group
-> Maybe TLS13TicketInfo
-> Maybe SessionIDCopy
-> Int
-> [SessionFlag]
-> SessionDataCopy
SessionDataCopy Version
v CipherID
cid Word8
comp Maybe HostName
msni SessionIDCopy
sec' Maybe Group
mg Maybe TLS13TicketInfo
mti Maybe SessionIDCopy
malpn' Int
siz [SessionFlag]
flg
#else
toValue (SessionData v cid comp msni sec mg mti malpn siz) =
SessionDataCopy v cid comp msni sec' mg mti malpn' siz
#endif
where
!sec' :: SessionIDCopy
sec' = ByteString -> SessionIDCopy
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
convert ByteString
sec
!malpn' :: Maybe SessionIDCopy
malpn' = ByteString -> SessionIDCopy
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
convert (ByteString -> SessionIDCopy)
-> Maybe ByteString -> Maybe SessionIDCopy
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe ByteString
malpn
#else
toValue (SessionData v cid comp msni sec) =
SessionDataCopy v cid comp msni sec'
where
!sec' = convert sec
#endif
fromValue :: SessionDataCopy -> SessionData
#if MIN_VERSION_tls(1,5,0)
#if MIN_VERSION_tls(1,5,3)
fromValue :: SessionDataCopy -> SessionData
fromValue (SessionDataCopy Version
v CipherID
cid Word8
comp Maybe HostName
msni SessionIDCopy
sec' Maybe Group
mg Maybe TLS13TicketInfo
mti Maybe SessionIDCopy
malpn' Int
siz [SessionFlag]
flg) =
Version
-> CipherID
-> Word8
-> Maybe HostName
-> ByteString
-> Maybe Group
-> Maybe TLS13TicketInfo
-> Maybe ByteString
-> Int
-> [SessionFlag]
-> SessionData
SessionData Version
v CipherID
cid Word8
comp Maybe HostName
msni ByteString
sec Maybe Group
mg Maybe TLS13TicketInfo
mti Maybe ByteString
malpn Int
siz [SessionFlag]
flg
#else
fromValue (SessionDataCopy v cid comp msni sec' mg mti malpn' siz) =
SessionData v cid comp msni sec mg mti malpn siz
#endif
where
!sec :: ByteString
sec = SessionIDCopy -> ByteString
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
convert SessionIDCopy
sec'
!malpn :: Maybe ByteString
malpn = SessionIDCopy -> ByteString
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
convert (SessionIDCopy -> ByteString)
-> Maybe SessionIDCopy -> Maybe ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe SessionIDCopy
malpn'
#else
fromValue (SessionDataCopy v cid comp msni sec') =
SessionData v cid comp msni sec
where
!sec = convert sec'
#endif
type SessionIDCopy = Block Word8
data SessionDataCopy = SessionDataCopy
!Version
!CipherID
!CompressionID
!(Maybe HostName)
(Block Word8)
#if MIN_VERSION_tls(1,5,0)
!(Maybe Group)
!(Maybe TLS13TicketInfo)
!(Maybe (Block Word8))
Int
#endif
#if MIN_VERSION_tls(1,5,3)
[SessionFlag]
#endif
deriving (Int -> SessionDataCopy -> ShowS
[SessionDataCopy] -> ShowS
SessionDataCopy -> HostName
(Int -> SessionDataCopy -> ShowS)
-> (SessionDataCopy -> HostName)
-> ([SessionDataCopy] -> ShowS)
-> Show SessionDataCopy
forall a.
(Int -> a -> ShowS) -> (a -> HostName) -> ([a] -> ShowS) -> Show a
showList :: [SessionDataCopy] -> ShowS
$cshowList :: [SessionDataCopy] -> ShowS
show :: SessionDataCopy -> HostName
$cshow :: SessionDataCopy -> HostName
showsPrec :: Int -> SessionDataCopy -> ShowS
$cshowsPrec :: Int -> SessionDataCopy -> ShowS
Show,SessionDataCopy -> SessionDataCopy -> Bool
(SessionDataCopy -> SessionDataCopy -> Bool)
-> (SessionDataCopy -> SessionDataCopy -> Bool)
-> Eq SessionDataCopy
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SessionDataCopy -> SessionDataCopy -> Bool
$c/= :: SessionDataCopy -> SessionDataCopy -> Bool
== :: SessionDataCopy -> SessionDataCopy -> Bool
$c== :: SessionDataCopy -> SessionDataCopy -> Bool
Eq)
type Sec = Int64
type Value = (SessionDataCopy, IORef Availability)
type DB = OrdPSQ SessionIDCopy Sec Value
type Item = (SessionIDCopy, Sec, Value, Operation)
data Operation = Add | Del
data Use = SingleUse | MultipleUse
data Availability = Fresh | Used
newSessionManager :: Config -> IO SessionManager
newSessionManager :: Config -> IO SessionManager
newSessionManager Config
conf = do
let lifetime :: Int64
lifetime = Int -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Int64) -> Int -> Int64
forall a b. (a -> b) -> a -> b
$ Config -> Int
ticketLifetime Config
conf
maxsiz :: Int
maxsiz = Config -> Int
dbMaxSize Config
conf
Reaper (OrdPSQ SessionIDCopy Int64 Value) Item
reaper <- ReaperSettings (OrdPSQ SessionIDCopy Int64 Value) Item
-> IO (Reaper (OrdPSQ SessionIDCopy Int64 Value) Item)
forall workload item.
ReaperSettings workload item -> IO (Reaper workload item)
mkReaper ReaperSettings [Any] Any
forall item. ReaperSettings [item] item
defaultReaperSettings {
reaperEmpty :: OrdPSQ SessionIDCopy Int64 Value
reaperEmpty = OrdPSQ SessionIDCopy Int64 Value
forall k p v. OrdPSQ k p v
Q.empty
, reaperCons :: Item
-> OrdPSQ SessionIDCopy Int64 Value
-> OrdPSQ SessionIDCopy Int64 Value
reaperCons = Int
-> Item
-> OrdPSQ SessionIDCopy Int64 Value
-> OrdPSQ SessionIDCopy Int64 Value
cons Int
maxsiz
, reaperAction :: OrdPSQ SessionIDCopy Int64 Value
-> IO
(OrdPSQ SessionIDCopy Int64 Value
-> OrdPSQ SessionIDCopy Int64 Value)
reaperAction = OrdPSQ SessionIDCopy Int64 Value
-> IO
(OrdPSQ SessionIDCopy Int64 Value
-> OrdPSQ SessionIDCopy Int64 Value)
clean
, reaperNull :: OrdPSQ SessionIDCopy Int64 Value -> Bool
reaperNull = OrdPSQ SessionIDCopy Int64 Value -> Bool
forall k p v. OrdPSQ k p v -> Bool
Q.null
, reaperDelay :: Int
reaperDelay = Config -> Int
pruningDelay Config
conf Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
1000000
}
SessionManager -> IO SessionManager
forall (m :: * -> *) a. Monad m => a -> m a
return SessionManager :: (ByteString -> IO (Maybe SessionData))
-> (ByteString -> IO (Maybe SessionData))
-> (ByteString -> SessionData -> IO ())
-> (ByteString -> IO ())
-> SessionManager
SessionManager {
sessionResume :: ByteString -> IO (Maybe SessionData)
sessionResume = Reaper (OrdPSQ SessionIDCopy Int64 Value) Item
-> Use -> ByteString -> IO (Maybe SessionData)
resume Reaper (OrdPSQ SessionIDCopy Int64 Value) Item
reaper Use
MultipleUse
#if MIN_VERSION_tls(1,5,0)
, sessionResumeOnlyOnce :: ByteString -> IO (Maybe SessionData)
sessionResumeOnlyOnce = Reaper (OrdPSQ SessionIDCopy Int64 Value) Item
-> Use -> ByteString -> IO (Maybe SessionData)
resume Reaper (OrdPSQ SessionIDCopy Int64 Value) Item
reaper Use
SingleUse
#endif
, sessionEstablish :: ByteString -> SessionData -> IO ()
sessionEstablish = Reaper (OrdPSQ SessionIDCopy Int64 Value) Item
-> Int64 -> ByteString -> SessionData -> IO ()
establish Reaper (OrdPSQ SessionIDCopy Int64 Value) Item
reaper Int64
lifetime
, sessionInvalidate :: ByteString -> IO ()
sessionInvalidate = Reaper (OrdPSQ SessionIDCopy Int64 Value) Item
-> ByteString -> IO ()
invalidate Reaper (OrdPSQ SessionIDCopy Int64 Value) Item
reaper
}
cons :: Int -> Item -> DB -> DB
cons :: Int
-> Item
-> OrdPSQ SessionIDCopy Int64 Value
-> OrdPSQ SessionIDCopy Int64 Value
cons Int
lim (SessionIDCopy
k,Int64
t,Value
v,Operation
Add) OrdPSQ SessionIDCopy Int64 Value
db
| Int
lim Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0 = OrdPSQ SessionIDCopy Int64 Value
forall k p v. OrdPSQ k p v
Q.empty
| OrdPSQ SessionIDCopy Int64 Value -> Int
forall k p v. OrdPSQ k p v -> Int
Q.size OrdPSQ SessionIDCopy Int64 Value
db Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
lim = case OrdPSQ SessionIDCopy Int64 Value
-> Maybe
(SessionIDCopy, Int64, Value, OrdPSQ SessionIDCopy Int64 Value)
forall k p v.
(Ord k, Ord p) =>
OrdPSQ k p v -> Maybe (k, p, v, OrdPSQ k p v)
Q.minView OrdPSQ SessionIDCopy Int64 Value
db of
Maybe
(SessionIDCopy, Int64, Value, OrdPSQ SessionIDCopy Int64 Value)
Nothing -> Bool
-> OrdPSQ SessionIDCopy Int64 Value
-> OrdPSQ SessionIDCopy Int64 Value
forall a. (?callStack::CallStack) => Bool -> a -> a
assert Bool
False (OrdPSQ SessionIDCopy Int64 Value
-> OrdPSQ SessionIDCopy Int64 Value)
-> OrdPSQ SessionIDCopy Int64 Value
-> OrdPSQ SessionIDCopy Int64 Value
forall a b. (a -> b) -> a -> b
$ SessionIDCopy
-> Int64
-> Value
-> OrdPSQ SessionIDCopy Int64 Value
-> OrdPSQ SessionIDCopy Int64 Value
forall k p v.
(Ord k, Ord p) =>
k -> p -> v -> OrdPSQ k p v -> OrdPSQ k p v
Q.insert SessionIDCopy
k Int64
t Value
v OrdPSQ SessionIDCopy Int64 Value
forall k p v. OrdPSQ k p v
Q.empty
Just (SessionIDCopy
_,Int64
_,Value
_,OrdPSQ SessionIDCopy Int64 Value
db') -> SessionIDCopy
-> Int64
-> Value
-> OrdPSQ SessionIDCopy Int64 Value
-> OrdPSQ SessionIDCopy Int64 Value
forall k p v.
(Ord k, Ord p) =>
k -> p -> v -> OrdPSQ k p v -> OrdPSQ k p v
Q.insert SessionIDCopy
k Int64
t Value
v OrdPSQ SessionIDCopy Int64 Value
db'
| Bool
otherwise = SessionIDCopy
-> Int64
-> Value
-> OrdPSQ SessionIDCopy Int64 Value
-> OrdPSQ SessionIDCopy Int64 Value
forall k p v.
(Ord k, Ord p) =>
k -> p -> v -> OrdPSQ k p v -> OrdPSQ k p v
Q.insert SessionIDCopy
k Int64
t Value
v OrdPSQ SessionIDCopy Int64 Value
db
cons Int
_ (SessionIDCopy
k,Int64
_,Value
_,Operation
Del) OrdPSQ SessionIDCopy Int64 Value
db = SessionIDCopy
-> OrdPSQ SessionIDCopy Int64 Value
-> OrdPSQ SessionIDCopy Int64 Value
forall k p v. (Ord k, Ord p) => k -> OrdPSQ k p v -> OrdPSQ k p v
Q.delete SessionIDCopy
k OrdPSQ SessionIDCopy Int64 Value
db
clean :: DB -> IO (DB -> DB)
clean :: OrdPSQ SessionIDCopy Int64 Value
-> IO
(OrdPSQ SessionIDCopy Int64 Value
-> OrdPSQ SessionIDCopy Int64 Value)
clean OrdPSQ SessionIDCopy Int64 Value
olddb = do
Int64
currentTime <- TimeSpec -> Int64
C.sec (TimeSpec -> Int64) -> IO TimeSpec -> IO Int64
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Clock -> IO TimeSpec
C.getTime Clock
C.Monotonic
let !pruned :: OrdPSQ SessionIDCopy Int64 Value
pruned = ([(SessionIDCopy, Int64, Value)], OrdPSQ SessionIDCopy Int64 Value)
-> OrdPSQ SessionIDCopy Int64 Value
forall a b. (a, b) -> b
snd (([(SessionIDCopy, Int64, Value)],
OrdPSQ SessionIDCopy Int64 Value)
-> OrdPSQ SessionIDCopy Int64 Value)
-> ([(SessionIDCopy, Int64, Value)],
OrdPSQ SessionIDCopy Int64 Value)
-> OrdPSQ SessionIDCopy Int64 Value
forall a b. (a -> b) -> a -> b
$ Int64
-> OrdPSQ SessionIDCopy Int64 Value
-> ([(SessionIDCopy, Int64, Value)],
OrdPSQ SessionIDCopy Int64 Value)
forall k p v.
(Ord k, Ord p) =>
p -> OrdPSQ k p v -> ([(k, p, v)], OrdPSQ k p v)
Q.atMostView Int64
currentTime OrdPSQ SessionIDCopy Int64 Value
olddb
(OrdPSQ SessionIDCopy Int64 Value
-> OrdPSQ SessionIDCopy Int64 Value)
-> IO
(OrdPSQ SessionIDCopy Int64 Value
-> OrdPSQ SessionIDCopy Int64 Value)
forall (m :: * -> *) a. Monad m => a -> m a
return ((OrdPSQ SessionIDCopy Int64 Value
-> OrdPSQ SessionIDCopy Int64 Value)
-> IO
(OrdPSQ SessionIDCopy Int64 Value
-> OrdPSQ SessionIDCopy Int64 Value))
-> (OrdPSQ SessionIDCopy Int64 Value
-> OrdPSQ SessionIDCopy Int64 Value)
-> IO
(OrdPSQ SessionIDCopy Int64 Value
-> OrdPSQ SessionIDCopy Int64 Value)
forall a b. (a -> b) -> a -> b
$ OrdPSQ SessionIDCopy Int64 Value
-> OrdPSQ SessionIDCopy Int64 Value
-> OrdPSQ SessionIDCopy Int64 Value
forall {k} {p} {v}.
(Ord k, Ord p) =>
OrdPSQ k p v -> OrdPSQ k p v -> OrdPSQ k p v
merge OrdPSQ SessionIDCopy Int64 Value
pruned
where
ins :: OrdPSQ k p v -> (k, p, v) -> OrdPSQ k p v
ins OrdPSQ k p v
db (k
k,p
p,v
v) = k -> p -> v -> OrdPSQ k p v -> OrdPSQ k p v
forall k p v.
(Ord k, Ord p) =>
k -> p -> v -> OrdPSQ k p v -> OrdPSQ k p v
Q.insert k
k p
p v
v OrdPSQ k p v
db
merge :: OrdPSQ k p v -> OrdPSQ k p v -> OrdPSQ k p v
merge OrdPSQ k p v
pruned OrdPSQ k p v
newdb = (OrdPSQ k p v -> (k, p, v) -> OrdPSQ k p v)
-> OrdPSQ k p v -> [(k, p, v)] -> OrdPSQ k p v
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' OrdPSQ k p v -> (k, p, v) -> OrdPSQ k p v
forall {k} {p} {v}.
(Ord k, Ord p) =>
OrdPSQ k p v -> (k, p, v) -> OrdPSQ k p v
ins OrdPSQ k p v
pruned [(k, p, v)]
entries
where
entries :: [(k, p, v)]
entries = OrdPSQ k p v -> [(k, p, v)]
forall k p v. OrdPSQ k p v -> [(k, p, v)]
Q.toList OrdPSQ k p v
newdb
establish :: Reaper DB Item -> Sec
-> SessionID -> SessionData -> IO ()
establish :: Reaper (OrdPSQ SessionIDCopy Int64 Value) Item
-> Int64 -> ByteString -> SessionData -> IO ()
establish Reaper (OrdPSQ SessionIDCopy Int64 Value) Item
reaper Int64
lifetime ByteString
k SessionData
sd = do
IORef Availability
ref <- Availability -> IO (IORef Availability)
forall a. a -> IO (IORef a)
newIORef Availability
Fresh
!Int64
p <- (Int64 -> Int64 -> Int64
forall a. Num a => a -> a -> a
+ Int64
lifetime) (Int64 -> Int64) -> (TimeSpec -> Int64) -> TimeSpec -> Int64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TimeSpec -> Int64
C.sec (TimeSpec -> Int64) -> IO TimeSpec -> IO Int64
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Clock -> IO TimeSpec
C.getTime Clock
C.Monotonic
let !v :: Value
v = (SessionDataCopy
sd',IORef Availability
ref)
Reaper (OrdPSQ SessionIDCopy Int64 Value) Item -> Item -> IO ()
forall workload item. Reaper workload item -> item -> IO ()
reaperAdd Reaper (OrdPSQ SessionIDCopy Int64 Value) Item
reaper (SessionIDCopy
k',Int64
p,Value
v,Operation
Add)
where
!k' :: SessionIDCopy
k' = ByteString -> SessionIDCopy
toKey ByteString
k
!sd' :: SessionDataCopy
sd' = SessionData -> SessionDataCopy
toValue SessionData
sd
resume :: Reaper DB Item -> Use
-> SessionID -> IO (Maybe SessionData)
resume :: Reaper (OrdPSQ SessionIDCopy Int64 Value) Item
-> Use -> ByteString -> IO (Maybe SessionData)
resume Reaper (OrdPSQ SessionIDCopy Int64 Value) Item
reaper Use
use ByteString
k = do
OrdPSQ SessionIDCopy Int64 Value
db <- Reaper (OrdPSQ SessionIDCopy Int64 Value) Item
-> IO (OrdPSQ SessionIDCopy Int64 Value)
forall workload item. Reaper workload item -> IO workload
reaperRead Reaper (OrdPSQ SessionIDCopy Int64 Value) Item
reaper
case SessionIDCopy
-> OrdPSQ SessionIDCopy Int64 Value -> Maybe (Int64, Value)
forall k p v. Ord k => k -> OrdPSQ k p v -> Maybe (p, v)
Q.lookup SessionIDCopy
k' OrdPSQ SessionIDCopy Int64 Value
db of
Maybe (Int64, Value)
Nothing -> Maybe SessionData -> IO (Maybe SessionData)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe SessionData
forall a. Maybe a
Nothing
Just (Int64
p,v :: Value
v@(SessionDataCopy
sd,IORef Availability
ref)) ->
case Use
use of
Use
SingleUse -> do
Bool
available <- IORef Availability
-> (Availability -> (Availability, Bool)) -> IO Bool
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' IORef Availability
ref Availability -> (Availability, Bool)
check
Reaper (OrdPSQ SessionIDCopy Int64 Value) Item -> Item -> IO ()
forall workload item. Reaper workload item -> item -> IO ()
reaperAdd Reaper (OrdPSQ SessionIDCopy Int64 Value) Item
reaper (SessionIDCopy
k',Int64
p,Value
v,Operation
Del)
Maybe SessionData -> IO (Maybe SessionData)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe SessionData -> IO (Maybe SessionData))
-> Maybe SessionData -> IO (Maybe SessionData)
forall a b. (a -> b) -> a -> b
$ if Bool
available then SessionData -> Maybe SessionData
forall a. a -> Maybe a
Just (SessionDataCopy -> SessionData
fromValue SessionDataCopy
sd) else Maybe SessionData
forall a. Maybe a
Nothing
Use
MultipleUse -> Maybe SessionData -> IO (Maybe SessionData)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe SessionData -> IO (Maybe SessionData))
-> Maybe SessionData -> IO (Maybe SessionData)
forall a b. (a -> b) -> a -> b
$ SessionData -> Maybe SessionData
forall a. a -> Maybe a
Just (SessionDataCopy -> SessionData
fromValue SessionDataCopy
sd)
where
check :: Availability -> (Availability, Bool)
check Availability
Fresh = (Availability
Used,Bool
True)
check Availability
Used = (Availability
Used,Bool
False)
!k' :: SessionIDCopy
k' = ByteString -> SessionIDCopy
toKey ByteString
k
invalidate :: Reaper DB Item
-> SessionID -> IO ()
invalidate :: Reaper (OrdPSQ SessionIDCopy Int64 Value) Item
-> ByteString -> IO ()
invalidate Reaper (OrdPSQ SessionIDCopy Int64 Value) Item
reaper ByteString
k = do
OrdPSQ SessionIDCopy Int64 Value
db <- Reaper (OrdPSQ SessionIDCopy Int64 Value) Item
-> IO (OrdPSQ SessionIDCopy Int64 Value)
forall workload item. Reaper workload item -> IO workload
reaperRead Reaper (OrdPSQ SessionIDCopy Int64 Value) Item
reaper
case SessionIDCopy
-> OrdPSQ SessionIDCopy Int64 Value -> Maybe (Int64, Value)
forall k p v. Ord k => k -> OrdPSQ k p v -> Maybe (p, v)
Q.lookup SessionIDCopy
k' OrdPSQ SessionIDCopy Int64 Value
db of
Maybe (Int64, Value)
Nothing -> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
Just (Int64
p,Value
v) -> Reaper (OrdPSQ SessionIDCopy Int64 Value) Item -> Item -> IO ()
forall workload item. Reaper workload item -> item -> IO ()
reaperAdd Reaper (OrdPSQ SessionIDCopy Int64 Value) Item
reaper (SessionIDCopy
k',Int64
p,Value
v,Operation
Del)
where
!k' :: SessionIDCopy
k' = ByteString -> SessionIDCopy
toKey ByteString
k