{-# LANGUAGE CPP #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# OPTIONS_HADDOCK not-home #-}
module Hmssql.Connection.Internal
( Connection (..)
, Transport (..)
, Session (..)
, SmpSession (..)
, SmpLink (..)
, Mars (..)
, ActiveResponse (..), Cancellation (..)
, ReadState (..), ReadPosition (..)
, newConnection
, startReader
, enableMars
, allSessions
, closeConnection
, releaseTransport
, closeSocket
, closeSocketWith
, socketCloser
, connectionContext
, connectionMars
, withConnectionLock
, checkLease
, invalidateLease
, renewLease
, renewUsable
, checkNotBroken
, refuseUnusable
, currentUnusableReason
, markBroken
, reasonFor
, resetFailure
, throwSevere
, transportError
, recvSome
, recvExactly
, newBufferedRecv
, SendGather (..)
, Gathered (..)
, gatheredSend
, sendBytes
, sendFramed
, sendPackets
, readPacket
, sendMessage
, runBody
, startRequest
, sourceAction
, bytesBody
, startRequestFor
, startStreamingRequest
, withReservedSession
, requestReset
, resetWithSessionSetup
, RowRead (..), newRowRead, wholeRows, discardRows, drainingRows
, nextStepReversed
, RowBatch (..)
, ResponseStep (..)
, nextStep
, readPiece
, nextToken
, checkCurrent
, finishResponse
, cancelActiveResponse
, readingToEnd
, abandonResponse
, drainCancelled
, busyStatements
, drainActiveResponse
, readWholeMessage
, readWholeMessageUpTo
) where
import Control.Concurrent (ThreadId, forkIOWithUnmask, forkOnWithUnmask, killThread, mkWeakThreadId, myThreadId, threadCapability)
import GHC.Conc (labelThread)
import GHC.Exts (keepAlive#)
import GHC.IO (IO (..))
import Control.Concurrent.MVar
import Control.Concurrent.STM
import Control.Exception
import Control.Applicative ((<|>))
import Control.Monad (forM, forM_, unless, void, when)
import Streaming (Stream, inspect)
import qualified Streaming
import Hmssql.Internal.Derived
import Hmssql.Tds.Reader
import qualified Hmssql.Tds.Value as V
import qualified Hmssql.Tds.Parser as P
import Data.Binary.Put (Put)
import qualified Data.Binary.Put as Put
import Data.Bits ((.&.))
import Data.Int (Int32)
import qualified Data.IntMap.Strict as IntMap
import qualified Data.ByteString as B
import qualified Data.ByteString.Builder as BB
import qualified Data.ByteString.Builder.Extra as BB
import qualified Data.ByteString.Internal as BI
import qualified Data.ByteString.Lazy as LB
import qualified Data.ByteString.Unsafe as BU
import Data.IORef
import Data.Maybe (catMaybes, fromMaybe, isJust, isNothing)
import Data.Proxy (Proxy (..))
import Data.Text (Text)
import qualified Data.Text as T
import Data.Word (Word16, Word32, Word8)
import Foreign.ForeignPtr (ForeignPtr, plusForeignPtr, withForeignPtr)
import Foreign.Marshal.Utils (copyBytes, moveBytes)
import Foreign.Ptr (plusPtr)
import qualified Network.TLS as TLS
import System.Mem.Weak (Weak, deRefWeak)
import Hmssql.Connection.Backend
import Hmssql.Connection.Locking
import Hmssql.Errors
import Hmssql.Tds.Client (sqlBatchBuilder, sqlBatchProblem)
import Hmssql.Tds.Context
import Hmssql.Tds.Packet
import Hmssql.Tds.PacketWriter
import Hmssql.Tds.Smp
import Hmssql.Tds.Token
data Transport
= TransportPlain !Backend
| TransportTls !TLS.Context
data Session = Session
{ Session -> IORef (Maybe ActiveResponse)
sessResponse :: !(IORef (Maybe ActiveResponse))
, Session -> IORef Int
sessGeneration :: !(IORef Int)
, Session -> IORef [ByteString]
sessRecvBuffer :: !(IORef [B.ByteString])
, Session -> Maybe SmpSession
sessSmp :: !(Maybe SmpSession)
}
data SmpSession = SmpSession
{ SmpSession -> Word16
smpSid :: !Word16
, SmpSession -> SmpLink
smpLink :: !SmpLink
, SmpSession -> IORef Word32
smpSendSeq :: !(IORef Word32)
, SmpSession -> IORef Word32
smpAdvertised :: !(IORef Word32)
}
data SmpLink = SmpLink
{ SmpLink -> TQueue ByteString
linkIncoming :: !(TQueue B.ByteString)
, SmpLink -> TVar Word32
linkSendHighWater :: !(TVar Word32)
, SmpLink -> TVar Word32
linkRecvSeq :: !(TVar Word32)
, SmpLink -> TVar Word32
linkRecvHighWater :: !(TVar Word32)
, SmpLink -> TVar Int
linkEoms :: !(TVar Int)
, SmpLink -> TVar Bool
linkClosing :: !(TVar Bool)
}
data Mars = Mars
{ Mars -> TVar (IntMap SmpLink)
marsRegistry :: !(TVar (IntMap.IntMap SmpLink))
, Mars -> IORef (IntMap Session)
marsOpen :: !(IORef (IntMap.IntMap Session))
, Mars -> IORef (Maybe Session)
marsReserved :: !(IORef (Maybe Session))
, Mars -> Word32
marsWindow :: !Word32
, Mars -> IORef (Maybe ActiveResponse)
marsResetInFlight :: !(IORef (Maybe ActiveResponse))
}
data ActiveResponse = ActiveResponse
{ ActiveResponse -> Int
arGeneration :: !Int
, ActiveResponse -> Session
arSession :: !Session
, ActiveResponse -> Maybe Text
arStatement :: !(Maybe Text)
, ActiveResponse -> Int
arEomBase :: !Int
, ActiveResponse -> Bool
arCarriedReset :: !Bool
, ActiveResponse -> IORef Bool
arSawResetAck :: !(IORef Bool)
, ActiveResponse -> IORef Bool
arInConsumer :: !(IORef Bool)
, ActiveResponse -> IORef Cancellation
arCancellation :: !(IORef Cancellation)
, ActiveResponse -> IORef [Token]
arReplay :: !(IORef [Token])
, ActiveResponse -> IORef ReadState
arState :: !(IORef ReadState)
, ActiveResponse -> IORef (Maybe ResultSetInfo)
arResultSet :: !(IORef (Maybe ResultSetInfo))
, ActiveResponse -> IORef Bool
arSawFinalDone :: !(IORef Bool)
}
data Cancellation = Running | Abandoned | AttentionSent | AttentionAcknowledged
deriving stock (Cancellation -> Cancellation -> Bool
(Cancellation -> Cancellation -> Bool)
-> (Cancellation -> Cancellation -> Bool) -> Eq Cancellation
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Cancellation -> Cancellation -> Bool
== :: Cancellation -> Cancellation -> Bool
$c/= :: Cancellation -> Cancellation -> Bool
/= :: Cancellation -> Cancellation -> Bool
Eq, Int -> Cancellation -> ShowS
[Cancellation] -> ShowS
Cancellation -> [Char]
(Int -> Cancellation -> ShowS)
-> (Cancellation -> [Char])
-> ([Cancellation] -> ShowS)
-> Show Cancellation
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Cancellation -> ShowS
showsPrec :: Int -> Cancellation -> ShowS
$cshow :: Cancellation -> [Char]
show :: Cancellation -> [Char]
$cshowList :: [Cancellation] -> ShowS
showList :: [Cancellation] -> ShowS
Show)
attentionWasSent :: Cancellation -> Bool
attentionWasSent :: Cancellation -> Bool
attentionWasSent Cancellation
AttentionSent = Bool
True
attentionWasSent Cancellation
AttentionAcknowledged = Bool
True
attentionWasSent Cancellation
_ = Bool
False
markAbandoned :: ActiveResponse -> IO ()
markAbandoned :: ActiveResponse -> IO ()
markAbandoned ActiveResponse
ar = IORef Cancellation -> (Cancellation -> Cancellation) -> IO ()
forall a. IORef a -> (a -> a) -> IO ()
modifyIORef' (ActiveResponse -> IORef Cancellation
arCancellation ActiveResponse
ar) ((Cancellation -> Cancellation) -> IO ())
-> (Cancellation -> Cancellation) -> IO ()
forall a b. (a -> b) -> a -> b
$ \case
Cancellation
Running -> Cancellation
Abandoned
Cancellation
state -> Cancellation
state
data ReadState = ReadState
{ ReadState -> Bool
readFinalPacket :: !Bool
, ReadState -> ReadPosition
readPosition :: !ReadPosition
}
data ReadPosition
= AtToken !B.ByteString
| Reading (Stream P.Await IO ReadEvent)
| Parked !B.ByteString (P.Parser ())
data ReadEvent
= ReadToken !Token !B.ByteString
| ReadRow (IO ()) !B.ByteString
| SkippedRow !B.ByteString
data Connection = Connection
{ Connection -> Backend
connBackend :: !Backend
, Connection -> IORef Transport
connTransport :: !(IORef Transport)
, Connection -> Session
connPrimary :: !Session
, Connection -> Maybe Mars
connMars :: !(Maybe Mars)
, Connection -> IORef ()
connAlive :: !(IORef ())
, Connection -> TMVar ByteString
connIncoming :: !(TMVar B.ByteString)
, Connection -> TVar (Maybe SomeException)
connEnded :: !(TVar (Maybe SomeException))
, Connection -> MVar ()
connSendLock :: !(MVar ())
, Connection -> SendGather
connSendGather :: !SendGather
, Connection -> IORef (Maybe (Weak ThreadId))
connReader :: !(IORef (Maybe (Weak ThreadId)))
, Connection -> IORef TdsContext
connContext :: !(IORef TdsContext)
, Connection -> Mutex
connMutex :: !Mutex
, Connection -> IORef (Maybe UnusableReason)
connBroken :: !(IORef (Maybe UnusableReason))
, Connection -> IORef Bool
connResetPending :: !(IORef Bool)
, Connection -> Bool
connPinReader :: !Bool
, Connection -> [Text]
connSessionSetup :: ![Text]
, Connection -> Int
connValueAllocAhead :: !Int
, Connection -> ServerMessage -> IO ()
connOnInfo :: !(ServerMessage -> IO ())
, Connection -> EnvChange -> IO ()
connOnEnvChange :: !(EnvChange -> IO ())
, Connection -> IORef Bool
connInSource :: !(IORef Bool)
, Connection -> IORef Bool
connInCallback :: !(IORef Bool)
, Connection -> Int
connLease :: !Int
, Connection -> IORef Int
connCurrentLease :: !(IORef Int)
}
newConnection :: Backend -> TdsContext -> (ServerMessage -> IO ()) -> IO Connection
newConnection :: Backend -> TdsContext -> (ServerMessage -> IO ()) -> IO Connection
newConnection Backend
backend TdsContext
ctx ServerMessage -> IO ()
onInfo = do
connTransport <- Transport -> IO (IORef Transport)
forall a. a -> IO (IORef a)
newIORef (Backend -> Transport
TransportPlain Backend
backend)
connPrimary <- newSession Nothing
connAlive <- newIORef ()
connIncoming <- newEmptyTMVarIO
connEnded <- newTVarIO Nothing
connSendLock <- newMVar ()
connSendGather <- newSendGather
connReader <- newIORef Nothing
connContext <- newIORef ctx
connMutex <- newMutex
connBroken <- newIORef Nothing
connInCallback <- newIORef False
connInSource <- newIORef False
connResetPending <- newIORef False
connCurrentLease <- newIORef 0
pure Connection
{ connBackend = backend
, connSessionSetup = []
, connPinReader = False
, connValueAllocAhead = lobAllocAhead
, connOnInfo = onInfo
, connOnEnvChange = \EnvChange
_ -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
, connLease = 0
, connMars = Nothing
, ..
}
newSession :: Maybe SmpSession -> IO Session
newSession :: Maybe SmpSession -> IO Session
newSession Maybe SmpSession
sessSmp = do
sessResponse <- Maybe ActiveResponse -> IO (IORef (Maybe ActiveResponse))
forall a. a -> IO (IORef a)
newIORef Maybe ActiveResponse
forall a. Maybe a
Nothing
sessGeneration <- newIORef 0
sessRecvBuffer <- newIORef []
pure Session{..}
connectionContext :: Connection -> IO TdsContext
connectionContext :: Connection -> IO TdsContext
connectionContext = IORef TdsContext -> IO TdsContext
forall a. IORef a -> IO a
readIORef (IORef TdsContext -> IO TdsContext)
-> (Connection -> IORef TdsContext) -> Connection -> IO TdsContext
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Connection -> IORef TdsContext
connContext
connectionMars :: Connection -> Bool
connectionMars :: Connection -> Bool
connectionMars = Maybe Mars -> Bool
forall a. Maybe a -> Bool
isJust (Maybe Mars -> Bool)
-> (Connection -> Maybe Mars) -> Connection -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Connection -> Maybe Mars
connMars
withConnectionLock :: Connection -> IO a -> IO a
withConnectionLock :: forall a. Connection -> IO a -> IO a
withConnectionLock Connection
conn IO a
act = Mutex -> IO a -> IO a
forall a. Mutex -> IO a -> IO a
withMutex (Connection -> Mutex
connMutex Connection
conn) (IO a -> IO a) -> IO a -> IO a
forall a b. (a -> b) -> a -> b
$ do
inCallback <- IORef Bool -> IO Bool
forall a. IORef a -> IO a
readIORef (Connection -> IORef Bool
connInCallback Connection
conn)
when inCallback $ throwIO ReentrantCallback
source <- readIORef (connInSource conn)
when (source && isNothing (connMars conn)) (throwIO ReentrantSource)
checkLease conn
act
{-# OPAQUE withConnectionLock #-}
sourceAction :: Connection -> IO a -> IO a
sourceAction :: forall a. Connection -> IO a -> IO a
sourceAction Connection
conn IO a
action = IO a -> IO a
forall a. IO a -> IO a
mask_ (IO a -> IO a) -> IO a -> IO a
forall a b. (a -> b) -> a -> b
$ IO Bool -> (Bool -> IO ()) -> (Bool -> IO a) -> IO a
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket
(IORef Bool -> (Bool -> (Bool, Bool)) -> IO Bool
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' (Connection -> IORef Bool
connInSource Connection
conn) (\Bool
old -> (Bool
True, Bool
old)))
(IORef Bool -> Bool -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (Connection -> IORef Bool
connInSource Connection
conn)) (IO a -> Bool -> IO a
forall a b. a -> b -> a
const IO a
action)
checkLease :: Connection -> IO ()
checkLease :: Connection -> IO ()
checkLease Connection
conn = do
current <- IORef Int -> IO Int
forall a. IORef a -> IO a
readIORef (Connection -> IORef Int
connCurrentLease Connection
conn)
when (current /= connLease conn) $ throwIO ConnectionReleased
invalidateLease :: Connection -> IO ()
invalidateLease :: Connection -> IO ()
invalidateLease Connection
conn = IORef Int -> (Int -> (Int, ())) -> IO ()
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' (Connection -> IORef Int
connCurrentLease Connection
conn) (\Int
l -> (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1, ()))
renewLease :: Connection -> IO Connection
renewLease :: Connection -> IO Connection
renewLease Connection
conn = Mutex -> IO Connection -> IO Connection
forall a. Mutex -> IO a -> IO a
withMutex (Connection -> Mutex
connMutex Connection
conn) (IO Connection -> IO Connection) -> IO Connection -> IO Connection
forall a b. (a -> b) -> a -> b
$ do
lease <- IORef Int -> (Int -> (Int, Int)) -> IO Int
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' (Connection -> IORef Int
connCurrentLease Connection
conn) (\Int
l -> (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1, Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1))
pure conn { connLease = lease }
renewUsable :: Connection -> IO Connection
renewUsable :: Connection -> IO Connection
renewUsable Connection
conn = Mutex -> IO Connection -> IO Connection
forall a. Mutex -> IO a -> IO a
withMutex (Connection -> Mutex
connMutex Connection
conn) (IO Connection -> IO Connection) -> IO Connection -> IO Connection
forall a b. (a -> b) -> a -> b
$ Connection -> IO ()
refuseUnusable Connection
conn IO () -> IO Connection -> IO Connection
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Connection -> IO Connection
renewLease Connection
conn
checkNotBroken :: Connection -> IO ()
checkNotBroken :: Connection -> IO ()
checkNotBroken Connection
conn = do
TVar (Maybe SomeException) -> IO (Maybe SomeException)
forall a. TVar a -> IO a
readTVarIO (Connection -> TVar (Maybe SomeException)
connEnded Connection
conn) IO (Maybe SomeException) -> (Maybe SomeException -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Just SomeException
e | SomeException -> Bool
closedByClient SomeException
e -> SomeException -> IO ()
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO SomeException
e
Maybe SomeException
_ -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
IORef (Maybe UnusableReason) -> IO (Maybe UnusableReason)
forall a. IORef a -> IO a
readIORef (Connection -> IORef (Maybe UnusableReason)
connBroken Connection
conn) IO (Maybe UnusableReason)
-> (Maybe UnusableReason -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Maybe UnusableReason
Nothing -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
Just UnusableReason
r -> ConnectionBroken -> IO ()
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO (UnusableReason -> ConnectionBroken
ConnectionBroken UnusableReason
r)
closedByClient :: SomeException -> Bool
closedByClient :: SomeException -> Bool
closedByClient SomeException
e = case SomeException -> Maybe ConnectionClosed
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
e of
Just (ConnectionClosedBy CloseReason
ClosedByClient) -> Bool
True
Maybe ConnectionClosed
_ -> Bool
False
refuseUnusable :: Connection -> IO ()
refuseUnusable :: Connection -> IO ()
refuseUnusable Connection
conn = do
Connection -> IO ()
checkNotBroken Connection
conn
TVar (Maybe SomeException) -> IO (Maybe SomeException)
forall a. TVar a -> IO a
readTVarIO (Connection -> TVar (Maybe SomeException)
connEnded Connection
conn) IO (Maybe SomeException) -> (Maybe SomeException -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (SomeException -> IO (ZonkAny 5)) -> Maybe SomeException -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (\SomeException
e -> Connection -> UnusableReason -> IO ()
markBroken Connection
conn ((SomeException -> UnusableReason)
-> SomeException -> UnusableReason
reasonFor SomeException -> UnusableReason
ReaderThreadDied SomeException
e) IO () -> IO (ZonkAny 5) -> IO (ZonkAny 5)
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> SomeException -> IO (ZonkAny 5)
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO SomeException
e)
currentUnusableReason :: Connection -> IO (Maybe UnusableReason)
currentUnusableReason :: Connection -> IO (Maybe UnusableReason)
currentUnusableReason Connection
conn = Mutex -> IO (Maybe UnusableReason) -> IO (Maybe UnusableReason)
forall a. Mutex -> IO a -> IO a
withMutex (Connection -> Mutex
connMutex Connection
conn) (IO (Maybe UnusableReason) -> IO (Maybe UnusableReason))
-> IO (Maybe UnusableReason) -> IO (Maybe UnusableReason)
forall a b. (a -> b) -> a -> b
$ do
ended <- TVar (Maybe SomeException) -> IO (Maybe SomeException)
forall a. TVar a -> IO a
readTVarIO (Connection -> TVar (Maybe SomeException)
connEnded Connection
conn)
broken <- readIORef (connBroken conn)
pure $ case ended of
Just SomeException
e | SomeException -> Bool
closedByClient SomeException
e -> UnusableReason -> Maybe UnusableReason
forall a. a -> Maybe a
Just (CloseReason -> UnusableReason
Closed CloseReason
ClosedByClient)
Maybe SomeException
_ -> Maybe UnusableReason
broken Maybe UnusableReason
-> Maybe UnusableReason -> Maybe UnusableReason
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ((SomeException -> UnusableReason)
-> SomeException -> UnusableReason
reasonFor SomeException -> UnusableReason
ReaderThreadDied (SomeException -> UnusableReason)
-> Maybe SomeException -> Maybe UnusableReason
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe SomeException
ended)
markBroken :: Connection -> UnusableReason -> IO ()
markBroken :: Connection -> UnusableReason -> IO ()
markBroken Connection
conn UnusableReason
reason = IORef (Maybe UnusableReason)
-> (Maybe UnusableReason -> Maybe UnusableReason) -> IO ()
forall a. IORef a -> (a -> a) -> IO ()
modifyIORef' (Connection -> IORef (Maybe UnusableReason)
connBroken Connection
conn) (Maybe UnusableReason
-> (UnusableReason -> Maybe UnusableReason)
-> Maybe UnusableReason
-> Maybe UnusableReason
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (UnusableReason -> Maybe UnusableReason
forall a. a -> Maybe a
Just UnusableReason
reason) UnusableReason -> Maybe UnusableReason
forall a. a -> Maybe a
Just)
reasonFor :: (SomeException -> UnusableReason) -> SomeException -> UnusableReason
reasonFor :: (SomeException -> UnusableReason)
-> SomeException -> UnusableReason
reasonFor SomeException -> UnusableReason
other SomeException
e
| Just (ConnectionBroken UnusableReason
r) <- SomeException -> Maybe ConnectionBroken
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
e = UnusableReason
r
| Just (ConnectionClosedBy CloseReason
r) <- SomeException -> Maybe ConnectionClosed
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
e = CloseReason -> UnusableReason
Closed CloseReason
r
| Just (ProtocolError [Char]
m) <- SomeException -> Maybe ProtocolError
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
e = [Char] -> UnusableReason
ServerProtocolViolation [Char]
m
| Bool
otherwise = SomeException -> UnusableReason
other SomeException
e
resetFailure :: SomeException -> UnusableReason
resetFailure :: SomeException -> UnusableReason
resetFailure SomeException
e
| Just SqlServerError
err <- SomeException -> Maybe SqlServerError
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
e = Maybe ServerMessage -> UnusableReason
ResetRefused (ServerMessage -> Maybe ServerMessage
forall a. a -> Maybe a
Just (SqlServerError -> ServerMessage
sqlError SqlServerError
err))
| Just (SevereError{}) <- SomeException -> Maybe SevereError
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
e = Maybe ServerMessage -> UnusableReason
ResetRefused Maybe ServerMessage
forall a. Maybe a
Nothing
| Bool
otherwise = (SomeException -> UnusableReason)
-> SomeException -> UnusableReason
reasonFor SomeException -> UnusableReason
ResetFailed SomeException
e
throwSevere :: Connection -> Done -> Maybe Text -> IO a
throwSevere :: forall a. Connection -> Done -> Maybe Text -> IO a
throwSevere Connection
conn Done
d Maybe Text
stmt = do
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Done -> Bool
doneServerError Done
d) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Connection -> UnusableReason -> IO ()
markBroken Connection
conn (Done -> UnusableReason
ServerFailedConnection Done
d)
SevereError -> IO a
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO (Done -> Maybe Text -> SevereError
SevereError Done
d Maybe Text
stmt)
breakOnFailure :: Connection -> IO a -> IO a
breakOnFailure :: forall a. Connection -> IO a -> IO a
breakOnFailure Connection
conn IO a
act = IO a
act IO a -> (SomeException -> IO a) -> IO a
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catch` \SomeException
e -> do
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (SomeException -> Bool
isBenign SomeException
e) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Connection -> UnusableReason -> IO ()
markBroken Connection
conn ((SomeException -> UnusableReason)
-> SomeException -> UnusableReason
reasonFor SomeException -> UnusableReason
ReadFailed SomeException
e)
SomeException -> IO a
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO SomeException
e
where
isBenign :: SomeException -> Bool
isBenign SomeException
e =
Proxy ResultAbandoned -> SomeException -> Bool
forall ex. Exception ex => Proxy ex -> SomeException -> Bool
isA (forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @ResultAbandoned) SomeException
e Bool -> Bool -> Bool
|| Proxy SqlServerError -> SomeException -> Bool
forall ex. Exception ex => Proxy ex -> SomeException -> Bool
isA (forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @SqlServerError) SomeException
e
Bool -> Bool -> Bool
|| Proxy AsyncException -> SomeException -> Bool
forall ex. Exception ex => Proxy ex -> SomeException -> Bool
isA (forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @AsyncException) SomeException
e Bool -> Bool -> Bool
|| Proxy SomeAsyncException -> SomeException -> Bool
forall ex. Exception ex => Proxy ex -> SomeException -> Bool
isA (forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @SomeAsyncException) SomeException
e
isA :: forall ex. Exception ex => Proxy ex -> SomeException -> Bool
isA :: forall ex. Exception ex => Proxy ex -> SomeException -> Bool
isA Proxy ex
_ SomeException
e = case SomeException -> Maybe ex
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
e :: Maybe ex of
Just ex
_ -> Bool
True
Maybe ex
Nothing -> Bool
False
transportError :: SomeException -> SomeException
transportError :: SomeException -> SomeException
transportError SomeException
e
| Just (SomeAsyncException
_ :: SomeAsyncException) <- SomeException -> Maybe SomeAsyncException
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
e = SomeException
e
| Just (ConnectionClosed
_ :: ConnectionClosed) <- SomeException -> Maybe ConnectionClosed
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
e = SomeException
e
| Just TLSException
tls <- SomeException -> Maybe TLSException
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
e =
ConnectionClosed -> SomeException
forall e. Exception e => e -> SomeException
toException (ConnectionClosed -> SomeException)
-> ConnectionClosed -> SomeException
forall a b. (a -> b) -> a -> b
$ CloseReason -> ConnectionClosed
ConnectionClosedBy (CloseReason -> ConnectionClosed)
-> CloseReason -> ConnectionClosed
forall a b. (a -> b) -> a -> b
$ if TLSException -> Bool
tlsEof TLSException
tls then CloseReason
ClosedByServer else SomeException -> CloseReason
TransportFailed SomeException
e
| Just (IOException
_ :: IOException) <- SomeException -> Maybe IOException
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
e = ConnectionClosed -> SomeException
forall e. Exception e => e -> SomeException
toException (ConnectionClosed -> SomeException)
-> ConnectionClosed -> SomeException
forall a b. (a -> b) -> a -> b
$ CloseReason -> ConnectionClosed
ConnectionClosedBy (SomeException -> CloseReason
TransportFailed SomeException
e)
| Bool
otherwise = SomeException
e
where
tlsEof :: TLSException -> Bool
tlsEof = \case
TLS.PostHandshake TLSError
TLS.Error_EOF -> Bool
True
TLS.Terminated Bool
_ [Char]
_ TLSError
TLS.Error_EOF -> Bool
True
TLS.Uncontextualized TLSError
TLS.Error_EOF -> Bool
True
TLSException
_ -> Bool
False
recvDirect :: Connection -> IO B.ByteString
recvDirect :: Connection -> IO ByteString
recvDirect Connection
conn = IORef Transport -> IO ByteString
recvTransport (Connection -> IORef Transport
connTransport Connection
conn)
recvTransport :: IORef Transport -> IO B.ByteString
recvTransport :: IORef Transport -> IO ByteString
recvTransport IORef Transport
transport = do
bs <- IO ByteString
recv IO ByteString -> (SomeException -> IO ByteString) -> IO ByteString
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catch` (SomeException -> IO ByteString
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO (SomeException -> IO ByteString)
-> (SomeException -> SomeException)
-> SomeException
-> IO ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SomeException -> SomeException
transportError)
when (B.null bs) $ throwIO ConnectionClosed
pure bs
where
recv :: IO ByteString
recv = IORef Transport -> IO Transport
forall a. IORef a -> IO a
readIORef IORef Transport
transport IO Transport -> (Transport -> IO ByteString) -> IO ByteString
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
TransportPlain Backend
backend -> Backend -> IO ByteString
recvFresh Backend
backend
TransportTls Context
ctx -> Context -> IO ByteString
forall (m :: * -> *). MonadIO m => Context -> m ByteString
TLS.recvData Context
ctx
recvFresh :: Backend -> IO B.ByteString
recvFresh :: Backend -> IO ByteString
recvFresh Backend
backend = do
fp <- Int -> IO (ForeignPtr Word8)
forall a. Int -> IO (ForeignPtr a)
BI.mallocByteString Int
recvBufferSize
n <- withForeignPtr fp (\Ptr Word8
p -> Backend -> Ptr Word8 -> Int -> IO Int
backendRecv Backend
backend Ptr Word8
p Int
recvBufferSize)
pure (BI.BS fp (max 0 n))
startReader :: Connection -> IO ()
startReader :: Connection -> IO ()
startReader Connection
conn = do
arena <- Arena -> IO (IORef Arena)
forall a. a -> IO (IORef a)
newIORef Arena
emptyArena
let !transport = Connection -> IORef Transport
connTransport Connection
conn
!incoming = Connection -> TMVar ByteString
connIncoming Connection
conn
!endedVar = Connection -> TVar (Maybe SomeException)
connEnded Connection
conn
!backend = Connection -> Backend
connBackend Connection
conn
receive = IORef Transport -> IO Transport
forall a. IORef a -> IO a
readIORef IORef Transport
transport IO Transport -> (Transport -> IO ByteString) -> IO ByteString
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
TransportPlain Backend
b -> Backend -> IORef Arena -> IO ByteString
recvIntoArena Backend
b IORef Arena
arena
TransportTls Context
_ -> IORef Transport -> IO ByteString
recvTransport IORef Transport
transport IO ByteString -> (ByteString -> IO ByteString) -> IO ByteString
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IORef Arena -> ByteString -> IO ByteString
copyIntoArena IORef Arena
arena
plainLoop = do
bs <- IO ByteString
receive
atomically $ putTMVar incoming bs
plainLoop
!loop = case Connection -> Maybe Mars
connMars Connection
conn of
Maybe Mars
Nothing -> IO b
forall {b}. IO b
plainLoop
Just Mars{marsRegistry :: Mars -> TVar (IntMap SmpLink)
marsRegistry = !TVar (IntMap SmpLink)
registry} -> TVar (IntMap SmpLink) -> IO ByteString -> IO b
forall a. TVar (IntMap SmpLink) -> IO ByteString -> IO a
demultiplex TVar (IntMap SmpLink)
registry IO ByteString
receive
ended SomeException
e = STM () -> IO ()
forall a. STM a -> IO a
atomically (STM () -> IO ()) -> STM () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
prev <- TVar (Maybe SomeException) -> STM (Maybe SomeException)
forall a. TVar a -> STM a
readTVar TVar (Maybe SomeException)
endedVar
case prev of
Just SomeException
_ -> () -> STM ()
forall a. a -> STM a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
Maybe SomeException
Nothing -> TVar (Maybe SomeException) -> Maybe SomeException -> STM ()
forall a. TVar a -> a -> STM ()
writeTVar TVar (Maybe SomeException)
endedVar (Maybe SomeException -> STM ()) -> Maybe SomeException -> STM ()
forall a b. (a -> b) -> a -> b
$ SomeException -> Maybe SomeException
forall a. a -> Maybe a
Just (SomeException -> Maybe SomeException)
-> SomeException -> Maybe SomeException
forall a b. (a -> b) -> a -> b
$ if
| Just (ConnectionClosed
_ :: ConnectionClosed) <- SomeException -> Maybe ConnectionClosed
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
e -> SomeException
e
| Just (ProtocolError
_ :: ProtocolError) <- SomeException -> Maybe ProtocolError
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
e -> SomeException
e
| Bool
otherwise -> ConnectionBroken -> SomeException
forall e. Exception e => e -> SomeException
toException (UnusableReason -> ConnectionBroken
ConnectionBroken (SomeException -> UnusableReason
ReaderThreadDied SomeException
e))
let fork :: ((forall a. IO a -> IO a) -> IO ()) -> IO ThreadId
fork (forall a. IO a -> IO a) -> IO ()
act
| Connection -> Bool
connPinReader Connection
conn = do
(cap, _) <- ThreadId -> IO (Int, Bool)
threadCapability (ThreadId -> IO (Int, Bool)) -> IO ThreadId -> IO (Int, Bool)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO ThreadId
myThreadId
forkOnWithUnmask cap act
| Bool
otherwise = ((forall a. IO a -> IO a) -> IO ()) -> IO ThreadId
forkIOWithUnmask (forall a. IO a -> IO a) -> IO ()
act
tid <- mask_ $ fork $ \forall a. IO a -> IO a
unmask ->
IO () -> IO (Either SomeException ())
forall e a. Exception e => IO a -> IO (Either e a)
try (IO () -> IO ()
forall a. IO a -> IO a
unmask IO ()
forall {b}. IO b
loop) IO (Either SomeException ())
-> (Either SomeException () -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (SomeException -> IO ())
-> (() -> IO ()) -> Either SomeException () -> IO ()
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either SomeException -> IO ()
ended (\() -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ())
labelThread tid "hmssql: connection reader"
weakTid <- mkWeakThreadId tid
writeIORef (connReader conn) (Just weakTid)
_ <- mkWeakIORef (connAlive conn) (stopReader backend weakTid >> backendClose backend)
pure ()
demultiplex :: TVar (IntMap.IntMap SmpLink) -> IO B.ByteString -> IO a
demultiplex :: forall a. TVar (IntMap SmpLink) -> IO ByteString -> IO a
demultiplex TVar (IntMap SmpLink)
registry IO ByteString
receive = ByteString -> IO a
forall {a}. ByteString -> IO a
go ByteString
B.empty
where
go :: ByteString -> IO a
go ByteString
buf
| ByteString -> Int
B.length ByteString
buf Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
smpHeaderLength = ByteString -> IO a
more ByteString
buf
| ByteString -> Word8
BU.unsafeHead ByteString
buf Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
smpIdentifier = [Char] -> IO a
forall a. [Char] -> IO a
violation [Char]
"a packet that is not an SMP packet"
| Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
smpHeaderLength Bool -> Bool -> Bool
|| Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
smpHeaderLength Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
65535 = [Char] -> IO a
forall a. [Char] -> IO a
violation [Char]
"an SMP packet of an impossible length"
| SmpHeader -> Word8
smpFlags SmpHeader
hdr Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= SmpFlag -> Word8
smpFlagWord SmpFlag
SmpData Bool -> Bool -> Bool
&& Int
len Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
smpHeaderLength = [Char] -> IO a
forall a. [Char] -> IO a
violation [Char]
"a control packet with a payload"
| ByteString -> Int
B.length ByteString
buf Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
len = ByteString -> IO a
more ByteString
buf
| Bool
otherwise = do
STM (Maybe SomeException) -> IO (Maybe SomeException)
forall a. STM a -> IO a
atomically (SmpHeader -> ByteString -> STM (Maybe SomeException)
packet SmpHeader
hdr (Int -> ByteString -> ByteString
BU.unsafeTake Int
len ByteString
buf)) IO (Maybe SomeException) -> (Maybe SomeException -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (SomeException -> IO (ZonkAny 3)) -> Maybe SomeException -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ SomeException -> IO (ZonkAny 3)
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO
ByteString -> IO a
go (Int -> ByteString -> ByteString
BU.unsafeDrop Int
len ByteString
buf)
where
hdr :: SmpHeader
hdr = ByteString -> SmpHeader
readSmpHeader ByteString
buf
len :: Int
len = Word32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (SmpHeader -> Word32
smpLength SmpHeader
hdr) :: Int
more :: ByteString -> IO a
more ByteString
buf = do
bs <- IO ByteString
receive
go (if B.null buf then bs else buf <> bs)
violation :: String -> IO a
violation :: forall a. [Char] -> IO a
violation [Char]
what = ProtocolError -> IO a
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO (ProtocolError -> IO a) -> ProtocolError -> IO a
forall a b. (a -> b) -> a -> b
$ [Char] -> ProtocolError
ProtocolError ([Char] -> ProtocolError) -> [Char] -> ProtocolError
forall a b. (a -> b) -> a -> b
$ [Char]
"SMP: the server sent " [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ [Char]
what
wrong :: [Char] -> f (Maybe SomeException)
wrong [Char]
what = Maybe SomeException -> f (Maybe SomeException)
forall a. a -> f a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe SomeException -> f (Maybe SomeException))
-> Maybe SomeException -> f (Maybe SomeException)
forall a b. (a -> b) -> a -> b
$ SomeException -> Maybe SomeException
forall a. a -> Maybe a
Just (SomeException -> Maybe SomeException)
-> SomeException -> Maybe SomeException
forall a b. (a -> b) -> a -> b
$ ProtocolError -> SomeException
forall e. Exception e => e -> SomeException
toException (ProtocolError -> SomeException) -> ProtocolError -> SomeException
forall a b. (a -> b) -> a -> b
$ [Char] -> ProtocolError
ProtocolError ([Char] -> ProtocolError) -> [Char] -> ProtocolError
forall a b. (a -> b) -> a -> b
$ [Char]
"SMP: the server sent " [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ [Char]
what
packet :: SmpHeader -> B.ByteString -> STM (Maybe SomeException)
packet :: SmpHeader -> ByteString -> STM (Maybe SomeException)
packet SmpHeader
hdr ByteString
bytes = do
links <- TVar (IntMap SmpLink) -> STM (IntMap SmpLink)
forall a. TVar a -> STM a
readTVar TVar (IntMap SmpLink)
registry
case IntMap.lookup (fromIntegral (smpSession hdr)) links of
Maybe SmpLink
Nothing -> [Char] -> STM (Maybe SomeException)
forall {f :: * -> *}.
Applicative f =>
[Char] -> f (Maybe SomeException)
wrong ([Char]
"a packet for session " [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ Word16 -> [Char]
forall a. Show a => a -> [Char]
show (SmpHeader -> Word16
smpSession SmpHeader
hdr) [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ [Char]
", which is not open")
Just SmpLink
link -> do
highWater <- TVar Word32 -> STM Word32
forall a. TVar a -> STM a
readTVar (SmpLink -> TVar Word32
linkSendHighWater SmpLink
link)
let grown = Word32 -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (SmpHeader -> Word32
smpWindow SmpHeader
hdr Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
- Word32
highWater) :: Int32
if grown < 0
then wrong "a window smaller than its last"
else do
when (grown > 0) $ writeTVar (linkSendHighWater link) (smpWindow hdr)
if
| flags == smpFlagWord SmpData -> dataPacket link
| flags == smpFlagWord SmpAck -> pure Nothing
| flags == smpFlagWord SmpFin -> do
closing <- readTVar (linkClosing link)
if closing
then Nothing <$ writeTVar registry (IntMap.delete (fromIntegral (smpSession hdr)) links)
else pure (Just (toException (ConnectionClosedBy ClosedByServer)))
| otherwise -> wrong ("a packet with flags " ++ show flags)
where
flags :: Word8
flags = SmpHeader -> Word8
smpFlags SmpHeader
hdr
tds :: ByteString
tds = Int -> ByteString -> ByteString
BU.unsafeDrop Int
smpHeaderLength ByteString
bytes
dataPacket :: SmpLink -> STM (Maybe SomeException)
dataPacket SmpLink
link = do
received <- TVar Word32 -> STM Word32
forall a. TVar a -> STM a
readTVar (SmpLink -> TVar Word32
linkRecvSeq SmpLink
link)
accepted <- readTVar (linkRecvHighWater link)
if
| smpSeqNum hdr /= received + 1 -> wrong "a DATA packet out of sequence"
| (fromIntegral (accepted - smpSeqNum hdr) :: Int32) < 0 -> wrong "a DATA packet beyond the window"
| B.length tds < headerLength || fromIntegral (headerPacketLength (readHeader tds)) /= B.length tds ->
wrong "a DATA packet that is not one TDS packet"
| otherwise -> do
writeTVar (linkRecvSeq link) (smpSeqNum hdr)
when (headerStatus (readHeader tds) `hasStatus` statusEndOfMessage) $
modifyTVar' (linkEoms link) (+ 1)
writeTQueue (linkIncoming link) tds
pure Nothing
stopReader :: Backend -> Weak ThreadId -> IO ()
stopReader :: Backend -> Weak ThreadId -> IO ()
stopReader Backend
backend Weak ThreadId
weakTid = do
Backend -> IO ()
backendStopReceiving Backend
backend
Weak ThreadId -> IO (Maybe ThreadId)
forall v. Weak v -> IO (Maybe v)
deRefWeak Weak ThreadId
weakTid IO (Maybe ThreadId) -> (Maybe ThreadId -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (ThreadId -> IO ()) -> Maybe ThreadId -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ ThreadId -> IO ()
killThread
data Arena = Arena !(ForeignPtr Word8) !Int
emptyArena :: Arena
emptyArena :: Arena
emptyArena = ForeignPtr Word8 -> Int -> Arena
Arena ForeignPtr Word8
nullForeignPtr Int
arenaSize
where
BI.BS ForeignPtr Word8
nullForeignPtr Int
_ = ByteString
B.empty
arenaSize :: Int
arenaSize :: Int
arenaSize = Int
32768
copyIntoArena :: IORef Arena -> B.ByteString -> IO B.ByteString
copyIntoArena :: IORef Arena -> ByteString -> IO ByteString
copyIntoArena IORef Arena
ref bs :: ByteString
bs@(BI.BS ForeignPtr Word8
src Int
len)
| Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
4096 = ByteString -> IO ByteString
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ByteString
bs
| Bool
otherwise = do
Arena fp0 used0 <- IORef Arena -> IO Arena
forall a. IORef a -> IO a
readIORef IORef Arena
ref
(fp, used) <-
if used0 + len <= arenaSize
then pure (fp0, used0)
else (,0) <$> BI.mallocByteString arenaSize
BI.unsafeWithForeignPtr fp $ \Ptr Word8
dst -> ForeignPtr Word8 -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
BI.unsafeWithForeignPtr ForeignPtr Word8
src ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
s ->
Ptr Word8 -> Ptr Word8 -> Int -> IO ()
forall a. Ptr a -> Ptr a -> Int -> IO ()
copyBytes (Ptr Word8
dst Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
used) Ptr Word8
s Int
len
writeIORef ref (Arena fp (used + len))
pure (BI.BS (fp `plusForeignPtr` used) len)
recvIntoArena :: Backend -> IORef Arena -> IO B.ByteString
recvIntoArena :: Backend -> IORef Arena -> IO ByteString
recvIntoArena Backend
backend IORef Arena
ref = do
Arena fp0 used0 <- IORef Arena -> IO Arena
forall a. IORef a -> IO a
readIORef IORef Arena
ref
(fp, used) <-
if arenaSize - used0 >= minRecvSpace
then pure (fp0, used0)
else (,0) <$> BI.mallocByteString arenaSize
n <- withForeignPtr fp (\Ptr Word8
p -> Backend -> Ptr Word8 -> Int -> IO Int
backendRecv Backend
backend (Ptr Word8
p Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
used) (Int
arenaSize Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
used))
`catch` (throwIO . transportError)
when (n <= 0) $ throwIO ConnectionClosed
writeIORef ref (Arena fp (used + n))
pure (BI.BS (fp `plusForeignPtr` used) n)
newBufferedRecv :: Backend -> IO (Int -> IO B.ByteString)
newBufferedRecv :: Backend -> IO (Int -> IO ByteString)
newBufferedRecv Backend
backend = do
buf <- Int -> IO (ForeignPtr (ZonkAny 2))
forall a. Int -> IO (ForeignPtr a)
BI.mallocByteString Int
recvBufferSize
window <- newIORef (0 :: Int, 0 :: Int)
let recvN Int
n = do
(start, end) <- IORef (Int, Int) -> IO (Int, Int)
forall a. IORef a -> IO a
readIORef IORef (Int, Int)
window
let have = Int
end Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
start
if
| have >= n -> do
writeIORef window (start + n, end)
copyOut start n
| n > recvBufferSize -> do
writeIORef window (0, 0)
BI.createUptoN n $ \Ptr Word8
dst -> do
ForeignPtr (ZonkAny 2) -> (Ptr (ZonkAny 2) -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr (ZonkAny 2)
buf ((Ptr (ZonkAny 2) -> IO ()) -> IO ())
-> (Ptr (ZonkAny 2) -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr (ZonkAny 2)
src -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
forall a. Ptr a -> Ptr a -> Int -> IO ()
copyBytes Ptr Word8
dst (Ptr (ZonkAny 2)
src Ptr (ZonkAny 2) -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
start) Int
have
let fill :: Int -> IO Int
fill Int
k
| Int
k Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
n = Int -> IO Int
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
k
| Bool
otherwise = Backend -> Ptr Word8 -> Int -> IO Int
backendRecv Backend
backend (Ptr Word8
dst Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
k) (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
k) IO Int -> (Int -> IO Int) -> IO Int
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Int
r | Int
r Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0 -> Int -> IO Int
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
k
| Bool
otherwise -> Int -> IO Int
fill (Int
k Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
r)
Int -> IO Int
fill Int
have
| otherwise -> do
when (start > 0 && have > 0) $ withForeignPtr buf $ \Ptr (ZonkAny 2)
p ->
Ptr (ZonkAny 2) -> Ptr (ZonkAny 2) -> Int -> IO ()
forall a. Ptr a -> Ptr a -> Int -> IO ()
moveBytes Ptr (ZonkAny 2)
p (Ptr (ZonkAny 2)
p Ptr (ZonkAny 2) -> Int -> Ptr (ZonkAny 2)
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
start) Int
have
writeIORef window (0, have)
r <- withForeignPtr buf $ \Ptr (ZonkAny 2)
p ->
Backend -> Ptr Word8 -> Int -> IO Int
backendRecv Backend
backend (Ptr (ZonkAny 2)
p Ptr (ZonkAny 2) -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
have) (Int
recvBufferSize Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
have)
if r <= 0
then writeIORef window (0, 0) >> copyOut 0 have
else writeIORef window (0, have + r) >> recvN n
copyOut Int
off Int
len = Int -> (Ptr Word8 -> IO ()) -> IO ByteString
BI.create Int
len ((Ptr Word8 -> IO ()) -> IO ByteString)
-> (Ptr Word8 -> IO ()) -> IO ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
dst ->
ForeignPtr (ZonkAny 2) -> (Ptr (ZonkAny 2) -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr (ZonkAny 2)
buf ((Ptr (ZonkAny 2) -> IO ()) -> IO ())
-> (Ptr (ZonkAny 2) -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr (ZonkAny 2)
src -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
forall a. Ptr a -> Ptr a -> Int -> IO ()
copyBytes Ptr Word8
dst (Ptr (ZonkAny 2)
src Ptr (ZonkAny 2) -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
off) Int
len
pure recvN
recvBufferSize :: Int
recvBufferSize :: Int
recvBufferSize = Int
32768
minRecvSpace :: Int
minRecvSpace :: Int
minRecvSpace = Int
8192
closeConnection :: Connection -> IO () -> IO ()
closeConnection :: Connection -> IO () -> IO ()
closeConnection Connection
conn IO ()
goodbye = IORef () -> IO () -> IO ()
forall a b. a -> IO b -> IO b
keepAlive (Connection -> IORef ()
connAlive Connection
conn) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
STM () -> IO ()
forall a. STM a -> IO a
atomically (STM () -> IO ()) -> STM () -> IO ()
forall a b. (a -> b) -> a -> b
$ TVar (Maybe SomeException) -> Maybe SomeException -> STM ()
forall a. TVar a -> a -> STM ()
writeTVar (Connection -> TVar (Maybe SomeException)
connEnded Connection
conn) (SomeException -> Maybe SomeException
forall a. a -> Maybe a
Just (ConnectionClosed -> SomeException
forall e. Exception e => e -> SomeException
toException (CloseReason -> ConnectionClosed
ConnectionClosedBy CloseReason
ClosedByClient)))
IORef (Maybe (Weak ThreadId)) -> IO (Maybe (Weak ThreadId))
forall a. IORef a -> IO a
readIORef (Connection -> IORef (Maybe (Weak ThreadId))
connReader Connection
conn) IO (Maybe (Weak ThreadId))
-> (Maybe (Weak ThreadId) -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Weak ThreadId -> IO ()) -> Maybe (Weak ThreadId) -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (Backend -> Weak ThreadId -> IO ()
stopReader Backend
backend)
((forall a. IO a -> IO a) -> IO ()) -> IO ()
forall b. ((forall a. IO a -> IO a) -> IO b) -> IO b
mask (((forall a. IO a -> IO a) -> IO ()) -> IO ())
-> ((forall a. IO a -> IO a) -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \forall a. IO a -> IO a
restore -> do
free <- Maybe () -> Bool
forall a. Maybe a -> Bool
isJust (Maybe () -> Bool) -> IO (Maybe ()) -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> MVar () -> IO (Maybe ())
forall a. MVar a -> IO (Maybe a)
tryTakeMVar MVar ()
lock
unless free $ do
backendShutdown backend
restore (takeMVar lock)
((when free (restore goodbye) `finally` backendClose backend) `finally` putMVar lock ())
where
lock :: MVar ()
lock = Connection -> MVar ()
connSendLock Connection
conn
backend :: Backend
backend = Connection -> Backend
connBackend Connection
conn
releaseTransport :: Connection -> IO ()
releaseTransport :: Connection -> IO ()
releaseTransport Connection
conn = do
IORef Transport -> Transport -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (Connection -> IORef Transport
connTransport Connection
conn) (Backend -> Transport
TransportPlain (Connection -> Backend
connBackend Connection
conn))
sessions <- Connection -> IO [Session]
allSessions Connection
conn
forM_ sessions $ \Session
sess -> do
IORef [ByteString] -> [ByteString] -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (Session -> IORef [ByteString]
sessRecvBuffer Session
sess) []
IORef (Maybe ActiveResponse) -> Maybe ActiveResponse -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (Session -> IORef (Maybe ActiveResponse)
sessResponse Session
sess) Maybe ActiveResponse
forall a. Maybe a
Nothing
Maybe SmpSession -> (SmpSession -> IO ()) -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ (Session -> Maybe SmpSession
sessSmp Session
sess) ((SmpSession -> IO ()) -> IO ()) -> (SmpSession -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \SmpSession
smp -> STM () -> IO ()
forall a. STM a -> IO a
atomically (STM () -> IO ()) -> STM () -> IO ()
forall a b. (a -> b) -> a -> b
$ STM [ByteString] -> STM ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (STM [ByteString] -> STM ()) -> STM [ByteString] -> STM ()
forall a b. (a -> b) -> a -> b
$ TQueue ByteString -> STM [ByteString]
forall a. TQueue a -> STM [a]
flushTQueue (SmpLink -> TQueue ByteString
linkIncoming (SmpSession -> SmpLink
smpLink SmpSession
smp))
atomically $ void $ tryTakeTMVar (connIncoming conn)
recvSome :: Connection -> IO B.ByteString
recvSome :: Connection -> IO ByteString
recvSome Connection
conn = IORef (Maybe (Weak ThreadId)) -> IO (Maybe (Weak ThreadId))
forall a. IORef a -> IO a
readIORef (Connection -> IORef (Maybe (Weak ThreadId))
connReader Connection
conn) IO (Maybe (Weak ThreadId))
-> (Maybe (Weak ThreadId) -> IO ByteString) -> IO ByteString
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Maybe (Weak ThreadId)
Nothing -> Connection -> IO ByteString
recvDirect Connection
conn
Just Weak ThreadId
_ -> STM ByteString -> IO ByteString
forall a. STM a -> IO a
atomically (STM ByteString -> IO ByteString)
-> STM ByteString -> IO ByteString
forall a b. (a -> b) -> a -> b
$ do
ended <- TVar (Maybe SomeException) -> STM (Maybe SomeException)
forall a. TVar a -> STM a
readTVar (Connection -> TVar (Maybe SomeException)
connEnded Connection
conn)
case ended of
Just SomeException
e | SomeException -> Bool
closedByClient SomeException
e -> SomeException -> STM ByteString
forall e a. Exception e => e -> STM a
throwSTM SomeException
e
Maybe SomeException
_ -> TMVar ByteString -> STM ByteString
forall a. TMVar a -> STM a
takeTMVar (Connection -> TMVar ByteString
connIncoming Connection
conn) STM ByteString -> STM ByteString -> STM ByteString
forall a. STM a -> STM a -> STM a
`orElse` STM ByteString
-> (SomeException -> STM ByteString)
-> Maybe SomeException
-> STM ByteString
forall b a. b -> (a -> b) -> Maybe a -> b
maybe STM ByteString
forall a. STM a
retry SomeException -> STM ByteString
forall e a. Exception e => e -> STM a
throwSTM Maybe SomeException
ended
recvMore :: Connection -> IO ()
recvMore :: Connection -> IO ()
recvMore Connection
conn = IO () -> IO ()
forall a. IO a -> IO a
mask_ (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
more <- Connection -> IO ByteString
recvSome Connection
conn
modifyIORef' (primaryBuffer conn) (++ [more])
primaryBuffer :: Connection -> IORef [B.ByteString]
primaryBuffer :: Connection -> IORef [ByteString]
primaryBuffer = Session -> IORef [ByteString]
sessRecvBuffer (Session -> IORef [ByteString])
-> (Connection -> Session) -> Connection -> IORef [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Connection -> Session
connPrimary
recvExactly :: Connection -> Int -> IO B.ByteString
recvExactly :: Connection -> Int -> IO ByteString
recvExactly Connection
conn Int
n = Connection -> Int -> IO ()
fillBuffer Connection
conn Int
n IO () -> IO ByteString -> IO ByteString
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Connection -> Int -> IO ByteString
takeBytes Connection
conn Int
n
fillBuffer :: Connection -> Int -> IO ()
fillBuffer :: Connection -> Int -> IO ()
fillBuffer Connection
conn Int
n = IO ()
go
where
go :: IO ()
go = do
chunks <- IORef [ByteString] -> IO [ByteString]
forall a. IORef a -> IO a
readIORef (Connection -> IORef [ByteString]
primaryBuffer Connection
conn)
unless (sum (map B.length chunks) >= n) $ recvMore conn >> go
peekBytes :: Connection -> Int -> IO B.ByteString
peekBytes :: Connection -> Int -> IO ByteString
peekBytes Connection
conn Int
n = (ByteString, [ByteString]) -> ByteString
forall a b. (a, b) -> a
fst ((ByteString, [ByteString]) -> ByteString)
-> ([ByteString] -> (ByteString, [ByteString]))
-> [ByteString]
-> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [ByteString] -> (ByteString, [ByteString])
splitChunks Int
n ([ByteString] -> ByteString) -> IO [ByteString] -> IO ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IORef [ByteString] -> IO [ByteString]
forall a. IORef a -> IO a
readIORef (Connection -> IORef [ByteString]
primaryBuffer Connection
conn)
takeBytes :: Connection -> Int -> IO B.ByteString
takeBytes :: Connection -> Int -> IO ByteString
takeBytes Connection
conn Int
n = do
(now, later) <- Int -> [ByteString] -> (ByteString, [ByteString])
splitChunks Int
n ([ByteString] -> (ByteString, [ByteString]))
-> IO [ByteString] -> IO (ByteString, [ByteString])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IORef [ByteString] -> IO [ByteString]
forall a. IORef a -> IO a
readIORef (Connection -> IORef [ByteString]
primaryBuffer Connection
conn)
writeIORef (primaryBuffer conn) later
pure now
splitChunks :: Int -> [B.ByteString] -> (B.ByteString, [B.ByteString])
splitChunks :: Int -> [ByteString] -> (ByteString, [ByteString])
splitChunks Int
n = \case
ByteString
c : [ByteString]
cs | ByteString -> Int
B.length ByteString
c Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
n ->
let (ByteString
now, ByteString
rest) = Int -> ByteString -> (ByteString, ByteString)
B.splitAt Int
n ByteString
c
in (ByteString
now, if ByteString -> Bool
B.null ByteString
rest then [ByteString]
cs else ByteString
rest ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
: [ByteString]
cs)
[ByteString]
chunks -> Int -> [ByteString] -> [ByteString] -> (ByteString, [ByteString])
go Int
n [] [ByteString]
chunks
where
go :: Int -> [ByteString] -> [ByteString] -> (ByteString, [ByteString])
go Int
_ [ByteString]
acc [] = ([ByteString] -> ByteString
B.concat ([ByteString] -> [ByteString]
forall a. [a] -> [a]
reverse [ByteString]
acc), [])
go Int
k [ByteString]
acc (ByteString
c : [ByteString]
cs)
| ByteString -> Int
B.length ByteString
c Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
k = Int -> [ByteString] -> [ByteString] -> (ByteString, [ByteString])
go (Int
k Int -> Int -> Int
forall a. Num a => a -> a -> a
- ByteString -> Int
B.length ByteString
c) (ByteString
c ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
: [ByteString]
acc) [ByteString]
cs
| Bool
otherwise =
let (ByteString
now, ByteString
rest) = Int -> ByteString -> (ByteString, ByteString)
B.splitAt Int
k ByteString
c
in ([ByteString] -> ByteString
B.concat ([ByteString] -> [ByteString]
forall a. [a] -> [a]
reverse (ByteString
now ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
: [ByteString]
acc)), if ByteString -> Bool
B.null ByteString
rest then [ByteString]
cs else ByteString
rest ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
: [ByteString]
cs)
sendBytes :: Connection -> [B.ByteString] -> IO ()
sendBytes :: Connection -> [ByteString] -> IO ()
sendBytes Connection
conn [ByteString]
packets = Connection -> (Transport -> [ByteString]) -> IO ()
sendWith Connection
conn ([ByteString] -> Transport -> [ByteString]
forall a b. a -> b -> a
const [ByteString]
packets)
sendFramed :: Connection -> Session -> TdsContext -> PacketType -> PacketStatus -> LB.ByteString -> IO ()
sendFramed :: Connection
-> Session
-> TdsContext
-> PacketType
-> PacketStatus
-> ByteString
-> IO ()
sendFramed Connection
conn Session
sess TdsContext
ctx PacketType
ptype PacketStatus
status ByteString
body =
Connection
-> Session
-> TdsContext
-> PacketType
-> PacketStatus
-> (PacketWriter -> IO ())
-> IO (Either SomeException ())
forall a.
Connection
-> Session
-> TdsContext
-> PacketType
-> PacketStatus
-> (PacketWriter -> IO a)
-> IO (Either SomeException a)
sendPacketsWith Connection
conn Session
sess TdsContext
ctx PacketType
ptype PacketStatus
status (\PacketWriter
writer -> PacketWriter -> Builder -> IO ()
writeBuilder PacketWriter
writer (ByteString -> Builder
BB.lazyByteString ByteString
body))
IO (Either SomeException ())
-> (Either SomeException () -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (SomeException -> IO ())
-> (() -> IO ()) -> Either SomeException () -> IO ()
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (Connection -> SomeException -> IO ()
forall a. Connection -> SomeException -> IO a
sendFailed Connection
conn) () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
breakingOnFailure :: Connection -> IO a -> IO a
breakingOnFailure :: forall a. Connection -> IO a -> IO a
breakingOnFailure Connection
conn IO a
act = IO a
act IO a -> (SomeException -> IO a) -> IO a
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catch` \SomeException
e -> do
Backend -> IO ()
backendShutdown (Connection -> Backend
connBackend Connection
conn) IO () -> (IOException -> IO ()) -> IO ()
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catch` \(IOException
_ :: IOException) -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
Connection -> SomeException -> IO a
forall a. Connection -> SomeException -> IO a
sendFailed Connection
conn SomeException
e
sendSmpPacket :: Connection -> SmpSession -> PacketSink
sendSmpPacket :: Connection -> SmpSession -> PacketSink
sendSmpPacket Connection
conn SmpSession
smp ByteString
packet = do
_ <- Connection -> SmpSession -> IO Int
awaitSmpWindow Connection
conn SmpSession
smp
writeSmpData conn smp [packet]
awaitSmpWindow :: Connection -> SmpSession -> IO Int
awaitSmpWindow :: Connection -> SmpSession -> IO Int
awaitSmpWindow Connection
conn SmpSession
smp = do
sent <- IORef Word32 -> IO Word32
forall a. IORef a -> IO a
readIORef (SmpSession -> IORef Word32
smpSendSeq SmpSession
smp)
atomically $ do
readTVar (connEnded conn) >>= mapM_ throwSTM
highWater <- readTVar (linkSendHighWater (smpLink smp))
let room = Word32 -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32
highWater Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
- Word32
sent) :: Int32
when (room <= 0) retry
pure (fromIntegral room)
writeSmpData :: Connection -> SmpSession -> [B.ByteString] -> IO ()
writeSmpData :: Connection -> SmpSession -> [ByteString] -> IO ()
writeSmpData Connection
conn SmpSession
smp [ByteString]
packets = Connection -> IO [[ByteString]] -> IO ()
writeSmp Connection
conn (IO [[ByteString]] -> IO ()) -> IO [[ByteString]] -> IO ()
forall a b. (a -> b) -> a -> b
$ do
sent <- IORef Word32 -> IO Word32
forall a. IORef a -> IO a
readIORef (SmpSession -> IORef Word32
smpSendSeq SmpSession
smp)
window <- readTVarIO (linkRecvHighWater (smpLink smp))
writeIORef (smpSendSeq smp) (sent + fromIntegral (length packets))
writeIORef (smpAdvertised smp) window
pure (zipWith (smpDataPacket (smpSid smp) window) (iterate (+ 1) (sent + 1)) packets)
sendSmpControl :: Connection -> SmpSession -> SmpFlag -> IO ()
sendSmpControl :: Connection -> SmpSession -> SmpFlag -> IO ()
sendSmpControl Connection
conn SmpSession
smp SmpFlag
flag = Connection -> IO () -> IO ()
forall a b. a -> IO b -> IO b
keepAlive Connection
conn (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ IO () -> IO ()
forall a. IO a -> IO a
mask_ (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Connection -> IO () -> IO ()
forall a. Connection -> IO a -> IO a
breakingOnFailure Connection
conn (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Connection -> IO [[ByteString]] -> IO ()
writeSmp Connection
conn (SmpFlag -> SmpSession -> IO [[ByteString]]
controlPacket SmpFlag
flag SmpSession
smp)
controlPacket :: SmpFlag -> SmpSession -> IO [[B.ByteString]]
controlPacket :: SmpFlag -> SmpSession -> IO [[ByteString]]
controlPacket SmpFlag
flag SmpSession
smp = do
seqNum <- if SmpFlag
flag SmpFlag -> SmpFlag -> Bool
forall a. Eq a => a -> a -> Bool
== SmpFlag
SmpSyn then Word32 -> IO Word32
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Word32
0 else IORef Word32 -> IO Word32
forall a. IORef a -> IO a
readIORef (SmpSession -> IORef Word32
smpSendSeq SmpSession
smp)
window <- readTVarIO (linkRecvHighWater (smpLink smp))
writeIORef (smpAdvertised smp) window
pure [[smpControlPacket flag (smpSid smp) seqNum window]]
writeSmp :: Connection -> IO [[B.ByteString]] -> IO ()
writeSmp :: Connection -> IO [[ByteString]] -> IO ()
writeSmp Connection
conn IO [[ByteString]]
packets = MVar () -> (() -> IO ()) -> IO ()
forall a b. MVar a -> (a -> IO b) -> IO b
withMVar (Connection -> MVar ()
connSendLock Connection
conn) ((() -> IO ()) -> IO ()) -> (() -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \() -> do
TVar (Maybe SomeException) -> IO (Maybe SomeException)
forall a. TVar a -> IO a
readTVarIO (Connection -> TVar (Maybe SomeException)
connEnded Connection
conn) IO (Maybe SomeException) -> (Maybe SomeException -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (SomeException -> IO (ZonkAny 0)) -> Maybe SomeException -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ SomeException -> IO (ZonkAny 0)
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO
smpPackets <- IO [[ByteString]]
packets
readIORef (connTransport conn) >>= \case
TransportPlain Backend
backend -> Backend -> [[ByteString]] -> IO ()
backendSendMany Backend
backend [[ByteString]]
smpPackets
TransportTls Context
ctx -> do
let gather :: SendGather
gather = Connection -> SendGather
connSendGather Connection
conn
backend :: Backend
backend = Connection -> Backend
connBackend Connection
conn
SendGather -> IO ()
startGathering SendGather
gather
(([ByteString] -> IO ()) -> [[ByteString]] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (Context -> ByteString -> IO ()
forall (m :: * -> *). MonadIO m => Context -> ByteString -> m ()
TLS.sendData Context
ctx (ByteString -> IO ())
-> ([ByteString] -> ByteString) -> [ByteString] -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
LB.fromStrict (ByteString -> ByteString)
-> ([ByteString] -> ByteString) -> [ByteString] -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString] -> ByteString
B.concat) [[ByteString]]
smpPackets IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Bool -> SendGather -> Backend -> IO ()
endGathering Bool
True SendGather
gather Backend
backend)
IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO a
`onException` Bool -> SendGather -> Backend -> IO ()
endGathering Bool
False SendGather
gather Backend
backend
sendWith :: Connection -> (Transport -> [B.ByteString]) -> IO ()
sendWith :: Connection -> (Transport -> [ByteString]) -> IO ()
sendWith Connection
conn Transport -> [ByteString]
chunksFor = Connection -> IO () -> IO ()
forall a b. a -> IO b -> IO b
keepAlive Connection
conn (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ MVar () -> (() -> IO ()) -> IO ()
forall a b. MVar a -> (a -> IO b) -> IO b
withMVar (Connection -> MVar ()
connSendLock Connection
conn) ((() -> IO ()) -> IO ()) -> (() -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \() -> IO () -> IO ()
forall a. IO a -> IO a
mask_ (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
(TVar (Maybe SomeException) -> IO (Maybe SomeException)
forall a. TVar a -> IO a
readTVarIO (Connection -> TVar (Maybe SomeException)
connEnded Connection
conn) IO (Maybe SomeException) -> (Maybe SomeException -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (SomeException -> IO (ZonkAny 4)) -> Maybe SomeException -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ SomeException -> IO (ZonkAny 4)
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO) IO () -> (SomeException -> IO ()) -> IO ()
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catch` Connection -> SomeException -> IO ()
forall a. Connection -> SomeException -> IO a
sendFailed Connection
conn
transport <- IORef Transport -> IO Transport
forall a. IORef a -> IO a
readIORef (Connection -> IORef Transport
connTransport Connection
conn)
let sendAll = case Transport
transport of
TransportPlain Backend
backend -> PacketSink -> [ByteString] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (Backend -> PacketSink
backendSend Backend
backend) (Transport -> [ByteString]
chunksFor Transport
transport)
TransportTls Context
ctx -> do
let gather :: SendGather
gather = Connection -> SendGather
connSendGather Connection
conn
backend :: Backend
backend = Connection -> Backend
connBackend Connection
conn
SendGather -> IO ()
startGathering SendGather
gather
(PacketSink -> [ByteString] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (Context -> ByteString -> IO ()
forall (m :: * -> *). MonadIO m => Context -> ByteString -> m ()
TLS.sendData Context
ctx (ByteString -> IO ()) -> (ByteString -> ByteString) -> PacketSink
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
LB.fromStrict) (Transport -> [ByteString]
chunksFor Transport
transport) IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Bool -> SendGather -> Backend -> IO ()
endGathering Bool
True SendGather
gather Backend
backend)
IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO a
`onException` Bool -> SendGather -> Backend -> IO ()
endGathering Bool
False SendGather
gather Backend
backend
breakingOnFailure conn sendAll
sendFailed :: Connection -> SomeException -> IO a
sendFailed :: forall a. Connection -> SomeException -> IO a
sendFailed Connection
conn SomeException
e = do
e' <- case SomeException -> Maybe ConnectionClosed
forall e. Exception e => SomeException -> Maybe e
fromException (SomeException -> SomeException
transportError SomeException
e) of
Just (ConnectionClosed
closed :: ConnectionClosed) -> SomeException -> Maybe SomeException -> SomeException
forall a. a -> Maybe a -> a
fromMaybe (ConnectionClosed -> SomeException
forall e. Exception e => e -> SomeException
toException ConnectionClosed
closed) (Maybe SomeException -> SomeException)
-> IO (Maybe SomeException) -> IO SomeException
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TVar (Maybe SomeException) -> IO (Maybe SomeException)
forall a. TVar a -> IO a
readTVarIO (Connection -> TVar (Maybe SomeException)
connEnded Connection
conn)
Maybe ConnectionClosed
Nothing -> SomeException -> IO SomeException
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure SomeException
e
markBroken conn (reasonFor SendFailed e')
throwIO e'
sendPackets :: forall a. Connection -> Session -> TdsContext -> PacketType -> (PacketWriter -> IO a) -> IO (Either SomeException a)
sendPackets :: forall a.
Connection
-> Session
-> TdsContext
-> PacketType
-> (PacketWriter -> IO a)
-> IO (Either SomeException a)
sendPackets Connection
conn Session
sess TdsContext
tdsCtx PacketType
ptype = Connection
-> Session
-> TdsContext
-> PacketType
-> PacketStatus
-> (PacketWriter -> IO a)
-> IO (Either SomeException a)
forall a.
Connection
-> Session
-> TdsContext
-> PacketType
-> PacketStatus
-> (PacketWriter -> IO a)
-> IO (Either SomeException a)
sendPacketsWith Connection
conn Session
sess TdsContext
tdsCtx PacketType
ptype (Word8 -> PacketStatus
PacketStatus Word8
0)
sendPacketsWith :: forall a. Connection -> Session -> TdsContext -> PacketType -> PacketStatus -> (PacketWriter -> IO a) -> IO (Either SomeException a)
sendPacketsWith :: forall a.
Connection
-> Session
-> TdsContext
-> PacketType
-> PacketStatus
-> (PacketWriter -> IO a)
-> IO (Either SomeException a)
sendPacketsWith Connection
conn Session
sess TdsContext
tdsCtx PacketType
ptype PacketStatus
status = Connection
-> Session
-> TdsContext
-> PacketType
-> PacketStatus
-> IO ()
-> (PacketWriter -> IO a)
-> IO (Either SomeException a)
forall a.
Connection
-> Session
-> TdsContext
-> PacketType
-> PacketStatus
-> IO ()
-> (PacketWriter -> IO a)
-> IO (Either SomeException a)
sendPacketsTracked Connection
conn Session
sess TdsContext
tdsCtx PacketType
ptype PacketStatus
status (() -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ())
sendPacketsTracked :: forall a. Connection -> Session -> TdsContext -> PacketType -> PacketStatus -> IO () -> (PacketWriter -> IO a) -> IO (Either SomeException a)
sendPacketsTracked :: forall a.
Connection
-> Session
-> TdsContext
-> PacketType
-> PacketStatus
-> IO ()
-> (PacketWriter -> IO a)
-> IO (Either SomeException a)
sendPacketsTracked Connection
conn Session
sess TdsContext
tdsCtx PacketType
ptype PacketStatus
status IO ()
onPacket PacketWriter -> IO a
produce = case Session -> Maybe SmpSession
sessSmp Session
sess of
Maybe SmpSession
Nothing -> Connection
-> IO (Either SomeException a) -> IO (Either SomeException a)
forall a b. a -> IO b -> IO b
keepAlive Connection
conn (IO (Either SomeException a) -> IO (Either SomeException a))
-> IO (Either SomeException a) -> IO (Either SomeException a)
forall a b. (a -> b) -> a -> b
$ MVar ()
-> (() -> IO (Either SomeException a))
-> IO (Either SomeException a)
forall a b. MVar a -> (a -> IO b) -> IO b
withMVar (Connection -> MVar ()
connSendLock Connection
conn) ((() -> IO (Either SomeException a))
-> IO (Either SomeException a))
-> (() -> IO (Either SomeException a))
-> IO (Either SomeException a)
forall a b. (a -> b) -> a -> b
$ \() -> IO (Either SomeException a) -> IO (Either SomeException a)
forall a. IO a -> IO a
mask_ (IO (Either SomeException a) -> IO (Either SomeException a))
-> IO (Either SomeException a) -> IO (Either SomeException a)
forall a b. (a -> b) -> a -> b
$ do
(TVar (Maybe SomeException) -> IO (Maybe SomeException)
forall a. TVar a -> IO a
readTVarIO (Connection -> TVar (Maybe SomeException)
connEnded Connection
conn) IO (Maybe SomeException) -> (Maybe SomeException -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (SomeException -> IO (ZonkAny 6)) -> Maybe SomeException -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ SomeException -> IO (ZonkAny 6)
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO) IO () -> (SomeException -> IO ()) -> IO ()
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catch` Connection -> SomeException -> IO ()
forall a. Connection -> SomeException -> IO a
sendFailed Connection
conn
transport <- IORef Transport -> IO Transport
forall a. IORef a -> IO a
readIORef (Connection -> IORef Transport
connTransport Connection
conn)
let run = case Transport
transport of
TransportPlain Backend
backend -> do
pending <- ([[ByteString]], Int) -> IO (IORef ([[ByteString]], Int))
forall a. a -> IO (IORef a)
newIORef ([], Int
0 :: Int)
let send ByteString
p = do
(ps, n) <- IORef ([[ByteString]], Int) -> IO ([[ByteString]], Int)
forall a. IORef a -> IO a
readIORef IORef ([[ByteString]], Int)
pending
let n' = Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ ByteString -> Int
B.length ByteString
p
if n' >= gatherLimit
then do
writeIORef pending ([], 0)
backendSendMany backend (reverse ([p] : ps)) `catch` sendFailure
else writeIORef pending ([p] : ps, n')
flush = do
(ps, _) <- IORef ([[ByteString]], Int) -> IO ([[ByteString]], Int)
forall a. IORef a -> IO a
readIORef IORef ([[ByteString]], Int)
pending
writeIORef pending ([], 0)
unless (null ps) $ backendSendMany backend (reverse ps) `catch` sendFailure
r <- writing send
flush
pure r
TransportTls Context
ctx -> do
let gather :: SendGather
gather = Connection -> SendGather
connSendGather Connection
conn
backend :: Backend
backend = Connection -> Backend
connBackend Connection
conn
SendGather -> IO ()
startGathering SendGather
gather
(do r <- PacketSink -> IO (Either SomeException a)
writing (\ByteString
p -> Context -> ByteString -> IO ()
forall (m :: * -> *). MonadIO m => Context -> ByteString -> m ()
TLS.sendData Context
ctx (ByteString -> ByteString
LB.fromStrict ByteString
p) IO () -> (SomeException -> IO ()) -> IO ()
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catch` SomeException -> IO ()
forall b. SomeException -> IO b
sendFailure)
endGathering True gather backend `catch` sendFailure
pure r)
IO (Either SomeException a) -> IO () -> IO (Either SomeException a)
forall a b. IO a -> IO b -> IO a
`onException` Bool -> SendGather -> Backend -> IO ()
endGathering Bool
False SendGather
gather Backend
backend
breakingOnFailure conn (run `catch` (throwIO . unwrap))
Just SmpSession
smp -> Connection
-> IO (Either SomeException a) -> IO (Either SomeException a)
forall a b. a -> IO b -> IO b
keepAlive Connection
conn (IO (Either SomeException a) -> IO (Either SomeException a))
-> IO (Either SomeException a) -> IO (Either SomeException a)
forall a b. (a -> b) -> a -> b
$ IO (Either SomeException a) -> IO (Either SomeException a)
forall a. IO a -> IO a
mask_ (IO (Either SomeException a) -> IO (Either SomeException a))
-> IO (Either SomeException a) -> IO (Either SomeException a)
forall a b. (a -> b) -> a -> b
$ Connection
-> IO (Either SomeException a) -> IO (Either SomeException a)
forall a. Connection -> IO a -> IO a
breakingOnFailure Connection
conn (IO (Either SomeException a) -> IO (Either SomeException a))
-> IO (Either SomeException a) -> IO (Either SomeException a)
forall a b. (a -> b) -> a -> b
$
PacketSink -> IO (Either SomeException a)
writing (\ByteString
p -> Connection -> SmpSession -> PacketSink
sendSmpPacket Connection
conn SmpSession
smp ByteString
p IO () -> (SomeException -> IO ()) -> IO ()
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catch` SomeException -> IO ()
forall b. SomeException -> IO b
sendFailure) IO (Either SomeException a)
-> (SomeException -> IO (Either SomeException a))
-> IO (Either SomeException a)
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catch` (SomeException -> IO (Either SomeException a)
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO (SomeException -> IO (Either SomeException a))
-> (SomeException -> SomeException)
-> SomeException
-> IO (Either SomeException a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SomeException -> SomeException
unwrap)
where
writing :: PacketSink -> IO (Either SomeException a)
writing :: PacketSink -> IO (Either SomeException a)
writing PacketSink
sink = IO a -> IO (Either SomeException a)
forall {b}. IO b -> IO (Either SomeException b)
produced (TdsContext
-> PacketType
-> PacketStatus
-> PacketSink
-> (PacketWriter -> IO a)
-> IO a
forall a.
TdsContext
-> PacketType
-> PacketStatus
-> PacketSink
-> (PacketWriter -> IO a)
-> IO a
runPacketWriterWith TdsContext
tdsCtx PacketType
ptype PacketStatus
status (\ByteString
packet -> IO ()
onPacket IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> PacketSink
sink ByteString
packet) (PacketWriter -> IO a
produce (PacketWriter -> IO a)
-> (PacketWriter -> PacketWriter) -> PacketWriter -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall a. IO a -> IO a) -> PacketWriter -> PacketWriter
withSourceScope IO a -> IO a
forall a. IO a -> IO a
sourceScope))
sourceScope :: IO b -> IO b
sourceScope :: forall a. IO a -> IO a
sourceScope = Connection -> IO b -> IO b
forall a. Connection -> IO a -> IO a
sourceAction Connection
conn
produced :: IO b -> IO (Either SomeException b)
produced IO b
act = IO b -> IO (Either SomeException b)
forall e a. Exception e => IO a -> IO (Either e a)
try IO b
act IO (Either SomeException b)
-> (Either SomeException b -> IO (Either SomeException b))
-> IO (Either SomeException b)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Right b
r -> Either SomeException b -> IO (Either SomeException b)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (b -> Either SomeException b
forall a b. b -> Either a b
Right b
r)
Left SomeException
e
| Just (PacketSendFailed SomeException
inner) <- SomeException -> Maybe PacketSendFailed
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
e -> PacketSendFailed -> IO (Either SomeException b)
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO (SomeException -> PacketSendFailed
PacketSendFailed SomeException
inner)
| Just (SomeAsyncException
_ :: SomeAsyncException) <- SomeException -> Maybe SomeAsyncException
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
e -> SomeException -> IO (Either SomeException b)
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO SomeException
e
| Bool
otherwise -> Either SomeException b -> IO (Either SomeException b)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (SomeException -> Either SomeException b
forall a b. a -> Either a b
Left SomeException
e)
unwrap :: SomeException -> SomeException
unwrap SomeException
e = case SomeException -> Maybe PacketSendFailed
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
e of
Just (PacketSendFailed SomeException
inner) -> SomeException
inner
Maybe PacketSendFailed
Nothing -> SomeException
e
sendFailure :: SomeException -> IO b
sendFailure :: forall b. SomeException -> IO b
sendFailure = PacketSendFailed -> IO b
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO (PacketSendFailed -> IO b)
-> (SomeException -> PacketSendFailed) -> SomeException -> IO b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SomeException -> PacketSendFailed
PacketSendFailed
newtype PacketSendFailed = PacketSendFailed SomeException
instance Show PacketSendFailed where
showsPrec :: Int -> PacketSendFailed -> ShowS
showsPrec Int
p (PacketSendFailed SomeException
a) = Int -> Addr# -> SomeException -> ShowS
forall a. Show a => Int -> Addr# -> a -> ShowS
showCon1 Int
p Addr#
"PacketSendFailed"# SomeException
a
{-# OPAQUE showsPrec #-}
instance Exception PacketSendFailed
newtype SendGather = SendGather (MVar Gathered)
data Gathered
= NotGathering
| Gathering ![[B.ByteString]] !Int
newSendGather :: IO SendGather
newSendGather :: IO SendGather
newSendGather = MVar Gathered -> SendGather
SendGather (MVar Gathered -> SendGather)
-> IO (MVar Gathered) -> IO SendGather
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gathered -> IO (MVar Gathered)
forall a. a -> IO (MVar a)
newMVar Gathered
NotGathering
gatherLimit :: Int
gatherLimit :: Int
gatherLimit = Int
65536
gatheredSend :: SendGather -> Backend -> B.ByteString -> IO ()
gatheredSend :: SendGather -> Backend -> PacketSink
gatheredSend (SendGather MVar Gathered
v) Backend
backend ByteString
bs = MVar Gathered -> (Gathered -> IO Gathered) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ MVar Gathered
v ((Gathered -> IO Gathered) -> IO ())
-> (Gathered -> IO Gathered) -> IO ()
forall a b. (a -> b) -> a -> b
$ \case
Gathered
NotGathering -> Gathered
NotGathering Gathered -> IO () -> IO Gathered
forall a b. a -> IO b -> IO a
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Backend -> PacketSink
backendSend Backend
backend ByteString
bs
Gathering [[ByteString]]
pending Int
size
| Int
size Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0 Bool -> Bool -> Bool
&& Int
size Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
gatherLimit -> do
Backend -> [[ByteString]] -> IO ()
backendSendMany Backend
backend ([[ByteString]] -> [[ByteString]]
forall a. [a] -> [a]
reverse [[ByteString]]
pending)
Gathered -> IO Gathered
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Gathered -> IO Gathered) -> Gathered -> IO Gathered
forall a b. (a -> b) -> a -> b
$! [[ByteString]] -> Int -> Gathered
Gathering [[ByteString
bs]] Int
len
| Bool
otherwise -> Gathered -> IO Gathered
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Gathered -> IO Gathered) -> Gathered -> IO Gathered
forall a b. (a -> b) -> a -> b
$! [[ByteString]] -> Int -> Gathered
Gathering ([ByteString
bs] [ByteString] -> [[ByteString]] -> [[ByteString]]
forall a. a -> [a] -> [a]
: [[ByteString]]
pending) (Int
size Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
len)
where
len :: Int
len = ByteString -> Int
B.length ByteString
bs
startGathering :: SendGather -> IO ()
startGathering :: SendGather -> IO ()
startGathering (SendGather MVar Gathered
v) = MVar Gathered -> (Gathered -> IO Gathered) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ MVar Gathered
v (\Gathered
_ -> Gathered -> IO Gathered
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([[ByteString]] -> Int -> Gathered
Gathering [] Int
0))
endGathering :: Bool -> SendGather -> Backend -> IO ()
endGathering :: Bool -> SendGather -> Backend -> IO ()
endGathering Bool
write (SendGather MVar Gathered
v) Backend
backend = IO () -> IO ()
forall a. IO a -> IO a
mask_ (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
gathered <- MVar Gathered -> IO Gathered
forall a. MVar a -> IO a
takeMVar MVar Gathered
v
let pending = case Gathered
gathered of
Gathering [[ByteString]]
p Int
_ | Bool
write -> [[ByteString]]
p
Gathered
_ -> []
unless (null pending) (backendSendMany backend (reverse pending)) `finally` putMVar v NotGathering
keepAlive :: a -> IO b -> IO b
keepAlive :: forall a b. a -> IO b -> IO b
keepAlive a
x (IO State# RealWorld -> (# State# RealWorld, b #)
act) = (State# RealWorld -> (# State# RealWorld, b #)) -> IO b
forall a. (State# RealWorld -> (# State# RealWorld, a #)) -> IO a
IO (\State# RealWorld
s -> a
-> State# RealWorld
-> (State# RealWorld -> (# State# RealWorld, b #))
-> (# State# RealWorld, b #)
forall a d b. a -> State# d -> (State# d -> b) -> b
keepAlive# a
x State# RealWorld
s State# RealWorld -> (# State# RealWorld, b #)
act)
readPacket :: Connection -> IO (Header, B.ByteString)
readPacket :: Connection -> IO (Header, ByteString)
readPacket Connection
conn = Connection -> Session -> IO (Header, ByteString)
readSessionPacket Connection
conn (Connection -> Session
connPrimary Connection
conn)
readPlainPacket :: Connection -> IO (Header, B.ByteString)
readPlainPacket :: Connection -> IO (Header, ByteString)
readPlainPacket Connection
conn = do
Connection -> Int -> IO ()
fillBuffer Connection
conn Int
headerLength
hdr <- ByteString -> Header
readHeader (ByteString -> Header) -> IO ByteString -> IO Header
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Connection -> Int -> IO ByteString
peekBytes Connection
conn Int
headerLength
let total = Word16 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Header -> Word16
headerPacketLength Header
hdr)
when (total < headerLength) $ throwIO $ ProtocolError "packet length smaller than header"
fillBuffer conn total
packet <- takeBytes conn total
pure (hdr, B.drop headerLength packet)
readSessionPacket :: Connection -> Session -> IO (Header, B.ByteString)
readSessionPacket :: Connection -> Session -> IO (Header, ByteString)
readSessionPacket Connection
conn Session
sess = IORef () -> IO (Header, ByteString) -> IO (Header, ByteString)
forall a b. a -> IO b -> IO b
keepAlive (Connection -> IORef ()
connAlive Connection
conn) (IO (Header, ByteString) -> IO (Header, ByteString))
-> IO (Header, ByteString) -> IO (Header, ByteString)
forall a b. (a -> b) -> a -> b
$ case Session -> Maybe SmpSession
sessSmp Session
sess of
Maybe SmpSession
Nothing -> Connection -> IO (Header, ByteString)
readPlainPacket Connection
conn
Just SmpSession
smp -> do
let link :: SmpLink
link = SmpSession -> SmpLink
smpLink SmpSession
smp
packet <- STM ByteString -> IO ByteString
forall a. STM a -> IO a
atomically (STM ByteString -> IO ByteString)
-> STM ByteString -> IO ByteString
forall a b. (a -> b) -> a -> b
$ do
ended <- TVar (Maybe SomeException) -> STM (Maybe SomeException)
forall a. TVar a -> STM a
readTVar (Connection -> TVar (Maybe SomeException)
connEnded Connection
conn)
case ended of
Just SomeException
e | SomeException -> Bool
closedByClient SomeException
e -> SomeException -> STM ByteString
forall e a. Exception e => e -> STM a
throwSTM SomeException
e
Maybe SomeException
_ -> TQueue ByteString -> STM ByteString
forall a. TQueue a -> STM a
readTQueue (SmpLink -> TQueue ByteString
linkIncoming SmpLink
link) STM ByteString -> STM ByteString -> STM ByteString
forall a. STM a -> STM a -> STM a
`orElse` STM ByteString
-> (SomeException -> STM ByteString)
-> Maybe SomeException
-> STM ByteString
forall b a. b -> (a -> b) -> Maybe a -> b
maybe STM ByteString
forall a. STM a
retry SomeException -> STM ByteString
forall e a. Exception e => e -> STM a
throwSTM Maybe SomeException
ended
accepted <- atomically $ stateTVar (linkRecvHighWater link) (\Word32
w -> (Word32
w Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ Word32
1, Word32
w Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ Word32
1))
advertised <- readIORef (smpAdvertised smp)
let window = Word32 -> (Mars -> Word32) -> Maybe Mars -> Word32
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Word32
0 Mars -> Word32
marsWindow (Connection -> Maybe Mars
connMars Connection
conn)
when (accepted - advertised >= max 1 (window `div` 16)) $
uninterruptibleMask_ (sendAck conn smp)
pure (readHeader packet, B.drop headerLength packet)
sendAck :: Connection -> SmpSession -> IO ()
sendAck :: Connection -> SmpSession -> IO ()
sendAck Connection
conn SmpSession
smp = Connection -> IO () -> IO ()
forall a b. a -> IO b -> IO b
keepAlive Connection
conn (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ IO () -> IO ()
forall a. IO a -> IO a
mask_ (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
r <- IO () -> IO (Either SomeException ())
forall e a. Exception e => IO a -> IO (Either e a)
try (Connection -> IO [[ByteString]] -> IO ()
writeSmp Connection
conn (SmpFlag -> SmpSession -> IO [[ByteString]]
controlPacket SmpFlag
SmpAck SmpSession
smp))
case r of
Right () -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
Left (SomeException
e :: SomeException) -> do
ended <- Maybe SomeException -> Bool
forall a. Maybe a -> Bool
isJust (Maybe SomeException -> Bool)
-> IO (Maybe SomeException) -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TVar (Maybe SomeException) -> IO (Maybe SomeException)
forall a. TVar a -> IO a
readTVarIO (Connection -> TVar (Maybe SomeException)
connEnded Connection
conn)
unless ended $ breakingOnFailure conn (throwIO e)
runBody :: Put -> LB.ByteString
runBody :: Put -> ByteString
runBody = AllocationStrategy -> ByteString -> Builder -> ByteString
BB.toLazyByteStringWith (Int -> Int -> AllocationStrategy
BB.untrimmedStrategy Int
512 Int
32752) ByteString
LB.empty (Builder -> ByteString) -> (Put -> Builder) -> Put -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Put -> Builder
forall a. PutM a -> Builder
Put.execPut
sendMessage :: Connection -> PacketType -> Put -> IO ()
sendMessage :: Connection -> PacketType -> Put -> IO ()
sendMessage Connection
conn PacketType
ptype Put
body = do
ctx <- IORef TdsContext -> IO TdsContext
forall a. IORef a -> IO a
readIORef (Connection -> IORef TdsContext
connContext Connection
conn)
let bytes = Put -> ByteString
runBody Put
body
_ <- evaluate (LB.length bytes)
sendFramed conn (connPrimary conn) ctx ptype (PacketStatus 0) bytes
readWholeMessage :: Connection -> IO (PacketType, B.ByteString)
readWholeMessage :: Connection -> IO (PacketType, ByteString)
readWholeMessage Connection
conn = Connection -> Int -> IO (PacketType, ByteString)
readWholeMessageUpTo Connection
conn Int
forall a. Bounded a => a
maxBound
readWholeMessageUpTo :: Connection -> Int -> IO (PacketType, B.ByteString)
readWholeMessageUpTo :: Connection -> Int -> IO (PacketType, ByteString)
readWholeMessageUpTo Connection
conn Int
limit = Connection
-> IO (PacketType, ByteString) -> IO (PacketType, ByteString)
forall a. Connection -> IO a -> IO a
breakOnFailure Connection
conn (IO (PacketType, ByteString) -> IO (PacketType, ByteString))
-> IO (PacketType, ByteString) -> IO (PacketType, ByteString)
forall a b. (a -> b) -> a -> b
$ Int -> [ByteString] -> IO (PacketType, ByteString)
go Int
0 []
where
go :: Int -> [ByteString] -> IO (PacketType, ByteString)
go !Int
size [ByteString]
acc = do
(hdr, body) <- Connection -> IO (Header, ByteString)
readPacket Connection
conn
let acc' = ByteString
body ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
: [ByteString]
acc
size' = Int
size Int -> Int -> Int
forall a. Num a => a -> a -> a
+ ByteString -> Int
B.length ByteString
body
when (size' > limit) $ throwIO $ ProtocolError $
"the server's message is longer than " ++ show limit ++ " bytes, the most expected"
if headerStatus hdr `hasStatus` statusEndOfMessage
then pure (headerType hdr, B.concat (reverse acc'))
else go size' acc'
hasStatus :: PacketStatus -> PacketStatus -> Bool
hasStatus :: PacketStatus -> PacketStatus -> Bool
hasStatus PacketStatus
a PacketStatus
b = PacketStatus
a PacketStatus -> PacketStatus -> PacketStatus
forall a. Bits a => a -> a -> a
.&. PacketStatus
b PacketStatus -> PacketStatus -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8 -> PacketStatus
PacketStatus Word8
0
startRequest :: Connection -> PacketType -> (TdsContext -> LB.ByteString) -> IO ActiveResponse
startRequest :: Connection
-> PacketType -> (TdsContext -> ByteString) -> IO ActiveResponse
startRequest Connection
conn PacketType
ptype TdsContext -> ByteString
body = Connection
-> Maybe Text
-> PacketType
-> (TdsContext -> PacketWriter -> IO ())
-> IO ActiveResponse
startRequestFor Connection
conn Maybe Text
forall a. Maybe a
Nothing PacketType
ptype ((TdsContext -> ByteString) -> TdsContext -> PacketWriter -> IO ()
bytesBody TdsContext -> ByteString
body)
bytesBody :: (TdsContext -> LB.ByteString) -> TdsContext -> PacketWriter -> IO ()
bytesBody :: (TdsContext -> ByteString) -> TdsContext -> PacketWriter -> IO ()
bytesBody TdsContext -> ByteString
body TdsContext
ctx PacketWriter
writer = do
let bytes :: ByteString
bytes = TdsContext -> ByteString
body TdsContext
ctx
_ <- Int64 -> IO Int64
forall a. a -> IO a
evaluate (ByteString -> Int64
LB.length ByteString
bytes)
writeBuilder writer (BB.lazyByteString bytes)
startRequestFor :: Connection -> Maybe Text -> PacketType -> (TdsContext -> PacketWriter -> IO ()) -> IO ActiveResponse
startRequestFor :: Connection
-> Maybe Text
-> PacketType
-> (TdsContext -> PacketWriter -> IO ())
-> IO ActiveResponse
startRequestFor Connection
conn Maybe Text
stmt PacketType
ptype TdsContext -> PacketWriter -> IO ()
mkBody = Connection -> IO ActiveResponse -> IO ActiveResponse
forall a. Connection -> IO a -> IO a
withConnectionLock Connection
conn (IO ActiveResponse -> IO ActiveResponse)
-> IO ActiveResponse -> IO ActiveResponse
forall a b. (a -> b) -> a -> b
$ do
IORef Bool -> IO Bool
forall a. IORef a -> IO a
readIORef (Connection -> IORef Bool
connInSource Connection
conn) IO Bool -> (Bool -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Bool
active -> Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
active (ReentrantSource -> IO ()
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO ReentrantSource
ReentrantSource)
Connection -> IO ()
checkNotBroken Connection
conn
Connection -> IO ()
prepareForRequest Connection
conn
let resettable :: Bool
resettable = PacketType
ptype PacketType -> [PacketType] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [PacketType
PTSqlBatch, PacketType
PTRpc, PacketType
PTTransactionManager]
pending <- IORef Bool -> IO Bool
forall a. IORef a -> IO a
readIORef (Connection -> IORef Bool
connResetPending Connection
conn)
when (resettable && pending) $ do
forM_ (connMars conn) $ \Mars
_ -> Connection -> IO ()
finishResponse Connection
conn
unless (null (connSessionSetup conn)) $ resetWithSessionSetup conn
sendRequest conn stmt ptype resettable mkBody
prepareForRequest :: Connection -> IO ()
prepareForRequest :: Connection -> IO ()
prepareForRequest Connection
conn = case Connection -> Maybe Mars
connMars Connection
conn of
Maybe Mars
Nothing -> Connection -> Session -> IO ()
finishSession Connection
conn (Connection -> Session
connPrimary Connection
conn)
Just Mars
mars -> do
Connection -> IO ()
drainCancelled Connection
conn
IORef (Maybe Session) -> IO (Maybe Session)
forall a. IORef a -> IO a
readIORef (Mars -> IORef (Maybe Session)
marsReserved Mars
mars) IO (Maybe Session) -> (Maybe Session -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Session -> IO ()) -> Maybe Session -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (Connection -> Session -> IO ()
finishSession Connection
conn)
Connection -> Mars -> IO ()
awaitReset Connection
conn Mars
mars
Connection -> Mars -> IO ()
closeIdleSessions Connection
conn Mars
mars
drainCancelled :: Connection -> IO ()
drainCancelled :: Connection -> IO ()
drainCancelled Connection
conn = do
sessions <- Connection -> IO [Session]
allSessions Connection
conn
forM_ sessions $ \Session
sess -> IORef (Maybe ActiveResponse) -> IO (Maybe ActiveResponse)
forall a. IORef a -> IO a
readIORef (Session -> IORef (Maybe ActiveResponse)
sessResponse Session
sess) IO (Maybe ActiveResponse)
-> (Maybe ActiveResponse -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (ActiveResponse -> IO ()) -> Maybe ActiveResponse -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (\ActiveResponse
ar -> do
canceled <- (Cancellation -> Cancellation -> Bool
forall a. Eq a => a -> a -> Bool
/= Cancellation
Running) (Cancellation -> Bool) -> IO Cancellation -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IORef Cancellation -> IO Cancellation
forall a. IORef a -> IO a
readIORef (ActiveResponse -> IORef Cancellation
arCancellation ActiveResponse
ar)
when canceled $ finishSession conn sess)
readingToEnd :: Connection -> ActiveResponse -> IO a -> IO a
readingToEnd :: forall a. Connection -> ActiveResponse -> IO a -> IO a
readingToEnd Connection
conn ActiveResponse
ar IO a
act = IO a
act IO a -> (SomeException -> IO a) -> IO a
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catch` \(SomeException
e :: SomeException) -> do
case SomeException -> Maybe SomeAsyncException
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
e of
Just (SomeAsyncException
_ :: SomeAsyncException) -> Connection -> ActiveResponse -> IO ()
abandonResponse Connection
conn ActiveResponse
ar
Maybe SomeAsyncException
Nothing -> Connection -> ActiveResponse -> IO ()
cancelActiveResponse Connection
conn ActiveResponse
ar IO () -> (SomeException -> IO ()) -> IO ()
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catch` \(SomeException
c :: SomeException) -> case SomeException -> Maybe SomeAsyncException
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
c of
Just (SomeAsyncException
_ :: SomeAsyncException) -> SomeException -> IO ()
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO SomeException
c
Maybe SomeAsyncException
Nothing -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
SomeException -> IO a
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO SomeException
e
abandonResponse :: Connection -> ActiveResponse -> IO ()
abandonResponse :: Connection -> ActiveResponse -> IO ()
abandonResponse Connection
conn ActiveResponse
ar = do
ActiveResponse -> IO ()
markAbandoned ActiveResponse
ar
Mutex -> IO () -> IO ()
forall a. Mutex -> IO a -> IO a
withMutex (Connection -> Mutex
connMutex Connection
conn) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
current <- IORef (Maybe ActiveResponse) -> IO (Maybe ActiveResponse)
forall a. IORef a -> IO a
readIORef (Session -> IORef (Maybe ActiveResponse)
sessResponse Session
sess)
case current of
Just ActiveResponse
ar' | ActiveResponse -> IORef ReadState
arState ActiveResponse
ar' IORef ReadState -> IORef ReadState -> Bool
forall a. Eq a => a -> a -> Bool
== ActiveResponse -> IORef ReadState
arState ActiveResponse
ar -> do
ActiveResponse -> IO ()
abandonHandle ActiveResponse
ar
broken <- Maybe UnusableReason -> Bool
forall a. Maybe a -> Bool
isJust (Maybe UnusableReason -> Bool)
-> IO (Maybe UnusableReason) -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IORef (Maybe UnusableReason) -> IO (Maybe UnusableReason)
forall a. IORef a -> IO a
readIORef (Connection -> IORef (Maybe UnusableReason)
connBroken Connection
conn)
unless broken $ void (cancelStatement conn ar)
Maybe ActiveResponse
_ -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
where
sess :: Session
sess = ActiveResponse -> Session
arSession ActiveResponse
ar
abandonHandle :: ActiveResponse -> IO ()
abandonHandle :: ActiveResponse -> IO ()
abandonHandle ActiveResponse
ar = do
gen <- IORef Int -> (Int -> (Int, Int)) -> IO Int
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' (Session -> IORef Int
sessGeneration Session
sess) (\Int
g -> (Int
g Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1, Int
g Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1))
writeIORef (sessResponse sess) (Just ar { arGeneration = gen })
where
sess :: Session
sess = ActiveResponse -> Session
arSession ActiveResponse
ar
cancelStatement :: Connection -> ActiveResponse -> IO Bool
cancelStatement :: Connection -> ActiveResponse -> IO Bool
cancelStatement Connection
conn ActiveResponse
ar = do
arrived <- ActiveResponse -> IO Bool
fullyArrived ActiveResponse
ar
attn <- attentionWasSent <$> readIORef (arCancellation ar)
if arrived || attn
then pure False
else do
ctx <- readIORef (connContext conn)
sendFramed conn (arSession ar) ctx PTAttention (PacketStatus 0) LB.empty
`catch` \(SomeException
c :: SomeException) -> case SomeException -> Maybe SomeAsyncException
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
c of
Just (SomeAsyncException
_ :: SomeAsyncException) -> SomeException -> IO ()
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO SomeException
c
Maybe SomeAsyncException
Nothing -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
writeIORef (arCancellation ar) AttentionSent
pure True
allSessions :: Connection -> IO [Session]
allSessions :: Connection -> IO [Session]
allSessions Connection
conn = case Connection -> Maybe Mars
connMars Connection
conn of
Maybe Mars
Nothing -> [Session] -> IO [Session]
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure [Connection -> Session
connPrimary Connection
conn]
Just Mars
mars -> IntMap Session -> [Session]
forall a. IntMap a -> [a]
IntMap.elems (IntMap Session -> [Session])
-> IO (IntMap Session) -> IO [Session]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IORef (IntMap Session) -> IO (IntMap Session)
forall a. IORef a -> IO a
readIORef (Mars -> IORef (IntMap Session)
marsOpen Mars
mars)
takeSession :: Connection -> IO Session
takeSession :: Connection -> IO Session
takeSession Connection
conn = case Connection -> Maybe Mars
connMars Connection
conn of
Maybe Mars
Nothing -> Session -> IO Session
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Connection -> Session
connPrimary Connection
conn)
Just Mars
mars -> IORef (Maybe Session) -> IO (Maybe Session)
forall a. IORef a -> IO a
readIORef (Mars -> IORef (Maybe Session)
marsReserved Mars
mars) IO (Maybe Session) -> (Maybe Session -> IO Session) -> IO Session
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Just Session
sess -> Session -> IO Session
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Session
sess
Maybe Session
Nothing -> Connection -> Mars -> IO [Session]
idleSessions Connection
conn Mars
mars IO [Session] -> ([Session] -> IO Session) -> IO Session
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Session
sess : [Session]
_ -> Session -> IO Session
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Session
sess
[] -> Connection -> Mars -> IO Session
openSession Connection
conn Mars
mars
idleSessions :: Connection -> Mars -> IO [Session]
idleSessions :: Connection -> Mars -> IO [Session]
idleSessions Connection
_ Mars
mars = do
reserved <- (Session -> Int) -> Maybe Session -> Maybe Int
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Session -> Int
sessionId (Maybe Session -> Maybe Int)
-> IO (Maybe Session) -> IO (Maybe Int)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IORef (Maybe Session) -> IO (Maybe Session)
forall a. IORef a -> IO a
readIORef (Mars -> IORef (Maybe Session)
marsReserved Mars
mars)
open <- IntMap.elems <$> readIORef (marsOpen mars)
let idle Session
sess
| Int -> Maybe Int
forall a. a -> Maybe a
Just (Session -> Int
sessionId Session
sess) Maybe Int -> Maybe Int -> Bool
forall a. Eq a => a -> a -> Bool
== Maybe Int
reserved = Bool -> IO Bool
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
False
| Bool
otherwise = Maybe ActiveResponse -> Bool
forall a. Maybe a -> Bool
isNothing (Maybe ActiveResponse -> Bool)
-> IO (Maybe ActiveResponse) -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IORef (Maybe ActiveResponse) -> IO (Maybe ActiveResponse)
forall a. IORef a -> IO a
readIORef (Session -> IORef (Maybe ActiveResponse)
sessResponse Session
sess)
filterIO idle open
where
filterIO :: (a -> f Bool) -> t a -> f [a]
filterIO a -> f Bool
f = (t [a] -> [a]) -> f (t [a]) -> f [a]
forall a b. (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap t [a] -> [a]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat (f (t [a]) -> f [a]) -> (t a -> f (t [a])) -> t a -> f [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> f [a]) -> t a -> f (t [a])
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> t a -> m (t b)
mapM (\a
x -> a -> f Bool
f a
x f Bool -> (Bool -> f [a]) -> f [a]
forall a b. f a -> (a -> f b) -> f b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Bool
keep -> [a] -> f [a]
forall a. a -> f a
forall (f :: * -> *) a. Applicative f => a -> f a
pure [a
x | Bool
keep])
sessionId :: Session -> Int
sessionId :: Session -> Int
sessionId = Int -> (SmpSession -> Int) -> Maybe SmpSession -> Int
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (-Int
1) (Word16 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word16 -> Int) -> (SmpSession -> Word16) -> SmpSession -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SmpSession -> Word16
smpSid) (Maybe SmpSession -> Int)
-> (Session -> Maybe SmpSession) -> Session -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Session -> Maybe SmpSession
sessSmp
openSession :: Connection -> Mars -> IO Session
openSession :: Connection -> Mars -> IO Session
openSession Connection
conn Mars
mars = IO Session -> IO Session
forall a. IO a -> IO a
mask_ (IO Session -> IO Session) -> IO Session -> IO Session
forall a b. (a -> b) -> a -> b
$ do
links <- TVar (IntMap SmpLink) -> IO (IntMap SmpLink)
forall a. TVar a -> IO a
readTVarIO (Mars -> TVar (IntMap SmpLink)
marsRegistry Mars
mars)
let sid = (Int -> Bool) -> (Int -> Int) -> Int -> Int
forall a. (a -> Bool) -> (a -> a) -> a -> a
until (\Int
i -> Bool -> Bool
not (Int -> IntMap SmpLink -> Bool
forall a. Int -> IntMap a -> Bool
IntMap.member Int
i IntMap SmpLink
links)) (Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int
0
when (sid > 0xFFFF) $ throwIO $ EncodeError
"the connection has 65536 responses open, the most SMP has sessions for"
link <- SmpLink <$> newTQueueIO <*> newTVarIO smpInitialWindow <*> newTVarIO 0
<*> newTVarIO (marsWindow mars) <*> newTVarIO 0 <*> newTVarIO False
smp <- SmpSession (fromIntegral sid) link <$> newIORef 0 <*> newIORef (marsWindow mars)
sess <- newSession (Just smp)
atomically $ modifyTVar' (marsRegistry mars) (IntMap.insert sid link)
modifyIORef' (marsOpen mars) (IntMap.insert sid sess)
sendSmpControl conn smp SmpSyn
pure sess
maxIdleSessions :: Int
maxIdleSessions :: Int
maxIdleSessions = Int
10
closeIdleSessions :: Connection -> Mars -> IO ()
closeIdleSessions :: Connection -> Mars -> IO ()
closeIdleSessions Connection
conn Mars
mars = do
idle <- Connection -> Mars -> IO [Session]
idleSessions Connection
conn Mars
mars
forM_ (take (length idle - maxIdleSessions) (reverse idle)) $ \Session
sess ->
Maybe SmpSession -> (SmpSession -> IO ()) -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ (Session -> Maybe SmpSession
sessSmp Session
sess) ((SmpSession -> IO ()) -> IO ()) -> (SmpSession -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \SmpSession
smp -> IO () -> IO ()
forall a. IO a -> IO a
mask_ (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
STM () -> IO ()
forall a. STM a -> IO a
atomically (STM () -> IO ()) -> STM () -> IO ()
forall a b. (a -> b) -> a -> b
$ TVar Bool -> Bool -> STM ()
forall a. TVar a -> a -> STM ()
writeTVar (SmpLink -> TVar Bool
linkClosing (SmpSession -> SmpLink
smpLink SmpSession
smp)) Bool
True
IORef (IntMap Session)
-> (IntMap Session -> IntMap Session) -> IO ()
forall a. IORef a -> (a -> a) -> IO ()
modifyIORef' (Mars -> IORef (IntMap Session)
marsOpen Mars
mars) (Int -> IntMap Session -> IntMap Session
forall a. Int -> IntMap a -> IntMap a
IntMap.delete (Session -> Int
sessionId Session
sess))
Connection -> SmpSession -> SmpFlag -> IO ()
sendSmpControl Connection
conn SmpSession
smp SmpFlag
SmpFin
enableMars :: Connection -> Int -> IO Connection
enableMars :: Connection -> Int -> IO Connection
enableMars Connection
conn Int
window = do
leftover <- IORef [ByteString] -> IO [ByteString]
forall a. IORef a -> IO a
readIORef (Connection -> IORef [ByteString]
primaryBuffer Connection
conn)
unless (null leftover) $ throwIO $ ProtocolError "unexpected data after the login response"
marsRegistry <- newTVarIO IntMap.empty
marsOpen <- newIORef IntMap.empty
marsReserved <- newIORef Nothing
marsResetInFlight <- newIORef Nothing
let mars = Mars { marsWindow :: Word32
marsWindow = Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
4 (Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
0x7FFFFFFF Int
window)), TVar (IntMap SmpLink)
IORef (Maybe ActiveResponse)
IORef (Maybe Session)
IORef (IntMap Session)
marsRegistry :: TVar (IntMap SmpLink)
marsOpen :: IORef (IntMap Session)
marsReserved :: IORef (Maybe Session)
marsResetInFlight :: IORef (Maybe ActiveResponse)
marsRegistry :: TVar (IntMap SmpLink)
marsOpen :: IORef (IntMap Session)
marsReserved :: IORef (Maybe Session)
marsResetInFlight :: IORef (Maybe ActiveResponse)
.. }
conn' = Connection
conn { connMars = Just mars }
primary <- openSession conn' mars
pure conn' { connPrimary = primary }
withReservedSession :: Connection -> IO a -> IO a
withReservedSession :: forall a. Connection -> IO a -> IO a
withReservedSession Connection
conn IO a
act = Connection -> IO a -> IO a
forall a. Connection -> IO a -> IO a
withConnectionLock Connection
conn (IO a -> IO a) -> IO a -> IO a
forall a b. (a -> b) -> a -> b
$ case Connection -> Maybe Mars
connMars Connection
conn of
Maybe Mars
Nothing -> IO a
act
Just Mars
mars -> IORef (Maybe Session) -> IO (Maybe Session)
forall a. IORef a -> IO a
readIORef (Mars -> IORef (Maybe Session)
marsReserved Mars
mars) IO (Maybe Session) -> (Maybe Session -> IO a) -> IO a
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Just Session
_ -> IO a
act
Maybe Session
Nothing -> IO () -> IO () -> IO a -> IO a
forall a b c. IO a -> IO b -> IO c -> IO c
bracket_
(Connection -> IO ()
checkNotBroken Connection
conn IO () -> IO Session -> IO Session
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Connection -> IO Session
takeSession Connection
conn IO Session -> (Session -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IORef (Maybe Session) -> Maybe Session -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (Mars -> IORef (Maybe Session)
marsReserved Mars
mars) (Maybe Session -> IO ())
-> (Session -> Maybe Session) -> Session -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Session -> Maybe Session
forall a. a -> Maybe a
Just)
(IORef (Maybe Session) -> Maybe Session -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (Mars -> IORef (Maybe Session)
marsReserved Mars
mars) Maybe Session
forall a. Maybe a
Nothing)
IO a
act
sendRequest :: Connection -> Maybe Text -> PacketType -> Bool -> (TdsContext -> PacketWriter -> IO ()) -> IO ActiveResponse
sendRequest :: Connection
-> Maybe Text
-> PacketType
-> Bool
-> (TdsContext -> PacketWriter -> IO ())
-> IO ActiveResponse
sendRequest Connection
conn Maybe Text
stmt PacketType
ptype Bool
resettable TdsContext -> PacketWriter -> IO ()
writeBody = IO ActiveResponse -> IO ActiveResponse
forall a. IO a -> IO a
mask_ (IO ActiveResponse -> IO ActiveResponse)
-> IO ActiveResponse -> IO ActiveResponse
forall a b. (a -> b) -> a -> b
$ do
ctx <- IORef TdsContext -> IO TdsContext
forall a. IORef a -> IO a
readIORef (Connection -> IORef TdsContext
connContext Connection
conn)
sess <- takeSession conn
resetting <- if resettable then atomicModifyIORef' (connResetPending conn) (False,) else pure False
let status = if Bool
resetting then PacketStatus
statusResetConnection else Word8 -> PacketStatus
PacketStatus Word8
0
ar0 <- newResponse sess stmt resetting
sent <- newIORef False
result <- sendPacketsTracked conn sess ctx ptype status (writeIORef sent True) (writeBody ctx)
case result of
Right () -> Connection -> ActiveResponse -> IO ActiveResponse
registerResponse Connection
conn ActiveResponse
ar0
Left SomeException
err -> do
anyPacket <- IORef Bool -> IO Bool
forall a. IORef a -> IO a
readIORef IORef Bool
sent
if not anyPacket && ptype /= PTBulkLoad then do
when resetting (writeIORef (connResetPending conn) True)
throwIO err
else do
ar <- registerResponse conn ar0
sendFramed conn sess ctx PTAttention (PacketStatus 0) LB.empty
writeIORef (arCancellation ar) AttentionSent
finishSession conn sess
throwIO err
newResponse :: Session -> Maybe Text -> Bool -> IO ActiveResponse
newResponse :: Session -> Maybe Text -> Bool -> IO ActiveResponse
newResponse Session
sess Maybe Text
stmt Bool
resetting = do
arEomBase <- IO Int -> (SmpSession -> IO Int) -> Maybe SmpSession -> IO Int
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Int -> IO Int
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
0) (TVar Int -> IO Int
forall a. TVar a -> IO a
readTVarIO (TVar Int -> IO Int)
-> (SmpSession -> TVar Int) -> SmpSession -> IO Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SmpLink -> TVar Int
linkEoms (SmpLink -> TVar Int)
-> (SmpSession -> SmpLink) -> SmpSession -> TVar Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SmpSession -> SmpLink
smpLink) (Session -> Maybe SmpSession
sessSmp Session
sess)
arSawResetAck <- newIORef False
arCancellation <- newIORef Running
arInConsumer <- newIORef False
arReplay <- newIORef []
arState <- newIORef (ReadState False (AtToken B.empty))
arResultSet <- newIORef Nothing
arSawFinalDone <- newIORef False
pure ActiveResponse
{ arGeneration = 0, arSession = sess, arStatement = stmt, arCarriedReset = resetting, .. }
registerResponse :: Connection -> ActiveResponse -> IO ActiveResponse
registerResponse :: Connection -> ActiveResponse -> IO ActiveResponse
registerResponse Connection
conn ActiveResponse
ar0 = do
let sess :: Session
sess = ActiveResponse -> Session
arSession ActiveResponse
ar0
gen <- IORef Int -> (Int -> (Int, Int)) -> IO Int
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' (Session -> IORef Int
sessGeneration Session
sess) (\Int
g -> (Int
g Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1, Int
g Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1))
let ar = ActiveResponse
ar0 { arGeneration = gen }
writeIORef (sessResponse sess) (Just ar)
when (arCarriedReset ar) $ forM_ (connMars conn) $ \Mars
mars ->
IORef (Maybe ActiveResponse) -> Maybe ActiveResponse -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (Mars -> IORef (Maybe ActiveResponse)
marsResetInFlight Mars
mars) (ActiveResponse -> Maybe ActiveResponse
forall a. a -> Maybe a
Just ActiveResponse
ar)
pure ar
awaitReset :: Connection -> Mars -> IO ()
awaitReset :: Connection -> Mars -> IO ()
awaitReset Connection
conn Mars
mars = IORef (Maybe ActiveResponse) -> IO (Maybe ActiveResponse)
forall a. IORef a -> IO a
readIORef (Mars -> IORef (Maybe ActiveResponse)
marsResetInFlight Mars
mars) IO (Maybe ActiveResponse)
-> (Maybe ActiveResponse -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Maybe ActiveResponse
Nothing -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
Just ActiveResponse
ar -> do
current <- IORef (Maybe ActiveResponse) -> IO (Maybe ActiveResponse)
forall a. IORef a -> IO a
readIORef (Session -> IORef (Maybe ActiveResponse)
sessResponse (ActiveResponse -> Session
arSession ActiveResponse
ar))
case current of
Just ActiveResponse
ar' | ActiveResponse -> Int
arGeneration ActiveResponse
ar' Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== ActiveResponse -> Int
arGeneration ActiveResponse
ar -> do
step <- IO (ResponseStep (ZonkAny 7)) -> IO (ResponseStep (ZonkAny 7))
forall a. IO a -> IO a
mask_ (IO (ResponseStep (ZonkAny 7)) -> IO (ResponseStep (ZonkAny 7)))
-> IO (ResponseStep (ZonkAny 7)) -> IO (ResponseStep (ZonkAny 7))
forall a b. (a -> b) -> a -> b
$ do
step <- Connection
-> ActiveResponse
-> Bool
-> RowRead (ZonkAny 7)
-> IO (ResponseStep (ZonkAny 7))
forall r.
Connection
-> ActiveResponse -> Bool -> RowRead r -> IO (ResponseStep r)
stepCore Connection
conn ActiveResponse
ar Bool
False RowRead (ZonkAny 7)
forall a. RowRead a
StopAtRow
modifyIORef' (arReplay ar) (++ replayed step)
settleReset conn ar step
pure step
runCallbacks conn step
awaitReset conn mars
Maybe ActiveResponse
_ -> IORef (Maybe ActiveResponse) -> Maybe ActiveResponse -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (Mars -> IORef (Maybe ActiveResponse)
marsResetInFlight Mars
mars) Maybe ActiveResponse
forall a. Maybe a
Nothing
where
replayed :: ResponseStep r -> [Token]
replayed = \case
StepToken Token
tok -> [Token
tok]
StepRows RowBatch r
_ -> []
ResponseStep r
StepEnd -> []
settleReset :: Connection -> ActiveResponse -> ResponseStep r -> IO ()
settleReset :: forall r. Connection -> ActiveResponse -> ResponseStep r -> IO ()
settleReset Connection
conn ActiveResponse
ar ResponseStep r
step = Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (ActiveResponse -> Bool
arCarriedReset ActiveResponse
ar) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ case ResponseStep r
step of
StepToken (TEnvChange EnvChange
_) -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
ResponseStep r
_ -> Maybe Mars -> (Mars -> IO ()) -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ (Connection -> Maybe Mars
connMars Connection
conn) ((Mars -> IO ()) -> IO ()) -> (Mars -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Mars
mars -> IORef (Maybe ActiveResponse) -> IO (Maybe ActiveResponse)
forall a. IORef a -> IO a
readIORef (Mars -> IORef (Maybe ActiveResponse)
marsResetInFlight Mars
mars) IO (Maybe ActiveResponse)
-> (Maybe ActiveResponse -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Just ActiveResponse
inFlight | ActiveResponse -> IORef ReadState
arState ActiveResponse
inFlight IORef ReadState -> IORef ReadState -> Bool
forall a. Eq a => a -> a -> Bool
== ActiveResponse -> IORef ReadState
arState ActiveResponse
ar -> IORef (Maybe ActiveResponse) -> Maybe ActiveResponse -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (Mars -> IORef (Maybe ActiveResponse)
marsResetInFlight Mars
mars) Maybe ActiveResponse
forall a. Maybe a
Nothing
Maybe ActiveResponse
_ -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
startStreamingRequest :: Connection -> Maybe Text -> PacketType -> (PacketWriter -> IO ()) -> IO ActiveResponse
startStreamingRequest :: Connection
-> Maybe Text
-> PacketType
-> (PacketWriter -> IO ())
-> IO ActiveResponse
startStreamingRequest Connection
conn Maybe Text
stmt PacketType
ptype PacketWriter -> IO ()
produce = Connection
-> Maybe Text
-> PacketType
-> (TdsContext -> PacketWriter -> IO ())
-> IO ActiveResponse
startRequestFor Connection
conn Maybe Text
stmt PacketType
ptype (\TdsContext
_ -> PacketWriter -> IO ()
produce)
resetWithSessionSetup :: Connection -> IO ()
resetWithSessionSetup :: Connection -> IO ()
resetWithSessionSetup Connection
conn = ((forall a. IO a -> IO a) -> IO ()) -> IO ()
forall b. ((forall a. IO a -> IO a) -> IO b) -> IO b
mask (((forall a. IO a -> IO a) -> IO ()) -> IO ())
-> ((forall a. IO a -> IO a) -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \forall a. IO a -> IO a
restore -> do
let sql :: Text
sql = Text -> [Text] -> Text
T.intercalate Text
"\n" (Connection -> [Text]
connSessionSetup Connection
conn)
ar <- Connection
-> Maybe Text
-> PacketType
-> Bool
-> (TdsContext -> PacketWriter -> IO ())
-> IO ActiveResponse
sendRequest Connection
conn (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
sql) PacketType
PTSqlBatch Bool
True (\TdsContext
ctx PacketWriter
writer -> do
([Char] -> IO (ZonkAny 8)) -> Maybe [Char] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (EncodeError -> IO (ZonkAny 8)
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO (EncodeError -> IO (ZonkAny 8))
-> ([Char] -> EncodeError) -> [Char] -> IO (ZonkAny 8)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> EncodeError
EncodeError) (TdsContext -> Text -> Maybe [Char]
sqlBatchProblem TdsContext
ctx Text
sql)
PacketWriter -> Builder -> IO ()
writeBuilder PacketWriter
writer (TdsContext -> Text -> Builder
sqlBatchBuilder TdsContext
ctx Text
sql))
let go Maybe ServerMessage
err Maybe Done
done = Connection -> ActiveResponse -> IO (Maybe Token)
nextToken Connection
conn ActiveResponse
ar IO (Maybe Token)
-> (Maybe Token -> IO (Maybe ServerMessage, Maybe Done))
-> IO (Maybe ServerMessage, Maybe Done)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Maybe Token
Nothing -> (Maybe ServerMessage, Maybe Done)
-> IO (Maybe ServerMessage, Maybe Done)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe ServerMessage
err, Maybe Done
done)
Just (TError ServerMessage
msg) -> Maybe ServerMessage
-> Maybe Done -> IO (Maybe ServerMessage, Maybe Done)
go (Maybe ServerMessage
err Maybe ServerMessage -> Maybe ServerMessage -> Maybe ServerMessage
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ServerMessage -> Maybe ServerMessage
forall a. a -> Maybe a
Just ServerMessage
msg) Maybe Done
done
Just Token
tok -> Maybe ServerMessage
-> Maybe Done -> IO (Maybe ServerMessage, Maybe Done)
go Maybe ServerMessage
err (Maybe Done
done Maybe Done -> Maybe Done -> Maybe Done
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Token -> Maybe Done
failedDoneOf Token
tok)
failed <- restore (go Nothing Nothing) `catch` \(SomeException
e :: SomeException) -> do
Connection -> UnusableReason -> IO ()
markBroken Connection
conn ((SomeException -> UnusableReason)
-> SomeException -> UnusableReason
reasonFor SomeException -> UnusableReason
ResetFailed SomeException
e)
SomeException -> IO (Maybe ServerMessage, Maybe Done)
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO SomeException
e
let failure = case (Maybe ServerMessage, Maybe Done)
failed of
(Just ServerMessage
msg, Maybe Done
_) -> SomeException -> Maybe SomeException
forall a. a -> Maybe a
Just (SqlServerError -> SomeException
forall e. Exception e => e -> SomeException
toException (ServerMessage -> Maybe Text -> SqlServerError
SqlServerError ServerMessage
msg (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
sql)))
(Maybe ServerMessage
Nothing, Just Done
d) -> SomeException -> Maybe SomeException
forall a. a -> Maybe a
Just (SevereError -> SomeException
forall e. Exception e => e -> SomeException
toException (Done -> Maybe Text -> SevereError
SevereError Done
d (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
sql)))
(Maybe ServerMessage
Nothing, Maybe Done
Nothing) -> Maybe SomeException
forall a. Maybe a
Nothing
forM_ failure $ \SomeException
e -> do
Connection -> UnusableReason -> IO ()
markBroken Connection
conn (SomeException -> UnusableReason
resetFailure SomeException
e)
SomeException -> IO (ZonkAny 9)
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO SomeException
e
requestReset :: Connection -> IO ()
requestReset :: Connection -> IO ()
requestReset Connection
conn = Connection -> IO () -> IO ()
forall a. Connection -> IO a -> IO a
withConnectionLock Connection
conn (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
IORef Bool -> Bool -> IO ()
forall a. IORef a -> a -> IO ()
atomicWriteIORef (Connection -> IORef Bool
connResetPending Connection
conn) Bool
True
data RowBatch r = RowBatch
{ forall r. RowBatch r -> [r]
batchRows :: ![r]
, forall r. RowBatch r -> Maybe DecodeError
batchFailed :: !(Maybe DecodeError)
}
data StepProgress r
= StepReady (ResponseStep r)
| forall x. StepConsumer (IO x) (x -> IO (StepProgress r))
data ResponseStep r
= StepRows !(RowBatch r)
| StepToken !Token
| StepEnd
nextStep :: Connection -> ActiveResponse -> RowRead r -> IO (ResponseStep r)
nextStep :: forall r.
Connection -> ActiveResponse -> RowRead r -> IO (ResponseStep r)
nextStep Connection
conn ActiveResponse
ar RowRead r
decodeRow = Bool
-> Connection
-> ActiveResponse
-> Bool
-> RowRead r
-> IO (ResponseStep r)
forall r.
Bool
-> Connection
-> ActiveResponse
-> Bool
-> RowRead r
-> IO (ResponseStep r)
stepResponse Bool
False Connection
conn ActiveResponse
ar Bool
False RowRead r
decodeRow
nextStepReversed :: Connection -> ActiveResponse -> RowRead r -> IO (ResponseStep r)
nextStepReversed :: forall r.
Connection -> ActiveResponse -> RowRead r -> IO (ResponseStep r)
nextStepReversed Connection
conn ActiveResponse
ar RowRead r
decodeRow = Bool
-> Connection
-> ActiveResponse
-> Bool
-> RowRead r
-> IO (ResponseStep r)
forall r.
Bool
-> Connection
-> ActiveResponse
-> Bool
-> RowRead r
-> IO (ResponseStep r)
stepResponse Bool
True Connection
conn ActiveResponse
ar Bool
False RowRead r
decodeRow
nextToken :: Connection -> ActiveResponse -> IO (Maybe Token)
nextToken :: Connection -> ActiveResponse -> IO (Maybe Token)
nextToken Connection
conn ActiveResponse
ar = Bool
-> Connection
-> ActiveResponse
-> Bool
-> RowRead Row
-> IO (ResponseStep Row)
forall r.
Bool
-> Connection
-> ActiveResponse
-> Bool
-> RowRead r
-> IO (ResponseStep r)
stepResponse Bool
False Connection
conn ActiveResponse
ar Bool
True RowRead Row
wholeRows IO (ResponseStep Row)
-> (ResponseStep Row -> IO (Maybe Token)) -> IO (Maybe Token)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
StepRows (RowBatch [Row
row] Maybe DecodeError
_) -> Maybe Token -> IO (Maybe Token)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Token -> Maybe Token
forall a. a -> Maybe a
Just (Row -> Token
TRow Row
row))
StepRows RowBatch Row
_ -> ProtocolError -> IO (Maybe Token)
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO (ProtocolError -> IO (Maybe Token))
-> ProtocolError -> IO (Maybe Token)
forall a b. (a -> b) -> a -> b
$ [Char] -> ProtocolError
ProtocolError [Char]
"nextToken: a batch of one row without the row"
StepToken Token
tok -> Maybe Token -> IO (Maybe Token)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Token -> Maybe Token
forall a. a -> Maybe a
Just Token
tok)
ResponseStep Row
StepEnd -> Maybe Token -> IO (Maybe Token)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe Token
forall a. Maybe a
Nothing
checkCurrent :: Connection -> ActiveResponse -> IO ()
checkCurrent :: Connection -> ActiveResponse -> IO ()
checkCurrent Connection
conn ActiveResponse
ar = do
IORef Bool -> IO Bool
forall a. IORef a -> IO a
readIORef (ActiveResponse -> IORef Bool
arInConsumer ActiveResponse
ar) IO Bool -> (Bool -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Bool
active -> Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
active (ReentrantCallback -> IO ()
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO ReentrantCallback
ReentrantCallback)
Connection -> IO ()
checkLease Connection
conn
Connection -> IO ()
checkNotBroken Connection
conn
IORef (Maybe ActiveResponse) -> IO (Maybe ActiveResponse)
forall a. IORef a -> IO a
readIORef (Session -> IORef (Maybe ActiveResponse)
sessResponse (ActiveResponse -> Session
arSession ActiveResponse
ar)) IO (Maybe ActiveResponse)
-> (Maybe ActiveResponse -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Just ActiveResponse
ar' | ActiveResponse -> Int
arGeneration ActiveResponse
ar' Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== ActiveResponse -> Int
arGeneration ActiveResponse
ar -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
Maybe ActiveResponse
_ -> Connection -> IO ()
forall a. Connection -> IO a
abandoned Connection
conn
abandoned :: Connection -> IO a
abandoned :: forall a. Connection -> IO a
abandoned Connection
conn = Connection -> IO ()
checkNotBroken Connection
conn IO () -> IO a -> IO a
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ResultAbandoned -> IO a
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO ResultAbandoned
ResultAbandoned
stepResponse :: Bool -> Connection -> ActiveResponse -> Bool -> RowRead r -> IO (ResponseStep r)
stepResponse :: forall r.
Bool
-> Connection
-> ActiveResponse
-> Bool
-> RowRead r
-> IO (ResponseStep r)
stepResponse Bool
reversed Connection
conn ActiveResponse
ar Bool
oneRow RowRead r
decodeRow = Connection -> IO (ResponseStep r) -> IO (ResponseStep r)
forall a. Connection -> IO a -> IO a
withConnectionLock Connection
conn (IO (ResponseStep r) -> IO (ResponseStep r))
-> IO (ResponseStep r) -> IO (ResponseStep r)
forall a b. (a -> b) -> a -> b
$ do
IORef Bool -> IO Bool
forall a. IORef a -> IO a
readIORef (ActiveResponse -> IORef Bool
arInConsumer ActiveResponse
ar) IO Bool -> (Bool -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Bool
active -> Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
active (ReentrantCallback -> IO ()
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO ReentrantCallback
ReentrantCallback)
Connection -> IO ()
checkNotBroken Connection
conn
current <- IORef (Maybe ActiveResponse) -> IO (Maybe ActiveResponse)
forall a. IORef a -> IO a
readIORef (Session -> IORef (Maybe ActiveResponse)
sessResponse Session
sess)
case current of
Just ActiveResponse
ar' | ActiveResponse -> Int
arGeneration ActiveResponse
ar' Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== ActiveResponse -> Int
arGeneration ActiveResponse
ar ->
if ActiveResponse -> Bool
arCarriedReset ActiveResponse
ar then IORef [Token] -> IO [Token]
forall a. IORef a -> IO a
readIORef (ActiveResponse -> IORef [Token]
arReplay ActiveResponse
ar) IO [Token]
-> ([Token] -> IO (ResponseStep r)) -> IO (ResponseStep r)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= [Token] -> IO (ResponseStep r)
replayOr else IO (ResponseStep r)
step
Maybe ActiveResponse
_ -> Connection -> IO (ResponseStep r)
forall a. Connection -> IO a
abandoned Connection
conn
where
sess :: Session
sess = ActiveResponse -> Session
arSession ActiveResponse
ar
step :: IO (ResponseStep r)
step = (do
r <- Bool
-> Connection
-> ActiveResponse
-> Bool
-> RowRead r
-> IO (ResponseStep r)
forall r.
Bool
-> Connection
-> ActiveResponse
-> Bool
-> RowRead r
-> IO (ResponseStep r)
stepCoreWithOrder Bool
reversed Connection
conn ActiveResponse
ar Bool
oneRow RowRead r
decodeRow
settleReset conn ar r
runCallbacks conn r
pure r)
IO (ResponseStep r)
-> (SomeAsyncException -> IO (ResponseStep r))
-> IO (ResponseStep r)
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catch` \(SomeAsyncException
e :: SomeAsyncException) -> do
IO ()
cancelEagerly
SomeAsyncException -> IO (ResponseStep r)
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO SomeAsyncException
e
replayOr :: [Token] -> IO (ResponseStep r)
replayOr = \case
[] -> IO (ResponseStep r)
step
Token
tok : [Token]
rest -> IORef [Token] -> [Token] -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (ActiveResponse -> IORef [Token]
arReplay ActiveResponse
ar) [Token]
rest IO () -> IO (ResponseStep r) -> IO (ResponseStep r)
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ResponseStep r -> IO (ResponseStep r)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Token -> ResponseStep r
forall r. Token -> ResponseStep r
StepToken Token
tok)
cancelEagerly :: IO ()
cancelEagerly = do
sent <- Connection -> ActiveResponse -> IO Bool
cancelStatement Connection
conn ActiveResponse
ar
when sent $ abandonHandle ar
fullyArrived :: ActiveResponse -> IO Bool
fullyArrived :: ActiveResponse -> IO Bool
fullyArrived ActiveResponse
ar = do
eom <- ReadState -> Bool
readFinalPacket (ReadState -> Bool) -> IO ReadState -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IORef ReadState -> IO ReadState
forall a. IORef a -> IO a
readIORef (ActiveResponse -> IORef ReadState
arState ActiveResponse
ar)
case sessSmp (arSession ar) of
Just SmpSession
smp | Bool -> Bool
not Bool
eom -> (Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> ActiveResponse -> Int
arEomBase ActiveResponse
ar) (Int -> Bool) -> IO Int -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TVar Int -> IO Int
forall a. TVar a -> IO a
readTVarIO (SmpLink -> TVar Int
linkEoms (SmpSession -> SmpLink
smpLink SmpSession
smp))
Maybe SmpSession
_ -> Bool -> IO Bool
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
eom
runCallbacks :: Connection -> ResponseStep r -> IO ()
runCallbacks :: forall r. Connection -> ResponseStep r -> IO ()
runCallbacks Connection
conn = \case
StepToken (TEnvChange EnvChange
ec) -> IO () -> IO ()
forall a. IO a -> IO a
inCallback (Connection -> EnvChange -> IO ()
connOnEnvChange Connection
conn EnvChange
ec)
StepToken (TInfo ServerMessage
msg) -> IO () -> IO ()
forall a. IO a -> IO a
inCallback (Connection -> ServerMessage -> IO ()
connOnInfo Connection
conn ServerMessage
msg)
ResponseStep r
_ -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
where
inCallback :: IO c -> IO c
inCallback =
IO () -> IO () -> IO c -> IO c
forall a b c. IO a -> IO b -> IO c -> IO c
bracket_ (IORef Bool -> Bool -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (Connection -> IORef Bool
connInCallback Connection
conn) Bool
True) (IORef Bool -> Bool -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (Connection -> IORef Bool
connInCallback Connection
conn) Bool
False)
stepCore :: Connection -> ActiveResponse -> Bool -> RowRead r -> IO (ResponseStep r)
stepCore :: forall r.
Connection
-> ActiveResponse -> Bool -> RowRead r -> IO (ResponseStep r)
stepCore = Bool
-> Connection
-> ActiveResponse
-> Bool
-> RowRead r
-> IO (ResponseStep r)
forall r.
Bool
-> Connection
-> ActiveResponse
-> Bool
-> RowRead r
-> IO (ResponseStep r)
stepCoreWithOrder Bool
False
stepCoreWithOrder :: Bool -> Connection -> ActiveResponse -> Bool -> RowRead r -> IO (ResponseStep r)
stepCoreWithOrder :: forall r.
Bool
-> Connection
-> ActiveResponse
-> Bool
-> RowRead r
-> IO (ResponseStep r)
stepCoreWithOrder Bool
reversed Connection
conn ActiveResponse
ar Bool
requestedOne RowRead r
reader = ((forall a. IO a -> IO a) -> IO (ResponseStep r))
-> IO (ResponseStep r)
forall b. ((forall a. IO a -> IO a) -> IO b) -> IO b
mask (((forall a. IO a -> IO a) -> IO (ResponseStep r))
-> IO (ResponseStep r))
-> ((forall a. IO a -> IO a) -> IO (ResponseStep r))
-> IO (ResponseStep r)
forall a b. (a -> b) -> a -> b
$ \forall a. IO a -> IO a
restore -> do
let sess :: Session
sess = ActiveResponse -> Session
arSession ActiveResponse
ar
ahead :: Int
ahead = Connection -> Int
connValueAllocAhead Connection
conn
oneRow :: Bool
oneRow = Bool
requestedOne
rows :: ReadState -> [r] -> Maybe DecodeError -> IO (StepProgress r)
rows ReadState
state [r]
acc Maybe DecodeError
failed = do
IORef ReadState -> ReadState -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (ActiveResponse -> IORef ReadState
arState ActiveResponse
ar) ReadState
state
StepProgress r -> IO (StepProgress r)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ResponseStep r -> StepProgress r
forall r. ResponseStep r -> StepProgress r
StepReady (RowBatch r -> ResponseStep r
forall r. RowBatch r -> ResponseStep r
StepRows ([r] -> Maybe DecodeError -> RowBatch r
forall r. [r] -> Maybe DecodeError -> RowBatch r
RowBatch (if Bool
reversed then [r]
acc else [r] -> [r]
forall a. [a] -> [a]
reverse [r]
acc) Maybe DecodeError
failed)))
loop :: [r] -> IO (StepProgress r)
loop [r]
acc = IORef ReadState -> IO ReadState
forall a. IORef a -> IO a
readIORef (ActiveResponse -> IORef ReadState
arState ActiveResponse
ar) IO ReadState
-> (ReadState -> IO (StepProgress r)) -> IO (StepProgress r)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= [r] -> ReadState -> IO (StepProgress r)
at [r]
acc
at :: [r] -> ReadState -> IO (StepProgress r)
at [r]
acc ReadState
state = case ReadState -> ReadPosition
readPosition ReadState
state of
AtToken ByteString
bytes -> [r] -> Bool -> ByteString -> Int -> IO (StepProgress r)
atBytes [r]
acc (ReadState -> Bool
readFinalPacket ReadState
state) ByteString
bytes Int
0
Reading Stream Await IO ReadEvent
suspended -> [r]
-> ReadState -> Stream Await IO ReadEvent -> IO (StepProgress r)
resume [r]
acc ReadState
state Stream Await IO ReadEvent
suspended
Parked ByteString
bytes Parser ()
remainder -> [r]
-> ReadState -> Stream Await IO ReadEvent -> IO (StepProgress r)
resume [r]
acc ReadState
state (Stream Await IO ReadEvent -> IO (StepProgress r))
-> Stream Await IO ReadEvent -> IO (StepProgress r)
forall a b. (a -> b) -> a -> b
$
(Got () -> ReadEvent)
-> Stream Await IO (Got ()) -> Stream Await IO ReadEvent
forall a b. (a -> b) -> Stream Await IO a -> Stream Await IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\(P.Got () ByteString
rest) -> ByteString -> ReadEvent
SkippedRow ByteString
rest) (Parser () -> ByteString -> Stream Await IO (Got ())
forall a. Parser a -> ByteString -> Stream Await IO (Got a)
P.parse Parser ()
remainder ByteString
bytes)
atBytes :: [r] -> Bool -> ByteString -> Int -> IO (StepProgress r)
atBytes [r]
acc Bool
final ByteString
payload !Int
pos
| Bool
oneRow Bool -> Bool -> Bool
&& Bool -> Bool
not ([r] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [r]
acc) = ReadState -> [r] -> Maybe DecodeError -> IO (StepProgress r)
forall {r}.
ReadState -> [r] -> Maybe DecodeError -> IO (StepProgress r)
rows ReadState
state [r]
acc Maybe DecodeError
forall a. Maybe a
Nothing
| ByteString -> Int -> Bool
isRowTokenAt ByteString
payload Int
pos = [r] -> Bool -> ByteString -> Int -> IO (StepProgress r)
readRow [r]
acc Bool
final ByteString
payload Int
pos
| Bool -> Bool
not ([r] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [r]
acc) = ReadState -> [r] -> Maybe DecodeError -> IO (StepProgress r)
forall {r}.
ReadState -> [r] -> Maybe DecodeError -> IO (StepProgress r)
rows ReadState
state [r]
acc Maybe DecodeError
forall a. Maybe a
Nothing
| Int
pos Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= ByteString -> Int
B.length ByteString
payload = if Bool
final then IO (StepProgress r)
messageEnd else do
(body, end) <- Connection -> Session -> IO (ByteString, Bool)
readResponsePacket Connection
conn Session
sess
atBytes acc end body 0
| Bool
otherwise = [r] -> ReadState -> ByteString -> IO (StepProgress r)
startToken [r]
acc ReadState
state (Int -> ByteString -> ByteString
B.drop Int
pos ByteString
payload)
where state :: ReadState
state = Bool -> ReadPosition -> ReadState
ReadState Bool
final (ByteString -> ReadPosition
AtToken (Int -> ByteString -> ByteString
B.drop Int
pos ByteString
payload))
changed :: IO a
changed = ProtocolError -> IO a
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO ([Char] -> ProtocolError
ProtocolError [Char]
"row decoder changed inside a row")
readRow :: [r] -> Bool -> ByteString -> Int -> IO (StepProgress r)
readRow = case RowRead r
reader of
ReadRows Parser r
recipe IORef (Maybe (Either ReadFailure r))
inbox ->
\[r]
acc Bool
final ByteString
payload Int
pos -> case Parser r
-> ByteString
-> Int
-> Either (Stream Await IO (Got (Either ReadFailure r))) (At r)
forall a.
Parser a
-> ByteString
-> Int
-> Either (Stream Await IO (Got (Either ReadFailure a))) (At a)
P.runParserAt Parser r
recipe ByteString
payload Int
pos of
Right (P.At r
result Int
end) -> [r] -> Bool -> ByteString -> Int -> IO (StepProgress r)
atBytes (r
result r -> [r] -> [r]
forall a. a -> [a] -> [a]
: [r]
acc) Bool
final ByteString
payload Int
end
Right (P.FailedAt ReadFailure
failure Int
end) -> [r]
-> Bool -> ByteString -> Int -> ReadFailure -> IO (StepProgress r)
failedRow [r]
acc Bool
final ByteString
payload Int
end ReadFailure
failure
Left Stream Await IO (Got (Either ReadFailure r))
suspended -> [r]
-> ReadState
-> IORef (Maybe (Either ReadFailure r))
-> Stream Await IO (Got (Either ReadFailure r))
-> IO (StepProgress r)
driveRow [r]
acc (Bool -> ReadPosition -> ReadState
ReadState Bool
final (ByteString -> ReadPosition
AtToken (Int -> ByteString -> ByteString
B.drop Int
pos ByteString
payload))) IORef (Maybe (Either ReadFailure r))
inbox Stream Await IO (Got (Either ReadFailure r))
suspended
WholeRows Row -> r
_ -> ([r] -> ReadState -> ByteString -> IO (StepProgress r))
-> [r] -> Bool -> ByteString -> Int -> IO (StepProgress r)
forall {t} {t}.
(t -> ReadState -> ByteString -> t)
-> t -> Bool -> ByteString -> Int -> t
withPosition [r] -> ReadState -> ByteString -> IO (StepProgress r)
startToken
DiscardRows r
_ -> ([r] -> ReadState -> ByteString -> IO (StepProgress r))
-> [r] -> Bool -> ByteString -> Int -> IO (StepProgress r)
forall {t} {t}.
(t -> ReadState -> ByteString -> t)
-> t -> Bool -> ByteString -> Int -> t
withPosition [r] -> ReadState -> ByteString -> IO (StepProgress r)
skipCurrent
DrainRows r
_ -> ([r] -> ReadState -> ByteString -> IO (StepProgress r))
-> [r] -> Bool -> ByteString -> Int -> IO (StepProgress r)
forall {t} {t}.
(t -> ReadState -> ByteString -> t)
-> t -> Bool -> ByteString -> Int -> t
withPosition [r] -> ReadState -> ByteString -> IO (StepProgress r)
skipCurrent
RowRead r
StopAtRow -> ([r] -> ReadState -> ByteString -> IO (StepProgress r))
-> [r] -> Bool -> ByteString -> Int -> IO (StepProgress r)
forall {t} {t}.
(t -> ReadState -> ByteString -> t)
-> t -> Bool -> ByteString -> Int -> t
withPosition (\[r]
acc ReadState
state ByteString
_ -> ReadState -> [r] -> Maybe DecodeError -> IO (StepProgress r)
forall {r}.
ReadState -> [r] -> Maybe DecodeError -> IO (StepProgress r)
rows ReadState
state [r]
acc Maybe DecodeError
forall a. Maybe a
Nothing)
withPosition :: (t -> ReadState -> ByteString -> t)
-> t -> Bool -> ByteString -> Int -> t
withPosition t -> ReadState -> ByteString -> t
next t
acc Bool
final ByteString
payload Int
pos =
let bytes :: ByteString
bytes = Int -> ByteString -> ByteString
B.drop Int
pos ByteString
payload in t -> ReadState -> ByteString -> t
next t
acc (Bool -> ReadPosition -> ReadState
ReadState Bool
final (ByteString -> ReadPosition
AtToken ByteString
bytes)) ByteString
bytes
failedRow :: [r]
-> Bool -> ByteString -> Int -> ReadFailure -> IO (StepProgress r)
failedRow [r]
acc Bool
final ByteString
payload Int
end = \case
DecodeFailed DecodeError
err -> ReadState -> [r] -> Maybe DecodeError -> IO (StepProgress r)
forall {r}.
ReadState -> [r] -> Maybe DecodeError -> IO (StepProgress r)
rows (Bool -> ReadPosition -> ReadState
ReadState Bool
final (ByteString -> ReadPosition
AtToken (Int -> ByteString -> ByteString
B.drop Int
end ByteString
payload))) [r]
acc (DecodeError -> Maybe DecodeError
forall a. a -> Maybe a
Just DecodeError
err)
ReadFailure
ReadDiscarded -> [r] -> Bool -> ByteString -> Int -> IO (StepProgress r)
atBytes [r]
acc Bool
final ByteString
payload Int
end
skipCurrent :: [r] -> ReadState -> ByteString -> IO (StepProgress r)
skipCurrent [r]
acc ReadState
state ByteString
bytes = do
info <- IORef (Maybe ResultSetInfo) -> IO (Maybe ResultSetInfo)
forall a. IORef a -> IO a
readIORef (ActiveResponse -> IORef (Maybe ResultSetInfo)
arResultSet ActiveResponse
ar) IO (Maybe ResultSetInfo)
-> (Maybe ResultSetInfo -> IO ResultSetInfo) -> IO ResultSetInfo
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IO ResultSetInfo
-> (ResultSetInfo -> IO ResultSetInfo)
-> Maybe ResultSetInfo
-> IO ResultSetInfo
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
(ProtocolError -> IO ResultSetInfo
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO ([Char] -> ProtocolError
ProtocolError [Char]
"ROW without COLMETADATA")) ResultSetInfo -> IO ResultSetInfo
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
resume acc state $ fmap (\(P.Got () ByteString
rest) -> ByteString -> ReadEvent
SkippedRow ByteString
rest) (P.parse (skipRow info) bytes)
skipRow :: ResultSetInfo -> Parser ()
skipRow ResultSetInfo
info = do
bitmap <- Int -> Parser ByteString
V.rowBitmap (ResultSetInfo -> Int
rsColumnCount ResultSetInfo
info)
V.skipCells bitmap (rsCells info)
startToken :: [r] -> ReadState -> ByteString -> IO (StepProgress r)
startToken [r]
acc ReadState
state ByteString
bytes = do
cols <- IORef (Maybe ResultSetInfo) -> IO (Maybe ResultSetInfo)
forall a. IORef a -> IO a
readIORef (ActiveResponse -> IORef (Maybe ResultSetInfo)
arResultSet ActiveResponse
ar)
let token = case RowRead r
reader of DrainRows r
_ -> Maybe ResultSetInfo -> Parser Token
readTokenSkipping Maybe ResultSetInfo
cols; RowRead r
_ -> Int -> Maybe ResultSetInfo -> Parser Token
readTokenWith Int
ahead Maybe ResultSetInfo
cols
recipe = if ByteString -> Bool
isRowToken ByteString
bytes Bool -> Bool -> Bool
|| ByteString -> Bool
isReturnValueToken ByteString
bytes then Parser Token
token else Int -> Parser Token -> Parser Token
forall a. Int -> Parser a -> Parser a
P.limited Int
tokenSizeLimit Parser Token
token
resume acc state (fmap (\(P.Got Token
tok ByteString
rest) -> Token -> ByteString -> ReadEvent
ReadToken Token
tok ByteString
rest) (P.parse recipe bytes))
accept :: [r]
-> Bool
-> ByteString
-> Either ReadFailure r
-> IO (StepProgress r)
accept [r]
acc Bool
final ByteString
rest = \case
Left ReadFailure
failure -> [r]
-> Bool -> ByteString -> Int -> ReadFailure -> IO (StepProgress r)
failedRow [r]
acc Bool
final ByteString
rest Int
0 ReadFailure
failure
Right r
r -> [r] -> Bool -> ByteString -> Int -> IO (StepProgress r)
atBytes (r
r r -> [r] -> [r]
forall a. a -> [a] -> [a]
: [r]
acc) Bool
final ByteString
rest Int
0
driveRow :: [r]
-> ReadState
-> IORef (Maybe (Either ReadFailure r))
-> Stream Await IO (Got (Either ReadFailure r))
-> IO (StepProgress r)
driveRow [r]
acc ReadState
state IORef (Maybe (Either ReadFailure r))
inbox Stream Await IO (Got (Either ReadFailure r))
stream = Stream Await IO (Got (Either ReadFailure r))
-> IO
(Either
(Got (Either ReadFailure r))
(Await (Stream Await IO (Got (Either ReadFailure r)))))
forall (m :: * -> *) (f :: * -> *) r.
Monad m =>
Stream f m r -> m (Either r (f (Stream f m r)))
inspect Stream Await IO (Got (Either ReadFailure r))
stream IO
(Either
(Got (Either ReadFailure r))
(Await (Stream Await IO (Got (Either ReadFailure r)))))
-> (Either
(Got (Either ReadFailure r))
(Await (Stream Await IO (Got (Either ReadFailure r))))
-> IO (StepProgress r))
-> IO (StepProgress r)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Left (P.Got Either ReadFailure r
result ByteString
rest) -> [r]
-> Bool
-> ByteString
-> Either ReadFailure r
-> IO (StepProgress r)
accept [r]
acc (ReadState -> Bool
readFinalPacket ReadState
state) ByteString
rest Either ReadFailure r
result
Right Await (Stream Await IO (Got (Either ReadFailure r)))
await -> [r]
-> ReadState -> Stream Await IO ReadEvent -> IO (StepProgress r)
resume [r]
acc ReadState
state (Stream Await IO ReadEvent -> IO (StepProgress r))
-> Stream Await IO ReadEvent -> IO (StepProgress r)
forall a b. (a -> b) -> a -> b
$
(Got (Either ReadFailure r) -> ReadEvent)
-> Stream Await IO (Got (Either ReadFailure r))
-> Stream Await IO ReadEvent
forall a b. (a -> b) -> Stream Await IO a -> Stream Await IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\(P.Got Either ReadFailure r
result ByteString
rest) -> IO () -> ByteString -> ReadEvent
ReadRow (IORef (Maybe (Either ReadFailure r))
-> Maybe (Either ReadFailure r) -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (Maybe (Either ReadFailure r))
inbox (Either ReadFailure r -> Maybe (Either ReadFailure r)
forall a. a -> Maybe a
Just Either ReadFailure r
result)) ByteString
rest) (Await (Stream Await IO (Got (Either ReadFailure r)))
-> Stream Await IO (Got (Either ReadFailure r))
forall (m :: * -> *) (f :: * -> *) r.
(Monad m, Functor f) =>
f (Stream f m r) -> Stream f m r
Streaming.wrap Await (Stream Await IO (Got (Either ReadFailure r)))
await)
resume :: [r]
-> ReadState -> Stream Await IO ReadEvent -> IO (StepProgress r)
resume [r]
acc ReadState
state Stream Await IO ReadEvent
suspended = Stream Await IO ReadEvent
-> IO (Either ReadEvent (Await (Stream Await IO ReadEvent)))
forall (m :: * -> *) (f :: * -> *) r.
Monad m =>
Stream f m r -> m (Either r (f (Stream f m r)))
inspect Stream Await IO ReadEvent
suspended IO (Either ReadEvent (Await (Stream Await IO ReadEvent)))
-> (Either ReadEvent (Await (Stream Await IO ReadEvent))
-> IO (StepProgress r))
-> IO (StepProgress r)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Left ReadEvent
event -> case ReadEvent
event of
ReadToken Token
tok ByteString
rest -> do
Token -> IO ()
applyToken Token
tok
let after :: ReadState
after = ReadState
state { readPosition = AtToken rest }
case Token
tok of
TRow Row
row -> case RowRead r
reader of
WholeRows Row -> r
decode -> [r]
-> Bool
-> ByteString
-> Either ReadFailure r
-> IO (StepProgress r)
accept [r]
acc (ReadState -> Bool
readFinalPacket ReadState
state) ByteString
rest (r -> Either ReadFailure r
forall a b. b -> Either a b
Right (Row -> r
decode Row
row))
RowRead r
_ -> IO (StepProgress r)
-> (r -> IO (StepProgress r)) -> Maybe r -> IO (StepProgress r)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe IO (StepProgress r)
forall {b}. IO b
changed ([r]
-> Bool
-> ByteString
-> Either ReadFailure r
-> IO (StepProgress r)
accept [r]
acc (ReadState -> Bool
readFinalPacket ReadState
state) ByteString
rest (Either ReadFailure r -> IO (StepProgress r))
-> (r -> Either ReadFailure r) -> r -> IO (StepProgress r)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. r -> Either ReadFailure r
forall a b. b -> Either a b
Right) (RowRead r -> Maybe r
forall a. RowRead a -> Maybe a
skippedAs RowRead r
reader)
Token
_ -> IORef ReadState -> ReadState -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (ActiveResponse -> IORef ReadState
arState ActiveResponse
ar) ReadState
after IO () -> IO (StepProgress r) -> IO (StepProgress r)
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> StepProgress r -> IO (StepProgress r)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ResponseStep r -> StepProgress r
forall r. ResponseStep r -> StepProgress r
StepReady (Token -> ResponseStep r
forall r. Token -> ResponseStep r
StepToken Token
tok))
ReadRow IO ()
deliver ByteString
rest -> do
case RowRead r -> Maybe r
forall a. RowRead a -> Maybe a
skippedAs RowRead r
reader of
Just r
r -> [r]
-> Bool
-> ByteString
-> Either ReadFailure r
-> IO (StepProgress r)
accept [r]
acc (ReadState -> Bool
readFinalPacket ReadState
state) ByteString
rest (r -> Either ReadFailure r
forall a b. b -> Either a b
Right r
r)
Maybe r
Nothing -> case RowRead r
reader of
ReadRows Parser r
_ IORef (Maybe (Either ReadFailure r))
inbox -> do
IO ()
deliver
result <- IORef (Maybe (Either ReadFailure r))
-> IO (Maybe (Either ReadFailure r))
forall a. IORef a -> IO a
readIORef IORef (Maybe (Either ReadFailure r))
inbox
writeIORef inbox Nothing
maybe changed (accept acc (readFinalPacket state) rest) result
RowRead r
_ -> IO (StepProgress r)
forall {b}. IO b
changed
SkippedRow ByteString
rest -> do
let after :: ReadState
after = ReadState
state { readPosition = AtToken rest }
IO (StepProgress r)
-> (r -> IO (StepProgress r)) -> Maybe r -> IO (StepProgress r)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe ([r] -> ReadState -> IO (StepProgress r)
at [r]
acc ReadState
after) ([r]
-> Bool
-> ByteString
-> Either ReadFailure r
-> IO (StepProgress r)
accept [r]
acc (ReadState -> Bool
readFinalPacket ReadState
state) ByteString
rest (Either ReadFailure r -> IO (StepProgress r))
-> (r -> Either ReadFailure r) -> r -> IO (StepProgress r)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. r -> Either ReadFailure r
forall a b. b -> Either a b
Right) (RowRead r -> Maybe r
forall a. RowRead a -> Maybe a
skippedAs RowRead r
reader)
Right await :: Await (Stream Await IO ReadEvent)
await@(P.NeedMore Feed -> Stream Await IO ReadEvent
k) -> do
let pending :: ReadState
pending = ReadState
state { readPosition = Reading (Streaming.wrap await) }
IORef ReadState -> ReadState -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (ActiveResponse -> IORef ReadState
arState ActiveResponse
ar) ReadState
pending
if Bool -> Bool
not ([r] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [r]
acc) then ReadState -> [r] -> Maybe DecodeError -> IO (StepProgress r)
forall {r}.
ReadState -> [r] -> Maybe DecodeError -> IO (StepProgress r)
rows ReadState
pending [r]
acc Maybe DecodeError
forall a. Maybe a
Nothing else
if ReadState -> Bool
readFinalPacket ReadState
state then [r]
-> ReadState -> Stream Await IO ReadEvent -> IO (StepProgress r)
resume [] ReadState
pending (Feed -> Stream Await IO ReadEvent
k Feed
P.EndOfMessage) else do
(body, final) <- Connection -> Session -> IO (ByteString, Bool)
readResponsePacket Connection
conn Session
sess
resume [] pending { readFinalPacket = final } (k (case reader of DrainRows r
_ -> ByteString -> Feed
P.Discard ByteString
body; RowRead r
_ -> ByteString -> Feed
P.More ByteString
body))
Right await :: Await (Stream Await IO ReadEvent)
await@(P.RunConsumer Bool
live Runner -> IO x
io Maybe x -> Stream Await IO ReadEvent
k) -> do
let pending :: ReadState
pending = ReadState
state { readPosition = Reading (Streaming.wrap await) }
IORef ReadState -> ReadState -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (ActiveResponse -> IORef ReadState
arState ActiveResponse
ar) ReadState
pending
if Bool
live Bool -> Bool -> Bool
&& Bool -> Bool
not ([r] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [r]
acc) then ReadState -> [r] -> Maybe DecodeError -> IO (StepProgress r)
forall {r}.
ReadState -> [r] -> Maybe DecodeError -> IO (StepProgress r)
rows ReadState
pending [r]
acc Maybe DecodeError
forall a. Maybe a
Nothing else case RowRead r -> Maybe r
forall a. RowRead a -> Maybe a
skippedAs RowRead r
reader of
Just r
_ -> [r]
-> ReadState -> Stream Await IO ReadEvent -> IO (StepProgress r)
resume [r]
acc ReadState
state (Maybe x -> Stream Await IO ReadEvent
k Maybe x
forall a. Maybe a
Nothing)
Maybe r
Nothing -> StepProgress r -> IO (StepProgress r)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (StepProgress r -> IO (StepProgress r))
-> StepProgress r -> IO (StepProgress r)
forall a b. (a -> b) -> a -> b
$ IO x -> (x -> IO (StepProgress r)) -> StepProgress r
forall r x. IO x -> (x -> IO (StepProgress r)) -> StepProgress r
StepConsumer ((Runner -> IO x) -> IO x
forall a. (Runner -> IO a) -> IO a
runConsumer Runner -> IO x
io) ((x -> IO (StepProgress r)) -> StepProgress r)
-> (x -> IO (StepProgress r)) -> StepProgress r
forall a b. (a -> b) -> a -> b
$ \x
result -> do
final <- ReadState -> Bool
readFinalPacket (ReadState -> Bool) -> IO ReadState -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IORef ReadState -> IO ReadState
forall a. IORef a -> IO a
readIORef (ActiveResponse -> IORef ReadState
arState ActiveResponse
ar)
resume acc state { readFinalPacket = final } (k (Just result))
runConsumer :: (P.Runner -> IO a) -> IO a
runConsumer :: forall a. (Runner -> IO a) -> IO a
runConsumer Runner -> IO a
io = IO () -> IO () -> IO a -> IO a
forall a b c. IO a -> IO b -> IO c -> IO c
bracket_ IO ()
enter IO ()
leave (IO a -> IO a) -> IO a -> IO a
forall a b. (a -> b) -> a -> b
$ do
let feed :: IO Feed
feed = do
final <- ReadState -> Bool
readFinalPacket (ReadState -> Bool) -> IO ReadState -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IORef ReadState -> IO ReadState
forall a. IORef a -> IO a
readIORef (ActiveResponse -> IORef ReadState
arState ActiveResponse
ar)
if final then pure P.EndOfMessage else do
(body, end) <- readResponsePacket conn sess
modifyIORef' (arState ar) (\ReadState
s -> ReadState
s { readFinalPacket = end })
pure (P.More body)
pull :: Runner
pull = IO Feed -> Runner
P.feedRunner IO Feed
feed
runner :: Runner
runner = (forall a. IORef (Stream Await IO (Got a)) -> IO (Got a)) -> Runner
P.Runner ((forall a. IORef (Stream Await IO (Got a)) -> IO (Got a))
-> Runner)
-> (forall a. IORef (Stream Await IO (Got a)) -> IO (Got a))
-> Runner
forall a b. (a -> b) -> a -> b
$ \IORef (Stream Await IO (Got a))
current -> IO (Got a) -> IO (Got a)
forall a. IO a -> IO a
mask_ (IO (Got a) -> IO (Got a)) -> IO (Got a) -> IO (Got a)
forall a b. (a -> b) -> a -> b
$
Connection -> IO (Got a) -> IO (Got a)
forall a. Connection -> IO a -> IO a
breakOnFailure Connection
conn (Runner -> forall a. IORef (Stream Await IO (Got a)) -> IO (Got a)
P.runAwait Runner
pull IORef (Stream Await IO (Got a))
current)
IO a -> IO a
forall a. IO a -> IO a
restore (Runner -> IO a
io Runner
runner) IO a -> IO () -> IO a
forall a b. IO a -> IO b -> IO a
`onException` Connection -> ActiveResponse -> IO ()
abandonAtOnce Connection
conn ActiveResponse
ar
enter :: IO ()
enter = do
IORef Bool -> Bool -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (ActiveResponse -> IORef Bool
arInConsumer ActiveResponse
ar) Bool
True
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Maybe Mars -> Bool
forall a. Maybe a -> Bool
isNothing (Connection -> Maybe Mars
connMars Connection
conn)) (IORef Bool -> Bool -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (Connection -> IORef Bool
connInCallback Connection
conn) Bool
True)
leave :: IO ()
leave = do
IORef Bool -> Bool -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (ActiveResponse -> IORef Bool
arInConsumer ActiveResponse
ar) Bool
False
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Maybe Mars -> Bool
forall a. Maybe a -> Bool
isNothing (Connection -> Maybe Mars
connMars Connection
conn)) (IORef Bool -> Bool -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (Connection -> IORef Bool
connInCallback Connection
conn) Bool
False)
messageEnd :: IO (StepProgress r)
messageEnd = do
cancellation <- IORef Cancellation -> IO Cancellation
forall a. IORef a -> IO a
readIORef (ActiveResponse -> IORef Cancellation
arCancellation ActiveResponse
ar)
final <- readIORef (arSawFinalDone ar)
if cancellation == AttentionSent
then writeIORef (arState ar) (ReadState False (AtToken B.empty)) >> loop []
else if not final && cancellation /= AttentionAcknowledged
then throwIO (ProtocolError "response message ended without a final DONE token")
else writeIORef (sessResponse sess) Nothing >> pure (StepReady StepEnd)
applyToken :: Token -> IO ()
applyToken Token
tok = do
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Token -> Bool
isFinalDone Token
tok) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ IORef Bool -> Bool -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (ActiveResponse -> IORef Bool
arSawFinalDone ActiveResponse
ar) Bool
True
Maybe Done -> (Done -> IO ()) -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ (Token -> Maybe Done
doneOf Token
tok) ((Done -> IO ()) -> IO ()) -> (Done -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Done
d -> Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Done -> Bool
doneAttention Done
d) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
IORef Cancellation -> (Cancellation -> Cancellation) -> IO ()
forall a. IORef a -> (a -> a) -> IO ()
modifyIORef' (ActiveResponse -> IORef Cancellation
arCancellation ActiveResponse
ar) (\Cancellation
s -> if Cancellation
s Cancellation -> Cancellation -> Bool
forall a. Eq a => a -> a -> Bool
== Cancellation
AttentionSent then Cancellation
AttentionAcknowledged else Cancellation
s)
case Token
tok of
TError ServerMessage
msg | ServerMessage -> Word8
msgClass ServerMessage
msg Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
20 -> do
let err :: SqlServerError
err = ServerMessage -> Maybe Text -> SqlServerError
SqlServerError ServerMessage
msg (ActiveResponse -> Maybe Text
arStatement ActiveResponse
ar)
Connection -> UnusableReason -> IO ()
markBroken Connection
conn (ServerMessage -> UnusableReason
FatalServerError ServerMessage
msg)
SqlServerError -> IO ()
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO SqlServerError
err
TColMetaData [ColumnInfo]
cols -> IORef (Maybe ResultSetInfo) -> Maybe ResultSetInfo -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (ActiveResponse -> IORef (Maybe ResultSetInfo)
arResultSet ActiveResponse
ar) (ResultSetInfo -> Maybe ResultSetInfo
forall a. a -> Maybe a
Just ([ColumnInfo] -> ResultSetInfo
compileResultSet [ColumnInfo]
cols))
TEnvChange EnvChange
ec -> do
IORef TdsContext -> (TdsContext -> TdsContext) -> IO ()
forall a. IORef a -> (a -> a) -> IO ()
modifyIORef' (Connection -> IORef TdsContext
connContext Connection
conn) (EnvChange -> TdsContext -> TdsContext
applyEnvChange EnvChange
ec)
case EnvChange
ec of EnvChange
ECResetConnectionAck -> IORef Bool -> Bool -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (ActiveResponse -> IORef Bool
arSawResetAck ActiveResponse
ar) Bool
True; EnvChange
_ -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
Token
_ -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
let drive :: IO (StepProgress r) -> IO (ResponseStep r)
drive IO (StepProgress r)
reading = Connection -> IO (StepProgress r) -> IO (StepProgress r)
forall a. Connection -> IO a -> IO a
breakOnFailure Connection
conn IO (StepProgress r)
reading IO (StepProgress r)
-> (StepProgress r -> IO (ResponseStep r)) -> IO (ResponseStep r)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
StepReady ResponseStep r
step -> ResponseStep r -> IO (ResponseStep r)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ResponseStep r
step
StepConsumer IO x
consumer x -> IO (StepProgress r)
continue -> IO x
consumer IO x -> (x -> IO (ResponseStep r)) -> IO (ResponseStep r)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IO (StepProgress r) -> IO (ResponseStep r)
drive (IO (StepProgress r) -> IO (ResponseStep r))
-> (x -> IO (StepProgress r)) -> x -> IO (ResponseStep r)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. x -> IO (StepProgress r)
continue
IO (StepProgress r) -> IO (ResponseStep r)
forall {r}. IO (StepProgress r) -> IO (ResponseStep r)
drive ([r] -> IO (StepProgress r)
loop [])
readResponsePacket :: Connection -> Session -> IO (B.ByteString, Bool)
readResponsePacket :: Connection -> Session -> IO (ByteString, Bool)
readResponsePacket Connection
conn Session
sess = Connection -> IO (ByteString, Bool) -> IO (ByteString, Bool)
forall a. Connection -> IO a -> IO a
breakOnFailure Connection
conn (IO (ByteString, Bool) -> IO (ByteString, Bool))
-> IO (ByteString, Bool) -> IO (ByteString, Bool)
forall a b. (a -> b) -> a -> b
$ do
(header, bytes) <- Connection -> Session -> IO (Header, ByteString)
readSessionPacket Connection
conn Session
sess
unless (headerType header == PTTabularResult) $
throwIO (ProtocolError ("unexpected packet type " ++ show (headerType header)))
pure (bytes, headerStatus header `hasStatus` statusEndOfMessage)
abandonAtOnce :: Connection -> ActiveResponse -> IO ()
abandonAtOnce :: Connection -> ActiveResponse -> IO ()
abandonAtOnce Connection
conn ActiveResponse
ar = do
broken <- Maybe UnusableReason -> Bool
forall a. Maybe a -> Bool
isJust (Maybe UnusableReason -> Bool)
-> IO (Maybe UnusableReason) -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IORef (Maybe UnusableReason) -> IO (Maybe UnusableReason)
forall a. IORef a -> IO a
readIORef (Connection -> IORef (Maybe UnusableReason)
connBroken Connection
conn)
unless broken $ void (cancelStatement conn ar)
markAbandoned ar
abandonHandle ar
readPiece :: Connection -> ActiveResponse -> P.Parser a -> (a -> Maybe (P.Parser ())) -> IO a
readPiece :: forall a.
Connection
-> ActiveResponse -> Parser a -> (a -> Maybe (Parser ())) -> IO a
readPiece Connection
conn ActiveResponse
ar Parser a
recipe a -> Maybe (Parser ())
remainder = Connection -> IO a -> IO a
forall a. Connection -> IO a -> IO a
withConnectionLock Connection
conn (IO a -> IO a) -> IO a -> IO a
forall a b. (a -> b) -> a -> b
$ IO a -> IO a
forall a. IO a -> IO a
mask_ (IO a -> IO a) -> IO a -> IO a
forall a b. (a -> b) -> a -> b
$ do
Connection -> ActiveResponse -> IO ()
checkCurrent Connection
conn ActiveResponse
ar
state <- IORef ReadState -> IO ReadState
forall a. IORef a -> IO a
readIORef (ActiveResponse -> IORef ReadState
arState ActiveResponse
ar)
let start ByteString
bytes = ReadState -> Stream Await IO (Got a) -> IO a
drive ReadState
state (Parser a -> ByteString -> Stream Await IO (Got a)
forall a. Parser a -> ByteString -> Stream Await IO (Got a)
P.parse Parser a
recipe ByteString
bytes)
drive ReadState
current Stream Await IO (Got a)
stream = Connection
-> IO (Either (Got a) (Await (Stream Await IO (Got a))))
-> IO (Either (Got a) (Await (Stream Await IO (Got a))))
forall a. Connection -> IO a -> IO a
breakOnFailure Connection
conn (Stream Await IO (Got a)
-> IO (Either (Got a) (Await (Stream Await IO (Got a))))
forall (m :: * -> *) (f :: * -> *) r.
Monad m =>
Stream f m r -> m (Either r (f (Stream f m r)))
inspect Stream Await IO (Got a)
stream) IO (Either (Got a) (Await (Stream Await IO (Got a))))
-> (Either (Got a) (Await (Stream Await IO (Got a))) -> IO a)
-> IO a
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Left (P.Got a
a ByteString
rest) -> do
IORef ReadState -> ReadState -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (ActiveResponse -> IORef ReadState
arState ActiveResponse
ar) ReadState
current { readPosition = maybe (AtToken rest) (Parked rest) (remainder a) }
a -> IO a
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
a
Right await :: Await (Stream Await IO (Got a))
await@(P.NeedMore Feed -> Stream Await IO (Got a)
k) -> do
let drain :: Stream Await IO ReadEvent
drain = Await (Stream Await IO (Got a)) -> Stream Await IO (Got a)
forall (m :: * -> *) (f :: * -> *) r.
(Monad m, Functor f) =>
f (Stream f m r) -> Stream f m r
Streaming.wrap Await (Stream Await IO (Got a))
await Stream Await IO (Got a)
-> (Got a -> Stream Await IO ReadEvent)
-> Stream Await IO ReadEvent
forall a b.
Stream Await IO a -> (a -> Stream Await IO b) -> Stream Await IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \(P.Got a
a ByteString
rest) -> case a -> Maybe (Parser ())
remainder a
a of
Maybe (Parser ())
Nothing -> ReadEvent -> Stream Await IO ReadEvent
forall a. a -> Stream Await IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ByteString -> ReadEvent
SkippedRow ByteString
rest)
Just Parser ()
skip -> (Got () -> ReadEvent)
-> Stream Await IO (Got ()) -> Stream Await IO ReadEvent
forall a b. (a -> b) -> Stream Await IO a -> Stream Await IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\(P.Got () ByteString
rest') -> ByteString -> ReadEvent
SkippedRow ByteString
rest') (Parser () -> ByteString -> Stream Await IO (Got ())
forall a. Parser a -> ByteString -> Stream Await IO (Got a)
P.parse Parser ()
skip ByteString
rest)
pending :: ReadState
pending = ReadState
current { readPosition = Reading drain }
IORef ReadState -> ReadState -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (ActiveResponse -> IORef ReadState
arState ActiveResponse
ar) ReadState
pending
if ReadState -> Bool
readFinalPacket ReadState
current then ReadState -> Stream Await IO (Got a) -> IO a
drive ReadState
pending (Feed -> Stream Await IO (Got a)
k Feed
P.EndOfMessage) else do
(bytes, final) <- Connection -> Session -> IO (ByteString, Bool)
readResponsePacket Connection
conn (ActiveResponse -> Session
arSession ActiveResponse
ar)
drive pending { readFinalPacket = final } (k (P.More bytes))
Right P.RunConsumer{} -> ProtocolError -> IO a
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO ([Char] -> ProtocolError
ProtocolError [Char]
"a cell pull cannot invoke a field consumer")
interrupted (SomeAsyncException
err :: SomeAsyncException) = Connection -> ActiveResponse -> IO ()
abandonAtOnce Connection
conn ActiveResponse
ar IO () -> IO b -> IO b
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> SomeAsyncException -> IO b
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO SomeAsyncException
err
(case readPosition state of
AtToken ByteString
bytes -> ByteString -> IO a
start ByteString
bytes
Parked ByteString
bytes Parser ()
_ -> ByteString -> IO a
start ByteString
bytes
Reading Stream Await IO ReadEvent
_ -> ResultAbandoned -> IO a
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO ResultAbandoned
ResultAbandoned) `catch` interrupted
isRowToken :: B.ByteString -> Bool
isRowToken :: ByteString -> Bool
isRowToken ByteString
bs = ByteString -> Int -> Bool
isRowTokenAt ByteString
bs Int
0
isRowTokenAt :: B.ByteString -> Int -> Bool
isRowTokenAt :: ByteString -> Int -> Bool
isRowTokenAt ByteString
payload Int
pos = Int
pos Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< ByteString -> Int
B.length ByteString
payload Bool -> Bool -> Bool
&& (Word8
byte Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0xD1 Bool -> Bool -> Bool
|| Word8
byte Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0xD2)
where byte :: Word8
byte = HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
B.index ByteString
payload Int
pos
isReturnValueToken :: B.ByteString -> Bool
isReturnValueToken :: ByteString -> Bool
isReturnValueToken ByteString
bytes = Bool -> Bool
not (ByteString -> Bool
B.null ByteString
bytes) Bool -> Bool -> Bool
&& HasCallStack => ByteString -> Word8
ByteString -> Word8
B.head ByteString
bytes Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0xAC
applyEnvChange :: EnvChange -> TdsContext -> TdsContext
applyEnvChange :: EnvChange -> TdsContext -> TdsContext
applyEnvChange EnvChange
ec TdsContext
ctx = case EnvChange
ec of
ECPacketSize{Word32
newSize :: Word32
newSize :: EnvChange -> Word32
newSize} -> TdsContext
ctx { tdsPacketSize = newSize }
ECBeginTransaction{TransactionDescriptor
transaction :: TransactionDescriptor
transaction :: EnvChange -> TransactionDescriptor
transaction} -> TdsContext
ctx { tdsTransaction = Just transaction }
ECCommitTransaction{} -> TdsContext
ctx { tdsTransaction = Nothing }
ECRollbackTransaction{} -> TdsContext
ctx { tdsTransaction = Nothing }
ECDefectTransaction{} -> TdsContext
ctx { tdsTransaction = Nothing }
ECTransactionEnded{} -> TdsContext
ctx { tdsTransaction = Nothing }
ECEnlistDtcTransaction{TransactionDescriptor
transaction :: EnvChange -> TransactionDescriptor
transaction :: TransactionDescriptor
transaction} -> TdsContext
ctx { tdsTransaction = Just transaction }
EnvChange
ECResetConnectionAck -> TdsContext
ctx { tdsTransaction = Nothing }
ECSqlCollation{ByteString
newBytes :: ByteString
newBytes :: EnvChange -> ByteString
newBytes} -> TdsContext
ctx { tdsCollation = if B.null newBytes then Nothing else Just $! B.copy newBytes }
EnvChange
_ -> TdsContext
ctx
drainActiveResponse :: Connection -> ActiveResponse -> IO ()
drainActiveResponse :: Connection -> ActiveResponse -> IO ()
drainActiveResponse Connection
conn ActiveResponse
ar = do
r <- Connection -> ActiveResponse -> RowRead () -> IO (ResponseStep ())
forall r.
Connection -> ActiveResponse -> RowRead r -> IO (ResponseStep r)
nextStep Connection
conn ActiveResponse
ar RowRead ()
drainingRows
case r of
ResponseStep ()
StepEnd -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
ResponseStep ()
_ -> Connection -> ActiveResponse -> IO ()
drainActiveResponse Connection
conn ActiveResponse
ar
finishResponse :: Connection -> IO ()
finishResponse :: Connection -> IO ()
finishResponse Connection
conn = Connection -> IO () -> IO ()
forall a. Connection -> IO a -> IO a
withConnectionLock Connection
conn (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
sessions <- Connection -> IO [Session]
allSessions Connection
conn
when (isJust (connMars conn)) $
forM_ sessions $ \Session
sess -> IORef (Maybe ActiveResponse) -> IO (Maybe ActiveResponse)
forall a. IORef a -> IO a
readIORef (Session -> IORef (Maybe ActiveResponse)
sessResponse Session
sess) IO (Maybe ActiveResponse)
-> (Maybe ActiveResponse -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (ActiveResponse -> IO ()) -> Maybe ActiveResponse -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (Connection -> ActiveResponse -> IO ()
cancelRunning Connection
conn)
mapM_ (finishSession conn) sessions
finishSession :: Connection -> Session -> IO ()
finishSession :: Connection -> Session -> IO ()
finishSession Connection
conn Session
sess = Connection -> IO () -> IO ()
forall a. Connection -> IO a -> IO a
withConnectionLock Connection
conn (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
IORef (Maybe ActiveResponse) -> IO (Maybe ActiveResponse)
forall a. IORef a -> IO a
readIORef (Session -> IORef (Maybe ActiveResponse)
sessResponse Session
sess) IO (Maybe ActiveResponse)
-> (Maybe ActiveResponse -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Maybe ActiveResponse
Nothing -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
Just ActiveResponse
ar -> do
Connection -> ActiveResponse -> IO ()
cancelRunning Connection
conn ActiveResponse
ar
Connection -> ActiveResponse -> IO ()
drainActiveResponse Connection
conn ActiveResponse
ar IO () -> (SomeException -> IO ()) -> IO ()
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catch` \(SomeException
e :: SomeException) -> do
Connection -> UnusableReason -> IO ()
markBroken Connection
conn ((SomeException -> UnusableReason)
-> SomeException -> UnusableReason
reasonFor SomeException -> UnusableReason
DrainFailed SomeException
e)
SomeException -> IO ()
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO SomeException
e
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (ActiveResponse -> Bool
arCarriedReset ActiveResponse
ar) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
acked <- IORef Bool -> IO Bool
forall a. IORef a -> IO a
readIORef (ActiveResponse -> IORef Bool
arSawResetAck ActiveResponse
ar)
unless acked $ atomicWriteIORef (connResetPending conn) True
cancelRunning :: Connection -> ActiveResponse -> IO ()
cancelRunning :: Connection -> ActiveResponse -> IO ()
cancelRunning Connection
conn ActiveResponse
ar = do
arrived <- ActiveResponse -> IO Bool
fullyArrived ActiveResponse
ar
attentionSent <- attentionWasSent <$> readIORef (arCancellation ar)
unless (arrived || attentionSent) $ mask_ $ do
ctx <- readIORef (connContext conn)
sendFramed conn (arSession ar) ctx PTAttention (PacketStatus 0) LB.empty
writeIORef (arCancellation ar) AttentionSent
cancelActiveResponse :: Connection -> ActiveResponse -> IO ()
cancelActiveResponse :: Connection -> ActiveResponse -> IO ()
cancelActiveResponse Connection
conn ActiveResponse
ar = Connection -> IO () -> IO ()
forall a. Connection -> IO a -> IO a
withConnectionLock Connection
conn (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
ended <- Maybe SomeException -> Bool
forall a. Maybe a -> Bool
isJust (Maybe SomeException -> Bool)
-> IO (Maybe SomeException) -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TVar (Maybe SomeException) -> IO (Maybe SomeException)
forall a. TVar a -> IO a
readTVarIO (Connection -> TVar (Maybe SomeException)
connEnded Connection
conn)
broken <- isJust <$> readIORef (connBroken conn)
current <- readIORef (sessResponse sess)
case current of
Just ActiveResponse
ar' | Bool -> Bool
not (Bool
ended Bool -> Bool -> Bool
|| Bool
broken), ActiveResponse -> IORef ReadState
arState ActiveResponse
ar' IORef ReadState -> IORef ReadState -> Bool
forall a. Eq a => a -> a -> Bool
== ActiveResponse -> IORef ReadState
arState ActiveResponse
ar -> Connection -> Session -> IO ()
finishSession Connection
conn Session
sess
Maybe ActiveResponse
_ -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
where
sess :: Session
sess = ActiveResponse -> Session
arSession ActiveResponse
ar
busyStatements :: Connection -> IO [Text]
busyStatements :: Connection -> IO [Text]
busyStatements Connection
conn = do
sessions <- Connection -> IO [Session]
allSessions Connection
conn
busy <- catMaybes <$> forM sessions (readIORef . sessResponse)
pure [fromMaybe "(a request without SQL text)" (arStatement ar) | ar <- busy]