2012-03-13 26 views
5

Vì vậy, vấn đề của tôi là như sau. Tôi đang cố gắng để thực hiện một phân tích cú pháp streaming cho các tập tin RDB (các tập tin dump mà Redis sản xuất). Tôi muốn thực hiện một chức năng tương tự như mapM_ theo đó tôi có thể nói, in ra từng đối tượng được biểu diễn trong tệp kết xuất khi nó được phân tích cú pháp. Tuy nhiên, tôi dường như không thể làm cho nó hoạt động trong không gian liên tục. Tôi thấy rằng những gì đang xảy ra là tôi đang xây dựng một IO lớn() thunk bên trong của Get monad, trở về từ Get monad và sau đó thực thi IO. Có anyway để dòng các đối tượng của tôi khi chúng được phân tích cú pháp để in và sau đó loại bỏ chúng? Tôi đã thử Enumerators và Conduits nhưng tôi đã không nhìn thấy bất kỳ lợi ích thực sự. Dưới đây là những gì tôi có cho đến thời điểm này:IO bên trong Get Monad

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 

Xin cảm ơn tất cả trước.

nhất, Erik

EDIT: Đây là nỗ lực của tôi để phân tích các đối tượng vào một danh sách lười biếng và sau đó IO qua danh sách lười biếng.

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

Bạn đã thử http://hackage.haskell.org/package/binary-strict chưa? –

+0

Tôi đã không thử nhị phân nghiêm ngặt nhưng tôi đã cố gắng nhận được nghiêm ngặt của ngũ cốc không có avail. –

+0

Bạn không muốn làm cho nó khắt khe hơn, bạn muốn làm cho nó trở nên lười hơn. Cái gì đó ở đâu đó quá nghiêm ngặt. Nhưng tôi không biết cách của tôi xung quanh các gói có liên quan cũng đủ. –

Trả lời

2

Nếu tôi hiểu mã của bạn một cách chính xác, bạn đang cố gắng để chuyển đổi các nội dung tập tin thành hành động IO từng bước, với hy vọng sau đó thực hiện những hành động từng bước.

Một cách tiếp cận tốt hơn sẽ là để trình phân tích cú pháp của bạn trả lại danh sách các đối tượng lười biếng mà bạn in ra.

+1

Ah vâng, tôi cũng đã thử điều này. Tôi có một phiên bản của mã phân tích RDB thành một danh sách các đối tượng mà tôi gọi là 'mapM_. (print. show) 'alas tôi thấy cùng một đống tăng đột biến vào đầu thực hiện của tôi mà dần dần mờ đi khi nó lặp đi lặp lại và rác thu thập: –

+0

Tôi thêm chỉnh sửa hiển thị những gì tôi có ý nghĩa ở trên. –