2012-03-13 5 views
5

그래서 내 문제는 다음과 같습니다. RDB 파일 (Redis가 생성하는 덤프 파일) 용 스트리밍 파서를 구현하려고합니다. mapM_와 비슷한 기능을 구현하고 싶습니다. 구문 분석 할 때마다 덤프 파일에 표시된 각 객체를 출력 할 수 있습니다. 그러나, 나는 그것이 일정한 공간에서 작동하도록 할 수 없습니다. 내가 무슨 일이 일어나고 있다는 것을 알게되면, Get 모나드 내부에 큰 IO() 썽크를 만들고, Get 모나드에서 돌아온 다음 IO를 실행하고있다. 인쇄물을 파싱 한 다음 폐기하기 위해 객체를 스트리밍 할 여지가 있습니까? 나는 열거 자 (Enumerators)와 도관 (Conduits)을 시도했지만 실제 이득을 보지 못했습니다. 여기까지 제가 가지고있는 것이 있습니다 :입출력 내 입출력

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

나는 binary-strict를 시도하지는 않았지만, 시리얼을 엄격하게 사용하려고 시도하지는 않았다. –

+0

당신은 그것을 더 엄격하게 만들고 싶지 않습니다, 당신은 그것을 게으르게 만들고 싶습니다. 뭔가 어딘가 너무 엄격합니다. 그러나 관련 패키지를 잘 이해할 수는 없습니다. –

답변

2

, 당신은 점차적으로 이러한 작업을 실행하는 희망으로, 점진적으로 IO 작업으로 파일 내용을 변환하기 위해 노력하고 있습니다.

더 나은 방법은 파서가 객체의 게으른 목록을 반환하여 출력하는 것입니다.

+1

아 그래, 나는 이것도 시도했다. RDB를'mapM_ '이라고하는 객체 목록으로 파싱하는 코드 버전이 있습니다. (인쇄 쇼)'아아, 나는 반복 실행과 쓰레기 수거로 점차적으로 희박 해지는 나의 실행 초기에 같은 힙 스파이크를 본다 : –

+0

위의 의미를 보여주는 편집을 추가했다. –