lmdb-simple 0.3.0.0 → 0.3.1.0
raw patch · 7 files changed
+102/−76 lines, 7 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- README.md +24/−1
- lmdb-simple.cabal +2/−2
- src/Database/LMDB/Simple.hs +1/−6
- src/Database/LMDB/Simple/DBRef.hs +23/−49
- src/Database/LMDB/Simple/Internal.hs +43/−14
- test/Database/LMDB/Simple/DBRefSpec.hs +6/−2
- test/Database/LMDB/SimpleSpec.hs +3/−2
README.md view
@@ -2,6 +2,29 @@ Simple Haskell API for LMDB =========================== -This is a simple API for the [Lightning Memory-mapped Database][LMDB].+This package allows you to store arbitrary Haskell values in and retrieve them+from a persistent [Lightning Memory-mapped Database][LMDB] on disk. [LMDB]: https://symas.com/lightning-memory-mapped-database/++LMDB is a high-performance [ACID][]-compliant no-maintenance read-optimized+key-value store. Any Haskell value with a [`Serialise`][Serialise] instance+can be stored in an LMDB database, or used as a key to index one.++ [ACID]: https://en.wikipedia.org/wiki/ACID+ [Serialise]: https://hackage.haskell.org/package/serialise/docs/Codec-Serialise-Tutorial.html#g:3++This package provides a few different APIs for using LMDB:++ * The basic API provides transactional `put` and `get` functions to store+ and retrieve values from an LMDB database.++ * The extended API provides many functions similar to those in `Data.Map`,+ e.g. `lookup`, `insert`, `delete`, `foldr`, and so on.++ * The `View` API provides a read-only snapshot of an LMDB database that can+ be queried from pure code.++ * The `DBRef` API provides a mutable variable similar to `IORef` that is+ tied to a particular key in an LMDB database.+
lmdb-simple.cabal view
@@ -1,6 +1,6 @@ name: lmdb-simple-version: 0.3.0.0+version: 0.3.1.0 synopsis: Simple API for LMDB @@ -42,8 +42,8 @@ build-depends: base >= 4.7 && < 5 , bytestring >= 0.10 && < 0.11- , serialise >= 0.1 && < 0.2 , lmdb >= 0.2 && < 0.3+ , serialise >= 0.1 && < 0.2 ghc-options: -Wall -Wno-name-shadowing -Wno-unused-do-bind default-language: Haskell2010 default-extensions: Trustworthy
src/Database/LMDB/Simple.hs view
@@ -35,7 +35,7 @@ These additional APIs are available: * "Database.LMDB.Simple.Extra" provides additional functions for querying- and modifying LMDB databases within the 'Transaction' monad+ and modifying LMDB databases from within the 'Transaction' monad * "Database.LMDB.Simple.View" provides a read-only snapshot of an LMDB database that can be accessed from pure code@@ -77,10 +77,6 @@ , SubMode ) where -import Prelude hiding- ( lookup- )- import Control.Concurrent ( runInBoundThread )@@ -129,7 +125,6 @@ , isReadOnlyTransaction , isReadWriteTransaction )- import qualified Database.LMDB.Simple.Internal as Internal import Foreign.C
src/Database/LMDB/Simple/DBRef.hs view
@@ -13,32 +13,15 @@ ) where import Control.Monad- ( (>=>)- , void- )--import Control.Monad.IO.Class- ( MonadIO (liftIO)+ ( void ) import Data.ByteString ( ByteString ) -import Data.ByteString.Lazy- ( toStrict- )--import Data.ByteString.Unsafe- ( unsafeUseAsCStringLen- )- import Database.LMDB.Raw ( MDB_dbi'- , MDB_val (..)- , mdb_get'- , mdb_put'- , mdb_del' ) import Database.LMDB.Simple@@ -52,14 +35,10 @@ , ReadWrite , ReadOnly , Serialise- , serialise- , marshalIn- , marshalOut- , defaultWriteFlags- )--import Foreign- ( castPtr+ , serialiseBS+ , getBS+ , putBS+ , deleteBS ) -- | A 'DBRef' is a reference to a particular key within an LMDB database. It@@ -76,32 +55,26 @@ -- environment. newDBRef :: Serialise k => Environment mode -> Database k a -> k -> IO (DBRef mode a)-newDBRef env (Db _ dbi) = return . Ref env dbi . toStrict . serialise--withVal :: ByteString -> (MDB_val -> IO a) -> IO a-withVal bs f = unsafeUseAsCStringLen bs $ \(ptr, len) ->- f $ MDB_val (fromIntegral len) (castPtr ptr)+newDBRef env (Db _ dbi) = return . Ref env dbi . serialiseBS -- | Read the current value of a 'DBRef'. readDBRef :: Serialise a => DBRef mode a -> IO (Maybe a)-readDBRef ref@(Ref env dbi key) = transaction env (tx ref)+readDBRef ref@(Ref env dbi key) = transaction env (tx env ref) - where tx :: Serialise a => DBRef mode a -> Transaction ReadOnly (Maybe a)- tx _ = Txn $ \txn -> withVal key $ mdb_get' txn dbi >=>- maybe (return Nothing) (liftIO . fmap Just . marshalIn)+ where tx :: Serialise a+ => Environment mode -> DBRef mode a -> Transaction ReadOnly (Maybe a)+ tx (Env env) _ = getBS (Db env dbi) key -- | Write a new value into a 'DBRef'. writeDBRef :: Serialise a => DBRef ReadWrite a -> Maybe a -> IO ()-writeDBRef (Ref env dbi key) = transaction env . maybe delKey putKey+writeDBRef (Ref env dbi key) = transaction env . maybe (delKey env) (putKey env) - where delKey :: Transaction ReadWrite ()- delKey = Txn $ \txn -> withVal key $ \kval ->- void $ mdb_del' txn dbi kval Nothing+ where delKey :: Environment ReadWrite -> Transaction ReadWrite ()+ delKey (Env env) = void $ deleteBS (Db env dbi) key - putKey :: Serialise a => a -> Transaction ReadWrite ()- putKey value = Txn $ \txn -> withVal key $ \kval ->- marshalOut value $ \vval -> -- FIXME: use mdb_reserve'- void $ mdb_put' defaultWriteFlags txn dbi kval vval+ putKey :: Serialise a+ => Environment ReadWrite -> a -> Transaction ReadWrite ()+ putKey (Env env) = putBS (Db env dbi) key -- | Atomically mutate the contents of a 'DBRef'. modifyDBRef_ :: Serialise a => DBRef ReadWrite a -> (Maybe a -> Maybe a) -> IO ()@@ -110,11 +83,12 @@ -- | Atomically mutate the contents of a 'DBRef' and return a value. modifyDBRef :: Serialise a => DBRef ReadWrite a -> (Maybe a -> (Maybe a, b)) -> IO b-modifyDBRef (Ref env dbi key) = transaction env . tx+modifyDBRef (Ref env dbi key) = transaction env . tx env - where tx :: Serialise a => (Maybe a -> (Maybe a, b)) -> Transaction ReadWrite b- tx f = Txn $ \txn -> withVal key $ \kval -> mdb_get' txn dbi kval >>=- maybe (return Nothing) (fmap Just . marshalIn) >>= \x ->- let (x', r) = f x in maybe (mdb_del' txn dbi kval Nothing)- (flip marshalOut $ mdb_put' defaultWriteFlags txn dbi kval) x' >>+ where tx :: Serialise a+ => Environment mode -> (Maybe a -> (Maybe a, b))+ -> Transaction ReadWrite b+ tx (Env env) f = let db = Db env dbi in+ getBS db key >>= \x -> let (x', r) = f x in+ maybe (void $ deleteBS db key) (putBS db key) x' >> return r
src/Database/LMDB/Simple/Internal.hs view
@@ -14,7 +14,7 @@ , isReadOnlyEnvironment , isReadOnlyTransaction , isReadWriteTransaction- , serialise+ , serialiseBS , marshalOut , marshalIn , peekVal@@ -25,8 +25,12 @@ , overwriteFlags , get , get'+ , getBS+ , getBS' , put+ , putBS , delete+ , deleteBS ) where import Codec.Serialise@@ -95,7 +99,9 @@ , copyBytes ) -import GHC.Exts (Constraint)+import GHC.Exts+ ( Constraint+ ) data ReadWrite data ReadOnly@@ -166,13 +172,22 @@ peekVal :: Serialise v => Ptr MDB_val -> IO v peekVal = peek >=> marshalIn +serialiseLBS :: Serialise v => v -> BSL.ByteString+serialiseLBS = serialise++serialiseBS :: Serialise v => v -> BS.ByteString+serialiseBS = toStrict . serialiseLBS+ marshalIn :: Serialise v => MDB_val -> IO v marshalIn (MDB_val len ptr) = deserialise . fromStrict <$> packCStringLen (castPtr ptr, fromIntegral len) marshalOut :: Serialise v => v -> (MDB_val -> IO a) -> IO a-marshalOut value f =- unsafeUseAsCStringLen (toStrict $ serialise value) $ \(ptr, len) ->+marshalOut = marshalOutBS . serialiseBS++marshalOutBS :: BS.ByteString -> (MDB_val -> IO a) -> IO a+marshalOutBS bs f =+ unsafeUseAsCStringLen bs $ \(ptr, len) -> f $ MDB_val (fromIntegral len) (castPtr ptr) copyLazyBS :: BSL.ByteString -> Ptr Word8 -> Int -> IO ()@@ -211,22 +226,36 @@ get :: (Serialise k, Serialise v) => Database k v -> k -> Transaction mode (Maybe v)-get db key = get' db key >>=- maybe (return Nothing) (liftIO . fmap Just . marshalIn)+get db = getBS db . serialiseBS get' :: Serialise k => Database k v -> k -> Transaction mode (Maybe MDB_val)-get' (Db _ dbi) key = Txn $ \txn -> marshalOut key $ mdb_get' txn dbi+get' db = getBS' db . serialiseBS +getBS :: Serialise v+ => Database k v -> BS.ByteString -> Transaction mode (Maybe v)+getBS db keyBS = getBS' db keyBS >>=+ maybe (return Nothing) (liftIO . fmap Just . marshalIn)++getBS' :: Database k v -> BS.ByteString -> Transaction mode (Maybe MDB_val)+getBS' (Db _ dbi) keyBS = Txn $ \txn -> marshalOutBS keyBS $ mdb_get' txn dbi+ put :: (Serialise k, Serialise v) => Database k v -> k -> v -> Transaction ReadWrite ()-put (Db _ dbi) key value = Txn $ \txn ->- marshalOut key $ \kval -> do- let bs = serialise value- sz = fromIntegral (BSL.length bs)+put db = putBS db . serialiseBS++putBS :: Serialise v+ => Database k v -> BS.ByteString -> v -> Transaction ReadWrite ()+putBS (Db _ dbi) keyBS value = Txn $ \txn ->+ marshalOutBS keyBS $ \kval -> do+ let valueLBS = serialiseLBS value+ sz = fromIntegral (BSL.length valueLBS) MDB_val len ptr <- mdb_reserve' defaultWriteFlags txn dbi kval sz let len' = fromIntegral len- assert (len' == sz) $ copyLazyBS bs ptr len'+ assert (len' == sz) $ copyLazyBS valueLBS ptr len' delete :: Serialise k => Database k v -> k -> Transaction ReadWrite Bool-delete (Db _ dbi) key = Txn $ \txn ->- marshalOut key $ \kval -> mdb_del' txn dbi kval Nothing+delete db = deleteBS db . serialiseBS++deleteBS :: Database k v -> BS.ByteString -> Transaction ReadWrite Bool+deleteBS (Db _ dbi) key = Txn $ \txn ->+ marshalOutBS key $ \kval -> mdb_del' txn dbi kval Nothing
test/Database/LMDB/Simple/DBRefSpec.hs view
@@ -22,6 +22,10 @@ (modifyDBRef_ ref (fmap (++ "bar")) >> readDBRef ref) `shouldReturn` Just "foobar" - it "can be made empty again" $ \ref ->- (writeDBRef ref Nothing >> readDBRef ref)+ it "can be emptied with modifyDBRef" $ \ref ->+ (modifyDBRef_ ref (const Nothing) >> readDBRef ref)+ `shouldReturn` Nothing++ it "can be emptied with writeDBRef" $ \ref ->+ (writeDBRef ref (Just "baz") >> writeDBRef ref Nothing >> readDBRef ref) `shouldReturn` Nothing
test/Database/LMDB/SimpleSpec.hs view
@@ -29,8 +29,9 @@ describe "transactions" $ do it "aborts" $ \(env, db) ->- transaction env (put db 0 (Just "zero") >> abort)- `shouldThrow` (const True :: Selector AbortedTransaction)+ ( do transaction env $ put db 0 Nothing+ transaction env $ put db 0 (Just "zero") >> abort+ ) `shouldThrow` (const True :: Selector AbortedTransaction) it "rolls back" $ \(env, db) -> readOnlyTransaction env (get db 0)