packages feed

hedis 0.7.10 → 0.8.0

raw patch · 5 files changed

+74/−38 lines, 5 filesdep +scannerdep +textdep −attoparsecPVP ok

version bump matches the API change (PVP)

Dependencies added: scanner, text

Dependencies removed: attoparsec

API changes (from Hackage documentation)

Files

CHANGELOG view
@@ -1,5 +1,9 @@ # Changelog for Hedis +## 0.8.0++* Major speed improvement by using non-backtracking parser (PR #69)+ ## 0.7.10  * Improved performance (PR #64)
hedis.cabal view
@@ -1,5 +1,5 @@ name:               hedis-version:            0.7.10+version:            0.8.0 synopsis:     Client library for the Redis datastore: supports full command set,     pipelining.@@ -63,10 +63,11 @@   if flag(dev)     ghc-prof-options: -auto-all   exposed-modules:  Database.Redis-  build-depends:    attoparsec >= 0.12,+  build-depends:    scanner >= 0.2,                     base >= 4.6 && < 5,                     bytestring >= 0.9,                     bytestring-lexing >= 0.5,+                    text,                     deepseq,                     mtl >= 2,                     network >= 2,
src/Database/Redis/Protocol.hs view
@@ -9,11 +9,14 @@ import Control.Applicative #endif import Control.DeepSeq-import Data.Attoparsec.ByteString (takeTill)-import Data.Attoparsec.ByteString.Char8 hiding (takeTill)+import Scanner (Scanner)+import qualified Scanner import Data.ByteString.Char8 (ByteString) import GHC.Generics import qualified Data.ByteString.Char8 as B+import qualified Data.Text.Encoding as Text+import qualified Data.Text.Read as Text+import Control.Monad (replicateM)  -- |Low-level representation of replies from the Redis server. data Reply = SingleLine ByteString@@ -48,36 +51,61 @@ ------------------------------------------------------------------------------ -- Reply parsers ---reply :: Parser Reply+{-# INLINE reply #-}+reply :: Scanner Reply reply = do-  c <- anyChar+  c <- Scanner.anyChar8   case c of-    '+' -> singleLine+    '+' -> string     '-' -> error     ':' -> integer     '$' -> bulk-    '*' -> multiBulk+    '*' -> multi     _ -> fail "Unknown reply type" -singleLine :: Parser Reply-singleLine = SingleLine <$> (takeTill isEndOfLine <* endOfLine)+{-# INLINE string #-}+string :: Scanner Reply+string = SingleLine <$> line -error :: Parser Reply-error = Error <$> (takeTill isEndOfLine <* endOfLine)+{-# INLINE error #-}+error :: Scanner Reply+error = Error <$> line -integer :: Parser Reply-integer = Integer <$> (signed decimal <* endOfLine)+{-# INLINE integer #-}+integer :: Scanner Reply+integer = Integer <$> integral -bulk :: Parser Reply+{-# INLINE bulk #-}+bulk :: Scanner Reply bulk = Bulk <$> do-    len <- signed decimal <* endOfLine-    if len < 0-        then return Nothing-        else Just <$> take len <* endOfLine+  len <- integral+  if len < 0+    then return Nothing+    else Just <$> Scanner.take len <* eol -multiBulk :: Parser Reply-multiBulk = MultiBulk <$> do-    len <- signed decimal <* endOfLine-    if len < 0-        then return Nothing-        else Just <$> count len reply+-- don't inline it to break the circle between reply and multi+{-# NOINLINE multi #-}+multi :: Scanner Reply+multi = MultiBulk <$> do+  len <- integral+  if len < 0+    then return Nothing+    else Just <$> replicateM len reply++{-# INLINE integral #-}+integral :: Integral i => Scanner i+integral = do+  str <- line+  case Text.signed Text.decimal (Text.decodeUtf8 str) of+    Left err -> fail (show err)+    Right (l, _) -> return l++{-# INLINE line #-}+line :: Scanner ByteString+line = Scanner.takeWhileChar8 (/= '\r') <* eol++{-# INLINE eol #-}+eol :: Scanner ()+eol = do+  Scanner.char8 '\r'+  Scanner.char8 '\n'
src/Database/Redis/ProtocolPipelining.hs view
@@ -23,7 +23,7 @@ import           Prelude import           Control.Exception import           Control.Monad-import           Data.Attoparsec.ByteString+import qualified Scanner import qualified Data.ByteString as S import           Data.IORef import           Data.Typeable@@ -116,11 +116,11 @@       ~(r, rest') <- unsafeInterleaveIO $ do         -- Force previous reply for correct order.         previous `seq` return ()-        parseResult <- parseWith readMore reply rest-        case parseResult of-          Fail{}       -> errConnClosed-          Partial{}    -> error "Hedis: parseWith returned Partial"-          Done rest' r -> do+        scanResult <- Scanner.scanWith readMore reply rest+        case scanResult of+          Scanner.Fail{}       -> errConnClosed+          Scanner.More{}    -> error "Hedis: parseWith returned Partial"+          Scanner.Done rest' r -> do             -- r is the same as 'head' of 'connPending'. Since we just             -- received r, we remove it from the pending list.             atomicModifyIORef' connPending $ \(_:rs) -> (rs, ())
test/Test.hs view
@@ -437,14 +437,17 @@         scriptFlush                             >>=? Ok         -- start long running script from another client         configSet "lua-time-limit" "100"        >>=? Ok-        liftIO $ do-            _ <- fork $ runRedis conn $ do-                -- we must pattern match to block the thread-                Left _ <- eval "while true do end" [] []-                    :: Redis (Either Reply Integer)-                return ()-            threadDelay 500000 -- 0.5s+        evalFinished <- liftIO newEmptyMVar+        void $ liftIO $ fork $ runRedis conn $ do+            -- we must pattern match to block the thread+            Left _ <- eval "while true do end" [] []+                :: Redis (Either Reply Integer)+            liftIO (putMVar evalFinished ())+            return ()+        liftIO (threadDelay 500000) -- 0.5s         scriptKill                              >>=? Ok+        () <- liftIO (takeMVar evalFinished)+        return ()  ------------------------------------------------------------------------------ -- Connection