patternMinor
Simple Haskell key value file store
Viewed 0 times
filesimplevaluestorehaskellkey
Problem
As an exercise in learning Haskell, I implemented a simple key value store, where you can put and get values (as
```
{-# LANGUAGE OverloadedStrings #-}
module KV (
evalKV,
putKV,
getKV,
liftIO
) where
import Prelude hiding (mapM)
import Data.Traversable (mapM)
import Control.Monad (liftM, liftM2)
import Control.Monad.State (StateT, evalStateT, get, put, liftIO)
import qualified System.IO as IO
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as L
import qualified Data.Binary as B
import qualified Data.Binary.Get as G
import qualified Data.Map as M
type Header = (Integer, Integer)
-- keysize valuesize
type ValueInfo = (Integer, Integer)
-- offset valuesize
type Key = ByteString
type Pair = (Key, ValueInfo)
type Index = M.Map Key ValueInfo
data KVState = KVState
{ kvHandle :: IO.Handle
, kvIndex :: Index
} deriving (Show)
type KV a = StateT KVState IO a
evalKV :: FilePath -> KV a -> IO a
evalKV p s = IO.withBinaryFile p IO.ReadWriteMode $ \h -> do
i ByteString -> KV ()
putKV k v = do
(KVState h i) KV (Maybe ByteString)
getKV k = do
(KVState h i) (Header, Integer)
readHeader c = (h, fromIntegral o)
where (h, _, o) = G.runGetState B.get c 0
readAt :: IO.Handle -> Integer -> Integer -> IO ByteString
readAt h o sz = do
IO.hSeek h IO.AbsoluteSeek o
L.hGet h $ fromIntegral sz
readPair :: IO.Handle -> Integer -> IO (Maybe Pair)
readPair h o = do
IO.hSeek h IO.AbsoluteSeek o
b ByteString -> ByteString -> IO ValueInfo
writePair h k v = do
IO.hSeek h IO.SeekFromEnd 0
let l = fromIntegral . L.length
let vsz = l v
let t = (l k, vsz) :: Header
L.hPut h (B.encode t)
L.hPut h k
p IO Index
readIndex h =
ByteStrings). (For reference this is inspired by this short note describing bitcask's design). I'd appreciate feedback on any aspect (style, 'haskellyness', library usage etc.) of my implementation:```
{-# LANGUAGE OverloadedStrings #-}
module KV (
evalKV,
putKV,
getKV,
liftIO
) where
import Prelude hiding (mapM)
import Data.Traversable (mapM)
import Control.Monad (liftM, liftM2)
import Control.Monad.State (StateT, evalStateT, get, put, liftIO)
import qualified System.IO as IO
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as L
import qualified Data.Binary as B
import qualified Data.Binary.Get as G
import qualified Data.Map as M
type Header = (Integer, Integer)
-- keysize valuesize
type ValueInfo = (Integer, Integer)
-- offset valuesize
type Key = ByteString
type Pair = (Key, ValueInfo)
type Index = M.Map Key ValueInfo
data KVState = KVState
{ kvHandle :: IO.Handle
, kvIndex :: Index
} deriving (Show)
type KV a = StateT KVState IO a
evalKV :: FilePath -> KV a -> IO a
evalKV p s = IO.withBinaryFile p IO.ReadWriteMode $ \h -> do
i ByteString -> KV ()
putKV k v = do
(KVState h i) KV (Maybe ByteString)
getKV k = do
(KVState h i) (Header, Integer)
readHeader c = (h, fromIntegral o)
where (h, _, o) = G.runGetState B.get c 0
readAt :: IO.Handle -> Integer -> Integer -> IO ByteString
readAt h o sz = do
IO.hSeek h IO.AbsoluteSeek o
L.hGet h $ fromIntegral sz
readPair :: IO.Handle -> Integer -> IO (Maybe Pair)
readPair h o = do
IO.hSeek h IO.AbsoluteSeek o
b ByteString -> ByteString -> IO ValueInfo
writePair h k v = do
IO.hSeek h IO.SeekFromEnd 0
let l = fromIntegral . L.length
let vsz = l v
let t = (l k, vsz) :: Header
L.hPut h (B.encode t)
L.hPut h k
p IO Index
readIndex h =
Solution
Why not:
Instead of commenting, like you did here:
Same about
type KeySize = Integer
type ValueSize = Integer
type Header = (KeySize, ValueSize)Instead of commenting, like you did here:
type Header = (Integer, Integer)
-- keysize valuesizeSame about
ValueInfo.Code Snippets
type KeySize = Integer
type ValueSize = Integer
type Header = (KeySize, ValueSize)type Header = (Integer, Integer)
-- keysize valuesizeContext
StackExchange Code Review Q#9177, answer score: 2
Revisions (0)
No revisions yet.