2012-03-13 10 views
5

私の問題は次のとおりです。私はRDBファイル(Redisが生成するダンプファイル)用のストリーミングパーサーを実装しようとしています。私はmapM_に似た関数を実装したいと思います。これは、解析されたときにダンプファイルに表現された各オブジェクトを出力することができます。しかし、私はそれが一定の空間で動作するように見えることはできません。私は、何が起こっているのかは、Getモナドの内部に大きなIO()サンクを構築し、Getモナドから戻ってIOを実行することです。オブジェクトを印刷してから破棄するときにオブジェクトをストリーミングする方法はありますか?私はEnumeratorsとConduitsを試しましたが、私は本当の利益を見ていません。これまで私が持っているものは次のとおりです。Get Monad内のIO

loadObjs_ :: (Monad m) => (Maybe Integer -> BL8.ByteString -> RDBObj -> Get (m a)) -> Get (m a) 
loadObjs_ f = do 
      code <- lookAhead getWord8 
      case code of 
       0xfd -> do 
       skip 1 
       expire <- loadTime 
       getPairs_ f (Just expire) 
       0xfc -> do 
       skip 1 
       expire <- loadTimeMs 
       getPairs_ f (Just expire) 
       0xfe -> f Nothing "Switching Database" RDBNull 
       0xff -> f Nothing "" RDBNull 
       _ -> getPairs_ f Nothing 

getPairs_ :: (Monad m) => (Maybe Integer -> BL8.ByteString -> RDBObj -> Get (m a)) -> Maybe Integer -> Get (m a) 
getPairs_ f ex = do 
       !t <- getWord8 
       !key <- loadStringObj False 
       !obj <- loadObj t 
       !rest <- loadObjs_ f 
       !out <- f ex key obj 
       return (out >> rest) 


(loadObj does the actual parsing of a single object but I believe that whatever I need to fix the streaming to operate in constant or near-constant memory is at a higher level in the iteration than loadObj) 

getDBs_ :: (Monad m) => (Maybe Integer -> BL8.ByteString -> RDBObj -> Get (m a)) -> Get (m a) 
getDBs_ f = do 
      opc <- lookAhead getWord8 
      if opc == opcodeSelectdb 
       then do 
        skip 1 
        (isEncType,dbnum) <- loadLen 
        objs <- loadObjs_ f 
        rest <- getDBs_ f 
        return (objs >> rest) 
       else f Nothing "EOF" RDBNull 

processRDB_ :: (Monad m) => (Maybe Integer -> BL8.ByteString -> RDBObj -> Get (m a)) -> Get (m a) 
processRDB_ f = do 
       header <- getBytes 9 
       dbs <- getDBs_ f 
       eof <- getWord8 
       return (dbs) 

printRDBObj :: Maybe Integer -> BL8.ByteString -> RDBObj -> Get (IO()) 
printRDBObj (Just exp) key obj = return $ (print ("Expires: " ++ show exp) >> 
              print ("Key: " ++ (BL8.unpack key)) >> 
              print ("Obj: " ++ show obj)) 
printRDBObj Nothing key RDBNull = return $ (print $ BL8.unpack key) 
printRDBObj Nothing key obj = return $ (print ("Key: " ++ (BL8.unpack key)) >> 
             print ("Obj: " ++ show obj)) 


main = do 
     testf <- BL8.readFile "./dump.rdb" 
     runGet (processRDB_ printRDBObj) testf 

ありがとうございました。

ベスト

、 エリック

編集:ここで怠惰なリストかけてIOを怠惰なリストにオブジェクトを解析し、する私の試みです。

processRDB :: Get [RDBObj] 

processRDB = do 
       header <- getBytes 9 
       dbs <- getDBs 
       eof <- getWord8 
       return (dbs) 

main = do 
     testf <- BL8.readFile "./dump.rdb" 
     mapM_ (print . show) $ runGet processRDB testf 
+0

http://hackage.haskell.org/package/binary-strictを試しましたか? –

+0

私はバイナリを厳密に試してみませんでしたが、シリアルを厳密に入手しようとはしませんでした。 –

+0

あなたはそれをより厳しくしたくない、あなたはそれを怠惰にしたい。どこかで何かが厳しすぎている。しかし、私は適切なパッケージの周りに自分の道を十分にわからない。 –

答えて

2

私が正しくあなたのコードを理解していれば、あなたはその後、インクリメンタルにそれらのアクションを実行するのを期待して、インクリメンタルIOアクションにファイルの内容を変換しようとしています。

より良い方法は、パーサーがオブジェクトの怠惰なリストを返してから印刷することです。

+1

ああ、私もこれを試しました。私は 'mapM_ 'と呼ばれるオブジェクトのリストにRDBを構文解析するコードのバージョンを持っています。 (印刷してください) 'うん、私は実行中の最初と同じヒープスパイクを参照します。これは繰り返し処理され、ガベージコレクトされると徐々に減少します。 –

+0

私は上記の意味を示す編集を追加しました。 –