Skip to content

Commit

Permalink
Fixes "unconsumed data left on socket" condition
Browse files Browse the repository at this point in the history
This is an ugly fix, but it makes life so much easier: we now read data
1 byte at a time when being in the single-object-parser-mode, leaving a
lot more room for performance.
  • Loading branch information
solatis committed Mar 8, 2015
1 parent 12824ad commit 039bfc9
Showing 1 changed file with 12 additions and 8 deletions.
20 changes: 12 additions & 8 deletions src/Network/Attoparsec.hs
Expand Up @@ -54,18 +54,19 @@ parseMany :: ( MonadIO m
-> ParseC a -- ^ Continuation parser state
-> m (ParseC a, [a]) -- ^ Next parser state with parsed values
parseMany s p0 pCur = do
buf <- readAvailable s
buf <- readAvailable s Nothing
(p1, xs) <- parseBuffer p0 Many buf pCur
return (p1, xs)

-- | Similar to parseMany, but assumes that there will only be enough data for a
-- single succesful parse on the socket, and guarantees that exactly one item
-- will be parsed.
--
-- __Warning:__ this function will /not/ work correctly when input data is
-- pipelined. The parser might consume more data than required from the socket,
-- or a partial second object is parsed, and the parser state and buffer will
-- be discarded.
-- __Warning:__ In order to make this function work stable with pipelined data,
-- we read in data one byte at a time, which causes many context
-- switches and kernel syscalls, and furthermore causes a lot of
-- separate calls to attoparsec. So only use if performance is not
-- a consideration.
--
-- The is typically used as follows:
--
Expand All @@ -77,7 +78,7 @@ parseOne :: ( MonadIO m
-> ParseC a -- ^ Initial parser state
-> m a -- ^ Parsed value
parseOne s p0 = do
buf <- readAvailable s
buf <- readAvailable s (Just 1)
(p1, value) <- parseBuffer p0 Single buf p0

case value of
Expand All @@ -99,6 +100,7 @@ parseBuffer :: ( MonadIO m
-> m (ParseC a, [a]) -- ^ Next parser state with parsed values
parseBuffer p0 mode =


let next bCur pCur =
case pCur bCur of
-- On error, throw error through MonadError
Expand Down Expand Up @@ -129,13 +131,15 @@ parseBuffer p0 mode =
readAvailable :: ( MonadIO m
, MonadMask m)
=> NS.Socket
-> Maybe Int
-> m BS.ByteString
readAvailable s =
readAvailable s Nothing = readAvailable s (Just 2048)
readAvailable s (Just bytes) =
let buf :: IO (Maybe BS.ByteString)
buf = do
-- For some reason, Windows seems to be generating an exception sometimes
-- when the remote has closed the connection
result <- tryAny $ NSB.recv s 2048
result <- tryAny $ NSB.recv s bytes

case result of
Left _ -> return Nothing
Expand Down

0 comments on commit 039bfc9

Please sign in to comment.