2012-03-13 2 views
5

Итак, моя проблема заключается в следующем. Я пытаюсь реализовать потоковый парсер для файлов RDB (файлы дампа, которые производит Redis). Я хочу реализовать функцию, похожую на mapM_, в которой я могу, скажем, распечатать каждый объект, представленный в файле дампа, по мере его разбора. Однако я не могу заставить его работать в постоянном пространстве. Я нахожу, что происходит то, что я создаю большой IO() thunk внутри монады Get, возвращаясь из монады Get, а затем выполняю IO. Есть ли все равно, чтобы передать мои объекты, когда они разбираются для печати, а затем отбрасывают их? Я пробовал счетчики и каналы, но я не видел никакой реальной выгоды. Вот что у меня есть до сих пор:IO внутри 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 

Спасибо за все.

Беста, Erik

EDIT: Вот моя попытка разобрать объекты в ленивый список, а затем 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

Если я понимаю ваш код правильно, вы пытаетесь преобразовать содержимое файла в действия ввода-вывода постепенно, в надежде на то выполнение этих действий постепенно.

Лучшим подходом было бы, чтобы ваш парсер вернул ленивый список объектов, которые вы затем распечатываете.

+1

Ах да, я тоже это пробовал. У меня есть версия кода, который анализирует RDB в список объектов, на которые я называю 'mapM_. (print. show) 'alas Я вижу тот же самый кусок в начале моего выполнения, который постепенно уменьшается, когда он выполняет итерацию и собирает мусор: –

+0

Я добавил редактирование, показывающее, что я имею в виду выше. –

Смежные вопросы