2012-03-13 17 views
5

Entonces mi problema es el siguiente. Estoy tratando de implementar un analizador de transmisión para archivos RDB (los archivos de volcado que produce Redis). Quiero implementar una función similar a mapM_ mediante la cual pueda, por ejemplo, imprimir cada objeto representado en el archivo de volcado a medida que se analiza. Sin embargo, parece que no puedo hacer que funcione en un espacio constante. Me parece que lo que está sucediendo es que estoy construyendo un gran IO() thunk dentro de la mónada Get, volviendo de la mónada Get y luego ejecutando el IO. ¿Hay alguna forma de transmitir mis objetos a medida que se analizan para imprimirlos y luego descartarlos? He intentado Enumerators y Conduits pero no he visto ninguna ganancia real. Esto es lo que tengo hasta ahora:IO dentro de 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 

Gracias de antemano.

mejor, Erik

EDIT: Aquí está mi intento de analizar los objetos en una lista perezosa y luego IO sobre la lista perezoso.

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

¿Has probado http://hackage.haskell.org/package/binary-strict? –

+0

No he probado el binario estricto, pero sí intenté obtener el estricto consumo de cereal en vano. –

+0

No desea que sea más estricto, desea hacerlo más tranquilo. Algo en algún lado es ser demasiado estricto. Pero no sé cómo manejar los paquetes relevantes lo suficientemente bien. –

Respuesta

2

Si entiendo el código correctamente, están tratando de convertir el contenido del archivo en acciones IO de forma incremental, con la esperanza de luego ejecutar esas acciones de forma incremental.

Un mejor enfoque sería hacer que su analizador devuelva una lista perezosa de objetos que luego imprima.

+1

Ah sí, lo he intentado también. Tengo una versión del código que analiza el RDB en una lista de objetos a los que llamo 'mapM_. (print. show) 'alas Veo el mismo pico de montón al comienzo de mi ejecución que se atenúa gradualmente a medida que se repite y recoge la basura: –

+0

He añadido la edición que muestra lo que quiero decir. –

Cuestiones relacionadas