leveldb-haskell 0.2.0 → 0.3.0
raw patch · 16 files changed
+1831/−1347 lines, 16 filesdep +asyncdep +leveldb-haskellnew-component:exe:leveldb-example-comparatornew-component:exe:leveldb-example-featuresnew-component:exe:leveldb-example-filterpolicynew-component:exe:leveldb-example-iterforkioPVP ok
version bump matches the API change (PVP)
Dependencies added: async, leveldb-haskell
API changes (from Hackage documentation)
- Database.LevelDB: Comparator :: (ByteString -> ByteString -> Ordering) -> Comparator
- Database.LevelDB: Del :: ByteString -> BatchOp
- Database.LevelDB: FilterPolicy :: String -> ([ByteString] -> ByteString) -> (ByteString -> ByteString -> Bool) -> FilterPolicy
- Database.LevelDB: NoCompression :: Compression
- Database.LevelDB: NumFilesAtLevel :: Int -> Property
- Database.LevelDB: Options :: !Int -> !Int -> !Int -> !(Maybe Comparator) -> !Compression -> !Bool -> !Bool -> !Int -> !Bool -> !Int -> !(Maybe (Either BloomFilter FilterPolicy)) -> Options
- Database.LevelDB: Put :: ByteString -> ByteString -> BatchOp
- Database.LevelDB: ReadOptions :: !Bool -> !Bool -> !(Maybe Snapshot) -> ReadOptions
- Database.LevelDB: SSTables :: Property
- Database.LevelDB: Snappy :: Compression
- Database.LevelDB: Stats :: Property
- Database.LevelDB: WriteOptions :: !Bool -> WriteOptions
- Database.LevelDB: approximateSize :: MonadResource m => DB -> Range -> m Int64
- Database.LevelDB: blockRestartInterval :: Options -> !Int
- Database.LevelDB: blockSize :: Options -> !Int
- Database.LevelDB: bloomFilter :: MonadResource m => Int -> m BloomFilter
- Database.LevelDB: cacheSize :: Options -> !Int
- Database.LevelDB: class (MonadThrow m, MonadUnsafeIO m, MonadIO m, Applicative m) => MonadResource (m :: * -> *)
- Database.LevelDB: comparator :: Options -> !(Maybe Comparator)
- Database.LevelDB: compression :: Options -> !Compression
- Database.LevelDB: createFilter :: FilterPolicy -> [ByteString] -> ByteString
- Database.LevelDB: createIfMissing :: Options -> !Bool
- Database.LevelDB: createSnapshot :: MonadResource m => DB -> m Snapshot
- Database.LevelDB: createSnapshot' :: MonadResource m => DB -> m (ReleaseKey, Snapshot)
- Database.LevelDB: data BatchOp
- Database.LevelDB: data Compression
- Database.LevelDB: data DB
- Database.LevelDB: data FilterPolicy
- Database.LevelDB: data Iterator
- Database.LevelDB: data Options
- Database.LevelDB: data Property
- Database.LevelDB: data ReadOptions
- Database.LevelDB: data Snapshot
- Database.LevelDB: data WriteOptions
- Database.LevelDB: defaultOptions :: Options
- Database.LevelDB: defaultReadOptions :: ReadOptions
- Database.LevelDB: defaultWriteOptions :: WriteOptions
- Database.LevelDB: delete :: MonadResource m => DB -> WriteOptions -> ByteString -> m ()
- Database.LevelDB: destroy :: MonadResource m => FilePath -> Options -> m ()
- Database.LevelDB: errorIfExists :: Options -> !Bool
- Database.LevelDB: fillCache :: ReadOptions -> !Bool
- Database.LevelDB: filterPolicy :: Options -> !(Maybe (Either BloomFilter FilterPolicy))
- Database.LevelDB: fpName :: FilterPolicy -> String
- Database.LevelDB: get :: MonadResource m => DB -> ReadOptions -> ByteString -> m (Maybe ByteString)
- Database.LevelDB: getProperty :: MonadResource m => DB -> Property -> m (Maybe ByteString)
- Database.LevelDB: instance Default Options
- Database.LevelDB: instance Default ReadOptions
- Database.LevelDB: instance Default WriteOptions
- Database.LevelDB: instance Eq BatchOp
- Database.LevelDB: instance Eq Compression
- Database.LevelDB: instance Eq DB
- Database.LevelDB: instance Eq Iterator
- Database.LevelDB: instance Eq Property
- Database.LevelDB: instance Eq ReadOptions
- Database.LevelDB: instance Eq Snapshot
- Database.LevelDB: instance Eq WriteOptions
- Database.LevelDB: instance Show BatchOp
- Database.LevelDB: instance Show Compression
- Database.LevelDB: instance Show Property
- Database.LevelDB: instance Show WriteOptions
- Database.LevelDB: iterFirst :: MonadResource m => Iterator -> m ()
- Database.LevelDB: iterGetError :: MonadResource m => Iterator -> m (Maybe ByteString)
- Database.LevelDB: iterItems :: MonadResource m => Iterator -> m [(ByteString, ByteString)]
- Database.LevelDB: iterKey :: MonadResource m => Iterator -> m (Maybe ByteString)
- Database.LevelDB: iterKeys :: MonadResource m => Iterator -> m [ByteString]
- Database.LevelDB: iterLast :: MonadResource m => Iterator -> m ()
- Database.LevelDB: iterNext :: MonadResource m => Iterator -> m ()
- Database.LevelDB: iterOpen :: MonadResource m => DB -> ReadOptions -> m Iterator
- Database.LevelDB: iterOpen' :: MonadResource m => DB -> ReadOptions -> m (ReleaseKey, Iterator)
- Database.LevelDB: iterPrev :: MonadResource m => Iterator -> m ()
- Database.LevelDB: iterSeek :: MonadResource m => Iterator -> ByteString -> m ()
- Database.LevelDB: iterValid :: MonadResource m => Iterator -> m Bool
- Database.LevelDB: iterValue :: MonadResource m => Iterator -> m (Maybe ByteString)
- Database.LevelDB: iterValues :: MonadResource m => Iterator -> m [ByteString]
- Database.LevelDB: keyMayMatch :: FilterPolicy -> ByteString -> ByteString -> Bool
- Database.LevelDB: liftResourceT :: MonadResource m => ResourceT IO a -> m a
- Database.LevelDB: mapIter :: MonadResource m => (Iterator -> m a) -> Iterator -> m [a]
- Database.LevelDB: maxOpenFiles :: Options -> !Int
- Database.LevelDB: newtype Comparator
- Database.LevelDB: open :: MonadResource m => FilePath -> Options -> m DB
- Database.LevelDB: paranoidChecks :: Options -> !Bool
- Database.LevelDB: put :: MonadResource m => DB -> WriteOptions -> ByteString -> ByteString -> m ()
- Database.LevelDB: repair :: MonadResource m => FilePath -> Options -> m ()
- Database.LevelDB: resourceForkIO :: MonadBaseControl IO m => ResourceT m () -> ResourceT m ThreadId
- Database.LevelDB: runResourceT :: MonadBaseControl IO m => ResourceT m a -> m a
- Database.LevelDB: sync :: WriteOptions -> !Bool
- Database.LevelDB: type Range = (ByteString, ByteString)
- Database.LevelDB: type WriteBatch = [BatchOp]
- Database.LevelDB: useSnapshot :: ReadOptions -> !(Maybe Snapshot)
- Database.LevelDB: verifyCheckSums :: ReadOptions -> !Bool
- Database.LevelDB: version :: MonadResource m => m (Int, Int)
- Database.LevelDB: withIterator :: MonadResource m => DB -> ReadOptions -> (Iterator -> m a) -> m a
- Database.LevelDB: withSnapshot :: MonadResource m => DB -> (Snapshot -> m a) -> m a
- Database.LevelDB: write :: MonadResource m => DB -> WriteOptions -> WriteBatch -> m ()
- Database.LevelDB: writeBufferSize :: Options -> !Int
+ Database.LevelDB.Base: Comparator :: (ByteString -> ByteString -> Ordering) -> Comparator
+ Database.LevelDB.Base: Del :: ByteString -> BatchOp
+ Database.LevelDB.Base: FilterPolicy :: String -> ([ByteString] -> ByteString) -> (ByteString -> ByteString -> Bool) -> FilterPolicy
+ Database.LevelDB.Base: NoCompression :: Compression
+ Database.LevelDB.Base: NumFilesAtLevel :: Int -> Property
+ Database.LevelDB.Base: Options :: !Int -> !Int -> !Int -> !(Maybe Comparator) -> !Compression -> !Bool -> !Bool -> !Int -> !Bool -> !Int -> !(Maybe (Either BloomFilter FilterPolicy)) -> Options
+ Database.LevelDB.Base: Put :: ByteString -> ByteString -> BatchOp
+ Database.LevelDB.Base: ReadOptions :: !Bool -> !Bool -> !(Maybe Snapshot) -> ReadOptions
+ Database.LevelDB.Base: SSTables :: Property
+ Database.LevelDB.Base: Snappy :: Compression
+ Database.LevelDB.Base: Stats :: Property
+ Database.LevelDB.Base: WriteOptions :: !Bool -> WriteOptions
+ Database.LevelDB.Base: approximateSize :: MonadIO m => DB -> Range -> m Int64
+ Database.LevelDB.Base: blockRestartInterval :: Options -> !Int
+ Database.LevelDB.Base: blockSize :: Options -> !Int
+ Database.LevelDB.Base: cacheSize :: Options -> !Int
+ Database.LevelDB.Base: close :: MonadIO m => DB -> m ()
+ Database.LevelDB.Base: comparator :: Options -> !(Maybe Comparator)
+ Database.LevelDB.Base: compression :: Options -> !Compression
+ Database.LevelDB.Base: createBloomFilter :: MonadIO m => Int -> m BloomFilter
+ Database.LevelDB.Base: createFilter :: FilterPolicy -> [ByteString] -> ByteString
+ Database.LevelDB.Base: createIfMissing :: Options -> !Bool
+ Database.LevelDB.Base: createSnapshot :: MonadIO m => DB -> m Snapshot
+ Database.LevelDB.Base: data BatchOp
+ Database.LevelDB.Base: data BloomFilter
+ Database.LevelDB.Base: data Compression
+ Database.LevelDB.Base: data DB
+ Database.LevelDB.Base: data FilterPolicy
+ Database.LevelDB.Base: data Options
+ Database.LevelDB.Base: data Property
+ Database.LevelDB.Base: data ReadOptions
+ Database.LevelDB.Base: data Snapshot
+ Database.LevelDB.Base: data WriteOptions
+ Database.LevelDB.Base: defaultOptions :: Options
+ Database.LevelDB.Base: defaultReadOptions :: ReadOptions
+ Database.LevelDB.Base: defaultWriteOptions :: WriteOptions
+ Database.LevelDB.Base: delete :: MonadIO m => DB -> WriteOptions -> ByteString -> m ()
+ Database.LevelDB.Base: destroy :: MonadIO m => FilePath -> Options -> m ()
+ Database.LevelDB.Base: errorIfExists :: Options -> !Bool
+ Database.LevelDB.Base: fillCache :: ReadOptions -> !Bool
+ Database.LevelDB.Base: filterPolicy :: Options -> !(Maybe (Either BloomFilter FilterPolicy))
+ Database.LevelDB.Base: fpName :: FilterPolicy -> String
+ Database.LevelDB.Base: get :: MonadIO m => DB -> ReadOptions -> ByteString -> m (Maybe ByteString)
+ Database.LevelDB.Base: getProperty :: MonadIO m => DB -> Property -> m (Maybe ByteString)
+ Database.LevelDB.Base: keyMayMatch :: FilterPolicy -> ByteString -> ByteString -> Bool
+ Database.LevelDB.Base: maxOpenFiles :: Options -> !Int
+ Database.LevelDB.Base: newtype Comparator
+ Database.LevelDB.Base: open :: MonadIO m => FilePath -> Options -> m DB
+ Database.LevelDB.Base: paranoidChecks :: Options -> !Bool
+ Database.LevelDB.Base: put :: MonadIO m => DB -> WriteOptions -> ByteString -> ByteString -> m ()
+ Database.LevelDB.Base: releaseBloomFilter :: MonadIO m => BloomFilter -> m ()
+ Database.LevelDB.Base: releaseSnapshot :: MonadIO m => DB -> Snapshot -> m ()
+ Database.LevelDB.Base: repair :: MonadIO m => FilePath -> Options -> m ()
+ Database.LevelDB.Base: sync :: WriteOptions -> !Bool
+ Database.LevelDB.Base: type Range = (ByteString, ByteString)
+ Database.LevelDB.Base: type WriteBatch = [BatchOp]
+ Database.LevelDB.Base: useSnapshot :: ReadOptions -> !(Maybe Snapshot)
+ Database.LevelDB.Base: verifyCheckSums :: ReadOptions -> !Bool
+ Database.LevelDB.Base: version :: MonadIO m => m (Int, Int)
+ Database.LevelDB.Base: withSnapshot :: MonadIO m => DB -> (Snapshot -> IO a) -> m a
+ Database.LevelDB.Base: write :: MonadIO m => DB -> WriteOptions -> WriteBatch -> m ()
+ Database.LevelDB.Base: writeBufferSize :: Options -> !Int
+ Database.LevelDB.C: CompressionOpt :: CInt -> CompressionOpt
+ Database.LevelDB.C: c_leveldb_approximate_sizes :: LevelDBPtr -> CInt -> Ptr CString -> Ptr CSize -> Ptr CString -> Ptr CSize -> Ptr Word64 -> IO ()
+ Database.LevelDB.C: c_leveldb_cache_create_lru :: CSize -> IO CachePtr
+ Database.LevelDB.C: c_leveldb_cache_destroy :: CachePtr -> IO ()
+ Database.LevelDB.C: c_leveldb_close :: LevelDBPtr -> IO ()
+ Database.LevelDB.C: c_leveldb_comparator_create :: StatePtr -> FunPtr Destructor -> FunPtr CompareFun -> FunPtr NameFun -> IO ComparatorPtr
+ Database.LevelDB.C: c_leveldb_comparator_destroy :: ComparatorPtr -> IO ()
+ Database.LevelDB.C: c_leveldb_create_iterator :: LevelDBPtr -> ReadOptionsPtr -> IO IteratorPtr
+ Database.LevelDB.C: c_leveldb_create_snapshot :: LevelDBPtr -> IO SnapshotPtr
+ Database.LevelDB.C: c_leveldb_delete :: LevelDBPtr -> WriteOptionsPtr -> Key -> CSize -> ErrPtr -> IO ()
+ Database.LevelDB.C: c_leveldb_destroy_db :: OptionsPtr -> DBName -> ErrPtr -> IO ()
+ Database.LevelDB.C: c_leveldb_filterpolicy_create :: StatePtr -> FunPtr Destructor -> FunPtr CreateFilterFun -> FunPtr KeyMayMatchFun -> FunPtr NameFun -> IO FilterPolicyPtr
+ Database.LevelDB.C: c_leveldb_filterpolicy_create_bloom :: CInt -> IO FilterPolicyPtr
+ Database.LevelDB.C: c_leveldb_filterpolicy_destroy :: FilterPolicyPtr -> IO ()
+ Database.LevelDB.C: c_leveldb_get :: LevelDBPtr -> ReadOptionsPtr -> Key -> CSize -> Ptr CSize -> ErrPtr -> IO CString
+ Database.LevelDB.C: c_leveldb_iter_destroy :: IteratorPtr -> IO ()
+ Database.LevelDB.C: c_leveldb_iter_get_error :: IteratorPtr -> ErrPtr -> IO ()
+ Database.LevelDB.C: c_leveldb_iter_key :: IteratorPtr -> Ptr CSize -> IO Key
+ Database.LevelDB.C: c_leveldb_iter_next :: IteratorPtr -> IO ()
+ Database.LevelDB.C: c_leveldb_iter_prev :: IteratorPtr -> IO ()
+ Database.LevelDB.C: c_leveldb_iter_seek :: IteratorPtr -> Key -> CSize -> IO ()
+ Database.LevelDB.C: c_leveldb_iter_seek_to_first :: IteratorPtr -> IO ()
+ Database.LevelDB.C: c_leveldb_iter_seek_to_last :: IteratorPtr -> IO ()
+ Database.LevelDB.C: c_leveldb_iter_valid :: IteratorPtr -> IO CUChar
+ Database.LevelDB.C: c_leveldb_iter_value :: IteratorPtr -> Ptr CSize -> IO Val
+ Database.LevelDB.C: c_leveldb_major_version :: IO CInt
+ Database.LevelDB.C: c_leveldb_minor_version :: IO CInt
+ Database.LevelDB.C: c_leveldb_open :: OptionsPtr -> DBName -> ErrPtr -> IO LevelDBPtr
+ Database.LevelDB.C: c_leveldb_options_create :: IO OptionsPtr
+ Database.LevelDB.C: c_leveldb_options_destroy :: OptionsPtr -> IO ()
+ Database.LevelDB.C: c_leveldb_options_set_block_restart_interval :: OptionsPtr -> CInt -> IO ()
+ Database.LevelDB.C: c_leveldb_options_set_block_size :: OptionsPtr -> CSize -> IO ()
+ Database.LevelDB.C: c_leveldb_options_set_cache :: OptionsPtr -> CachePtr -> IO ()
+ Database.LevelDB.C: c_leveldb_options_set_comparator :: OptionsPtr -> ComparatorPtr -> IO ()
+ Database.LevelDB.C: c_leveldb_options_set_compression :: OptionsPtr -> CompressionOpt -> IO ()
+ Database.LevelDB.C: c_leveldb_options_set_create_if_missing :: OptionsPtr -> CUChar -> IO ()
+ Database.LevelDB.C: c_leveldb_options_set_error_if_exists :: OptionsPtr -> CUChar -> IO ()
+ Database.LevelDB.C: c_leveldb_options_set_filter_policy :: OptionsPtr -> FilterPolicyPtr -> IO ()
+ Database.LevelDB.C: c_leveldb_options_set_info_log :: OptionsPtr -> LoggerPtr -> IO ()
+ Database.LevelDB.C: c_leveldb_options_set_max_open_files :: OptionsPtr -> CInt -> IO ()
+ Database.LevelDB.C: c_leveldb_options_set_paranoid_checks :: OptionsPtr -> CUChar -> IO ()
+ Database.LevelDB.C: c_leveldb_options_set_write_buffer_size :: OptionsPtr -> CSize -> IO ()
+ Database.LevelDB.C: c_leveldb_property_value :: LevelDBPtr -> CString -> IO CString
+ Database.LevelDB.C: c_leveldb_put :: LevelDBPtr -> WriteOptionsPtr -> Key -> CSize -> Val -> CSize -> ErrPtr -> IO ()
+ Database.LevelDB.C: c_leveldb_readoptions_create :: IO ReadOptionsPtr
+ Database.LevelDB.C: c_leveldb_readoptions_destroy :: ReadOptionsPtr -> IO ()
+ Database.LevelDB.C: c_leveldb_readoptions_set_fill_cache :: ReadOptionsPtr -> CUChar -> IO ()
+ Database.LevelDB.C: c_leveldb_readoptions_set_snapshot :: ReadOptionsPtr -> SnapshotPtr -> IO ()
+ Database.LevelDB.C: c_leveldb_readoptions_set_verify_checksums :: ReadOptionsPtr -> CUChar -> IO ()
+ Database.LevelDB.C: c_leveldb_release_snapshot :: LevelDBPtr -> SnapshotPtr -> IO ()
+ Database.LevelDB.C: c_leveldb_repair_db :: OptionsPtr -> DBName -> ErrPtr -> IO ()
+ Database.LevelDB.C: c_leveldb_write :: LevelDBPtr -> WriteOptionsPtr -> WriteBatchPtr -> ErrPtr -> IO ()
+ Database.LevelDB.C: c_leveldb_writebatch_clear :: WriteBatchPtr -> IO ()
+ Database.LevelDB.C: c_leveldb_writebatch_create :: IO WriteBatchPtr
+ Database.LevelDB.C: c_leveldb_writebatch_delete :: WriteBatchPtr -> Key -> CSize -> IO ()
+ Database.LevelDB.C: c_leveldb_writebatch_destroy :: WriteBatchPtr -> IO ()
+ Database.LevelDB.C: c_leveldb_writebatch_iterate :: WriteBatchPtr -> Ptr () -> FunPtr (Ptr () -> Key -> CSize -> Val -> CSize) -> FunPtr (Ptr () -> Key -> CSize) -> IO ()
+ Database.LevelDB.C: c_leveldb_writebatch_put :: WriteBatchPtr -> Key -> CSize -> Val -> CSize -> IO ()
+ Database.LevelDB.C: c_leveldb_writeoptions_create :: IO WriteOptionsPtr
+ Database.LevelDB.C: c_leveldb_writeoptions_destroy :: WriteOptionsPtr -> IO ()
+ Database.LevelDB.C: c_leveldb_writeoptions_set_sync :: WriteOptionsPtr -> CUChar -> IO ()
+ Database.LevelDB.C: compressionOpt :: CompressionOpt -> CInt
+ Database.LevelDB.C: data LCache
+ Database.LevelDB.C: data LComparator
+ Database.LevelDB.C: data LFilterPolicy
+ Database.LevelDB.C: data LIterator
+ Database.LevelDB.C: data LLogger
+ Database.LevelDB.C: data LOptions
+ Database.LevelDB.C: data LReadOptions
+ Database.LevelDB.C: data LSnapshot
+ Database.LevelDB.C: data LWriteBatch
+ Database.LevelDB.C: data LWriteOptions
+ Database.LevelDB.C: data LevelDB
+ Database.LevelDB.C: instance Eq CompressionOpt
+ Database.LevelDB.C: instance Show CompressionOpt
+ Database.LevelDB.C: mkCF :: CreateFilterFun -> IO (FunPtr CreateFilterFun)
+ Database.LevelDB.C: mkCmp :: CompareFun -> IO (FunPtr CompareFun)
+ Database.LevelDB.C: mkDest :: Destructor -> IO (FunPtr Destructor)
+ Database.LevelDB.C: mkKMM :: KeyMayMatchFun -> IO (FunPtr KeyMayMatchFun)
+ Database.LevelDB.C: mkName :: NameFun -> IO (FunPtr NameFun)
+ Database.LevelDB.C: newtype CompressionOpt
+ Database.LevelDB.C: noCompression :: CompressionOpt
+ Database.LevelDB.C: snappyCompression :: CompressionOpt
+ Database.LevelDB.C: type CachePtr = Ptr LCache
+ Database.LevelDB.C: type ComparatorPtr = Ptr LComparator
+ Database.LevelDB.C: type CompareFun = StatePtr -> CString -> CSize -> CString -> CSize -> IO CInt
+ Database.LevelDB.C: type CreateFilterFun = StatePtr -> Ptr CString -> Ptr CSize -> CInt -> Ptr CSize -> IO CString
+ Database.LevelDB.C: type DBName = CString
+ Database.LevelDB.C: type Destructor = StatePtr -> ()
+ Database.LevelDB.C: type ErrPtr = Ptr CString
+ Database.LevelDB.C: type FilterPolicyPtr = Ptr LFilterPolicy
+ Database.LevelDB.C: type IteratorPtr = Ptr LIterator
+ Database.LevelDB.C: type Key = CString
+ Database.LevelDB.C: type KeyMayMatchFun = StatePtr -> CString -> CSize -> CString -> CSize -> IO CUChar
+ Database.LevelDB.C: type LevelDBPtr = Ptr LevelDB
+ Database.LevelDB.C: type LoggerPtr = Ptr LLogger
+ Database.LevelDB.C: type NameFun = StatePtr -> CString
+ Database.LevelDB.C: type OptionsPtr = Ptr LOptions
+ Database.LevelDB.C: type ReadOptionsPtr = Ptr LReadOptions
+ Database.LevelDB.C: type SnapshotPtr = Ptr LSnapshot
+ Database.LevelDB.C: type StatePtr = Ptr ()
+ Database.LevelDB.C: type Val = CString
+ Database.LevelDB.C: type WriteBatchPtr = Ptr LWriteBatch
+ Database.LevelDB.C: type WriteOptionsPtr = Ptr LWriteOptions
+ Database.LevelDB.Internal: DB :: LevelDBPtr -> Options' -> DB
+ Database.LevelDB.Internal: Options' :: !OptionsPtr -> !(Maybe CachePtr) -> !(Maybe Comparator') -> !(Maybe (Either FilterPolicyPtr FilterPolicy')) -> Options'
+ Database.LevelDB.Internal: _cachePtr :: Options' -> !(Maybe CachePtr)
+ Database.LevelDB.Internal: _comp :: Options' -> !(Maybe Comparator')
+ Database.LevelDB.Internal: _fpPtr :: Options' -> !(Maybe (Either FilterPolicyPtr FilterPolicy'))
+ Database.LevelDB.Internal: _optsPtr :: Options' -> !OptionsPtr
+ Database.LevelDB.Internal: boolToNum :: Num b => Bool -> b
+ Database.LevelDB.Internal: cIntToInt :: CInt -> Int
+ Database.LevelDB.Internal: cSizeToInt :: CSize -> Int
+ Database.LevelDB.Internal: data Comparator'
+ Database.LevelDB.Internal: data DB
+ Database.LevelDB.Internal: data FilterPolicy'
+ Database.LevelDB.Internal: data Options'
+ Database.LevelDB.Internal: freeCReadOpts :: ReadOptionsPtr -> IO ()
+ Database.LevelDB.Internal: freeComparator :: Comparator' -> IO ()
+ Database.LevelDB.Internal: freeFilterPolicy :: FilterPolicy' -> IO ()
+ Database.LevelDB.Internal: freeOpts :: Options' -> IO ()
+ Database.LevelDB.Internal: instance Eq DB
+ Database.LevelDB.Internal: intToCInt :: Int -> CInt
+ Database.LevelDB.Internal: intToCSize :: Int -> CSize
+ Database.LevelDB.Internal: mkCReadOpts :: ReadOptions -> IO ReadOptionsPtr
+ Database.LevelDB.Internal: mkComparator :: String -> (ByteString -> ByteString -> Ordering) -> IO Comparator'
+ Database.LevelDB.Internal: mkCompareFun :: (ByteString -> ByteString -> Ordering) -> CompareFun
+ Database.LevelDB.Internal: mkCreateFilterFun :: ([ByteString] -> ByteString) -> CreateFilterFun
+ Database.LevelDB.Internal: mkFilterPolicy :: FilterPolicy -> IO FilterPolicy'
+ Database.LevelDB.Internal: mkKeyMayMatchFun :: (ByteString -> ByteString -> Bool) -> KeyMayMatchFun
+ Database.LevelDB.Internal: mkOpts :: Options -> IO Options'
+ Database.LevelDB.Internal: throwIfErr :: String -> (ErrPtr -> IO a) -> IO a
+ Database.LevelDB.Internal: withCReadOpts :: ReadOptions -> (ReadOptionsPtr -> IO a) -> IO a
+ Database.LevelDB.Internal: withCWriteOpts :: WriteOptions -> (WriteOptionsPtr -> IO a) -> IO a
+ Database.LevelDB.Iterator: createIter :: MonadIO m => DB -> ReadOptions -> m Iterator
+ Database.LevelDB.Iterator: data Iterator
+ Database.LevelDB.Iterator: instance Eq Iterator
+ Database.LevelDB.Iterator: iterEntry :: MonadIO m => Iterator -> m (Maybe (ByteString, ByteString))
+ Database.LevelDB.Iterator: iterFirst :: MonadIO m => Iterator -> m ()
+ Database.LevelDB.Iterator: iterGetError :: MonadIO m => Iterator -> m (Maybe ByteString)
+ Database.LevelDB.Iterator: iterItems :: (Functor m, MonadIO m) => Iterator -> m [(ByteString, ByteString)]
+ Database.LevelDB.Iterator: iterKey :: MonadIO m => Iterator -> m (Maybe ByteString)
+ Database.LevelDB.Iterator: iterKeys :: (Functor m, MonadIO m) => Iterator -> m [ByteString]
+ Database.LevelDB.Iterator: iterLast :: MonadIO m => Iterator -> m ()
+ Database.LevelDB.Iterator: iterNext :: MonadIO m => Iterator -> m ()
+ Database.LevelDB.Iterator: iterPrev :: MonadIO m => Iterator -> m ()
+ Database.LevelDB.Iterator: iterSeek :: MonadIO m => Iterator -> ByteString -> m ()
+ Database.LevelDB.Iterator: iterValid :: MonadIO m => Iterator -> m Bool
+ Database.LevelDB.Iterator: iterValue :: MonadIO m => Iterator -> m (Maybe ByteString)
+ Database.LevelDB.Iterator: iterValues :: (Functor m, MonadIO m) => Iterator -> m [ByteString]
+ Database.LevelDB.Iterator: mapIter :: MonadIO m => (Iterator -> m a) -> Iterator -> m [a]
+ Database.LevelDB.Iterator: releaseIter :: MonadIO m => Iterator -> m ()
+ Database.LevelDB.Iterator: withIter :: MonadIO m => DB -> ReadOptions -> (Iterator -> IO a) -> m a
+ Database.LevelDB.MonadResource: Comparator :: (ByteString -> ByteString -> Ordering) -> Comparator
+ Database.LevelDB.MonadResource: Del :: ByteString -> BatchOp
+ Database.LevelDB.MonadResource: FilterPolicy :: String -> ([ByteString] -> ByteString) -> (ByteString -> ByteString -> Bool) -> FilterPolicy
+ Database.LevelDB.MonadResource: NoCompression :: Compression
+ Database.LevelDB.MonadResource: NumFilesAtLevel :: Int -> Property
+ Database.LevelDB.MonadResource: Options :: !Int -> !Int -> !Int -> !(Maybe Comparator) -> !Compression -> !Bool -> !Bool -> !Int -> !Bool -> !Int -> !(Maybe (Either BloomFilter FilterPolicy)) -> Options
+ Database.LevelDB.MonadResource: Put :: ByteString -> ByteString -> BatchOp
+ Database.LevelDB.MonadResource: ReadOptions :: !Bool -> !Bool -> !(Maybe Snapshot) -> ReadOptions
+ Database.LevelDB.MonadResource: SSTables :: Property
+ Database.LevelDB.MonadResource: Snappy :: Compression
+ Database.LevelDB.MonadResource: Stats :: Property
+ Database.LevelDB.MonadResource: WriteOptions :: !Bool -> WriteOptions
+ Database.LevelDB.MonadResource: approximateSize :: MonadResource m => DB -> Range -> m Int64
+ Database.LevelDB.MonadResource: blockRestartInterval :: Options -> !Int
+ Database.LevelDB.MonadResource: blockSize :: Options -> !Int
+ Database.LevelDB.MonadResource: bloomFilter :: MonadResource m => Int -> m BloomFilter
+ Database.LevelDB.MonadResource: cacheSize :: Options -> !Int
+ Database.LevelDB.MonadResource: class (MonadThrow m, MonadIO m, Applicative m, MonadBase IO m) => MonadResource (m :: * -> *)
+ Database.LevelDB.MonadResource: comparator :: Options -> !(Maybe Comparator)
+ Database.LevelDB.MonadResource: compression :: Options -> !Compression
+ Database.LevelDB.MonadResource: createFilter :: FilterPolicy -> [ByteString] -> ByteString
+ Database.LevelDB.MonadResource: createIfMissing :: Options -> !Bool
+ Database.LevelDB.MonadResource: createSnapshot :: MonadResource m => DB -> m Snapshot
+ Database.LevelDB.MonadResource: createSnapshot' :: MonadResource m => DB -> m (ReleaseKey, Snapshot)
+ Database.LevelDB.MonadResource: data BatchOp
+ Database.LevelDB.MonadResource: data Compression
+ Database.LevelDB.MonadResource: data DB
+ Database.LevelDB.MonadResource: data FilterPolicy
+ Database.LevelDB.MonadResource: data Iterator
+ Database.LevelDB.MonadResource: data Options
+ Database.LevelDB.MonadResource: data Property
+ Database.LevelDB.MonadResource: data ReadOptions
+ Database.LevelDB.MonadResource: data Snapshot
+ Database.LevelDB.MonadResource: data WriteOptions
+ Database.LevelDB.MonadResource: defaultOptions :: Options
+ Database.LevelDB.MonadResource: defaultReadOptions :: ReadOptions
+ Database.LevelDB.MonadResource: defaultWriteOptions :: WriteOptions
+ Database.LevelDB.MonadResource: delete :: MonadResource m => DB -> WriteOptions -> ByteString -> m ()
+ Database.LevelDB.MonadResource: destroy :: MonadResource m => FilePath -> Options -> m ()
+ Database.LevelDB.MonadResource: errorIfExists :: Options -> !Bool
+ Database.LevelDB.MonadResource: fillCache :: ReadOptions -> !Bool
+ Database.LevelDB.MonadResource: filterPolicy :: Options -> !(Maybe (Either BloomFilter FilterPolicy))
+ Database.LevelDB.MonadResource: fpName :: FilterPolicy -> String
+ Database.LevelDB.MonadResource: get :: MonadResource m => DB -> ReadOptions -> ByteString -> m (Maybe ByteString)
+ Database.LevelDB.MonadResource: getProperty :: MonadResource m => DB -> Property -> m (Maybe ByteString)
+ Database.LevelDB.MonadResource: iterFirst :: MonadResource m => Iterator -> m ()
+ Database.LevelDB.MonadResource: iterGetError :: MonadResource m => Iterator -> m (Maybe ByteString)
+ Database.LevelDB.MonadResource: iterItems :: MonadResource m => Iterator -> m [(ByteString, ByteString)]
+ Database.LevelDB.MonadResource: iterKey :: MonadResource m => Iterator -> m (Maybe ByteString)
+ Database.LevelDB.MonadResource: iterKeys :: MonadResource m => Iterator -> m [ByteString]
+ Database.LevelDB.MonadResource: iterLast :: MonadResource m => Iterator -> m ()
+ Database.LevelDB.MonadResource: iterNext :: MonadResource m => Iterator -> m ()
+ Database.LevelDB.MonadResource: iterOpen :: MonadResource m => DB -> ReadOptions -> m Iterator
+ Database.LevelDB.MonadResource: iterOpen' :: MonadResource m => DB -> ReadOptions -> m (ReleaseKey, Iterator)
+ Database.LevelDB.MonadResource: iterPrev :: MonadResource m => Iterator -> m ()
+ Database.LevelDB.MonadResource: iterSeek :: MonadResource m => Iterator -> ByteString -> m ()
+ Database.LevelDB.MonadResource: iterValid :: MonadResource m => Iterator -> m Bool
+ Database.LevelDB.MonadResource: iterValue :: MonadResource m => Iterator -> m (Maybe ByteString)
+ Database.LevelDB.MonadResource: iterValues :: MonadResource m => Iterator -> m [ByteString]
+ Database.LevelDB.MonadResource: keyMayMatch :: FilterPolicy -> ByteString -> ByteString -> Bool
+ Database.LevelDB.MonadResource: liftResourceT :: MonadResource m => ResourceT IO a -> m a
+ Database.LevelDB.MonadResource: mapIter :: MonadResource m => (Iterator -> m a) -> Iterator -> m [a]
+ Database.LevelDB.MonadResource: maxOpenFiles :: Options -> !Int
+ Database.LevelDB.MonadResource: newtype Comparator
+ Database.LevelDB.MonadResource: open :: MonadResource m => FilePath -> Options -> m DB
+ Database.LevelDB.MonadResource: paranoidChecks :: Options -> !Bool
+ Database.LevelDB.MonadResource: put :: MonadResource m => DB -> WriteOptions -> ByteString -> ByteString -> m ()
+ Database.LevelDB.MonadResource: repair :: MonadResource m => FilePath -> Options -> m ()
+ Database.LevelDB.MonadResource: resourceForkIO :: MonadBaseControl IO m => ResourceT m () -> ResourceT m ThreadId
+ Database.LevelDB.MonadResource: runResourceT :: MonadBaseControl IO m => ResourceT m a -> m a
+ Database.LevelDB.MonadResource: sync :: WriteOptions -> !Bool
+ Database.LevelDB.MonadResource: type Range = (ByteString, ByteString)
+ Database.LevelDB.MonadResource: type WriteBatch = [BatchOp]
+ Database.LevelDB.MonadResource: useSnapshot :: ReadOptions -> !(Maybe Snapshot)
+ Database.LevelDB.MonadResource: verifyCheckSums :: ReadOptions -> !Bool
+ Database.LevelDB.MonadResource: version :: MonadResource m => m (Int, Int)
+ Database.LevelDB.MonadResource: withIterator :: MonadResource m => DB -> ReadOptions -> (Iterator -> m a) -> m a
+ Database.LevelDB.MonadResource: withSnapshot :: MonadResource m => DB -> (Snapshot -> m a) -> m a
+ Database.LevelDB.MonadResource: write :: MonadResource m => DB -> WriteOptions -> WriteBatch -> m ()
+ Database.LevelDB.MonadResource: writeBufferSize :: Options -> !Int
+ Database.LevelDB.Types: BloomFilter :: FilterPolicyPtr -> BloomFilter
+ Database.LevelDB.Types: Comparator :: (ByteString -> ByteString -> Ordering) -> Comparator
+ Database.LevelDB.Types: Del :: ByteString -> BatchOp
+ Database.LevelDB.Types: FilterPolicy :: String -> ([ByteString] -> ByteString) -> (ByteString -> ByteString -> Bool) -> FilterPolicy
+ Database.LevelDB.Types: NoCompression :: Compression
+ Database.LevelDB.Types: NumFilesAtLevel :: Int -> Property
+ Database.LevelDB.Types: Options :: !Int -> !Int -> !Int -> !(Maybe Comparator) -> !Compression -> !Bool -> !Bool -> !Int -> !Bool -> !Int -> !(Maybe (Either BloomFilter FilterPolicy)) -> Options
+ Database.LevelDB.Types: Put :: ByteString -> ByteString -> BatchOp
+ Database.LevelDB.Types: ReadOptions :: !Bool -> !Bool -> !(Maybe Snapshot) -> ReadOptions
+ Database.LevelDB.Types: SSTables :: Property
+ Database.LevelDB.Types: Snappy :: Compression
+ Database.LevelDB.Types: Snapshot :: SnapshotPtr -> Snapshot
+ Database.LevelDB.Types: Stats :: Property
+ Database.LevelDB.Types: WriteOptions :: !Bool -> WriteOptions
+ Database.LevelDB.Types: blockRestartInterval :: Options -> !Int
+ Database.LevelDB.Types: blockSize :: Options -> !Int
+ Database.LevelDB.Types: cacheSize :: Options -> !Int
+ Database.LevelDB.Types: comparator :: Options -> !(Maybe Comparator)
+ Database.LevelDB.Types: compression :: Options -> !Compression
+ Database.LevelDB.Types: createFilter :: FilterPolicy -> [ByteString] -> ByteString
+ Database.LevelDB.Types: createIfMissing :: Options -> !Bool
+ Database.LevelDB.Types: data BatchOp
+ Database.LevelDB.Types: data Compression
+ Database.LevelDB.Types: data FilterPolicy
+ Database.LevelDB.Types: data Options
+ Database.LevelDB.Types: data Property
+ Database.LevelDB.Types: data ReadOptions
+ Database.LevelDB.Types: data WriteOptions
+ Database.LevelDB.Types: defaultOptions :: Options
+ Database.LevelDB.Types: defaultReadOptions :: ReadOptions
+ Database.LevelDB.Types: defaultWriteOptions :: WriteOptions
+ Database.LevelDB.Types: errorIfExists :: Options -> !Bool
+ Database.LevelDB.Types: fillCache :: ReadOptions -> !Bool
+ Database.LevelDB.Types: filterPolicy :: Options -> !(Maybe (Either BloomFilter FilterPolicy))
+ Database.LevelDB.Types: fpName :: FilterPolicy -> String
+ Database.LevelDB.Types: instance Default Options
+ Database.LevelDB.Types: instance Default ReadOptions
+ Database.LevelDB.Types: instance Default WriteOptions
+ Database.LevelDB.Types: instance Eq BatchOp
+ Database.LevelDB.Types: instance Eq Compression
+ Database.LevelDB.Types: instance Eq Property
+ Database.LevelDB.Types: instance Eq ReadOptions
+ Database.LevelDB.Types: instance Eq Snapshot
+ Database.LevelDB.Types: instance Eq WriteOptions
+ Database.LevelDB.Types: instance Show BatchOp
+ Database.LevelDB.Types: instance Show Compression
+ Database.LevelDB.Types: instance Show Property
+ Database.LevelDB.Types: instance Show WriteOptions
+ Database.LevelDB.Types: keyMayMatch :: FilterPolicy -> ByteString -> ByteString -> Bool
+ Database.LevelDB.Types: maxOpenFiles :: Options -> !Int
+ Database.LevelDB.Types: newtype BloomFilter
+ Database.LevelDB.Types: newtype Comparator
+ Database.LevelDB.Types: newtype Snapshot
+ Database.LevelDB.Types: paranoidChecks :: Options -> !Bool
+ Database.LevelDB.Types: sync :: WriteOptions -> !Bool
+ Database.LevelDB.Types: type WriteBatch = [BatchOp]
+ Database.LevelDB.Types: useSnapshot :: ReadOptions -> !(Maybe Snapshot)
+ Database.LevelDB.Types: verifyCheckSums :: ReadOptions -> !Bool
+ Database.LevelDB.Types: writeBufferSize :: Options -> !Int
Files
- AUTHORS +8/−0
- CHANGELOG +28/−0
- Readme.md +6/−0
- examples/comparator.hs +0/−1
- examples/features.hs +18/−18
- examples/giantwrite.hs +0/−26
- examples/iterforkio.hs +36/−0
- leveldb-haskell.cabal +103/−15
- src/Database/LevelDB.hs +3/−932
- src/Database/LevelDB/Base.hs +254/−0
- src/Database/LevelDB/Base.hsc +0/−355
- src/Database/LevelDB/C.hsc +355/−0
- src/Database/LevelDB/Internal.hs +291/−0
- src/Database/LevelDB/Iterator.hs +227/−0
- src/Database/LevelDB/MonadResource.hs +285/−0
- src/Database/LevelDB/Types.hs +217/−0
+ AUTHORS view
@@ -0,0 +1,8 @@+# The following people, listed in alphabetical order, contributed to the+# leveldb-haskell library:++Austin Seipp+Kim Altintop+Michael Lazarev+Nicolas Trangez+Will Moss
+ CHANGELOG view
@@ -0,0 +1,28 @@+[0.3.0]:++* ResourceT is no longer compulsory+++[0.2.0]:++* requires LevelDB v1.7+* support for filter policy (LevelDB v1.5), either custom or using the built-in+ bloom filter implementation+* write batch values no longer require a `memcpy` to be early-finalizer-safe+ (introduced in 0.1.1)+++[0.1.0]:++* memory (foreign pointers) is managed through+ [ResourceT](http://hackage.haskell.org/package/resourcet). Note that this+ requires to lift monadic actions inside the `MonadResource` monad, see the+ examples.+* links against shared library (LevelDB v1.3 or higher)+* LevelDB 1.3 API fully supported (including custom comparators, excluding+ custom environments)+++[0.0.x]:++* experimental releases
Readme.md view
@@ -1,7 +1,13 @@ This library provides Haskell bindings to [LevelDB](http://leveldb.googlecode.com) +[](http://travis-ci.org/kim/leveldb-haskell)+ ## History++Version 0.3.0:++* ResourceT is no longer compulsory Version 0.2.0:
examples/comparator.hs view
@@ -5,7 +5,6 @@ module Main where import Control.Monad.IO.Class (liftIO)-import Data.ByteString.Char8 (take) import Data.Default import Database.LevelDB
examples/features.hs view
@@ -6,10 +6,10 @@ import Control.Monad import Control.Monad.IO.Class (liftIO)+import Control.Monad.Trans.Resource (release) import Data.ByteString.Char8 hiding (take) import Data.Default import Prelude hiding (putStrLn)-import System.FilePath import Database.LevelDB @@ -33,8 +33,7 @@ , Put "c" "three" ] - withIterator db def{useSnapshot = Just snap} $ \iter ->- dumpEntries iter+ withIterator db def{useSnapshot = Just snap} $ \iter -> dumpEntries iter -- early release snapshot release releaseSnap@@ -59,22 +58,23 @@ return () - where- dumpEntries iter = do- iterFirst iter- iterItems iter >>= liftIO . print+ where - printProperty l p = liftIO $ do- putStrLn l- maybe (putStrLn "n/a") putStrLn $ p+ dumpEntries iter = do+ iterFirst iter+ iterItems iter >>= liftIO . print - printVersion = do- v <- versionBS- liftIO . putStrLn $ "LevelDB Version: " `append` v+ printProperty l p = liftIO $ do+ putStrLn l+ maybe (putStrLn "n/a") putStrLn p - versionBS = do- (major, minor) <- version- return $ intToBs major `append` "." `append` intToBs minor+ printVersion = do+ v <- versionBS+ liftIO . putStrLn $ "LevelDB Version: " `append` v - intToBs :: Int -> ByteString- intToBs = pack . show+ versionBS = do+ (major, minor) <- version+ return $ intToBs major `append` "." `append` intToBs minor++ intToBs :: Int -> ByteString+ intToBs = pack . show
− examples/giantwrite.hs
@@ -1,26 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-module Main where--import Control.Monad-import Control.Monad.IO.Class (liftIO)-import Data.Default-import Data.Word-import Prelude hiding (putStrLn)-import System.FilePath--import qualified Data.ByteString as BS-import qualified Data.ByteString.Char8 as BC--import Database.LevelDB-import Debug.Trace---main :: IO ()-main = runResourceT $ do- db <- open "/tmp/giantwrite"- defaultOptions { createIfMissing = True }-- let w x = put db def x x- mapM_ (w . BC.pack . show) [1..100000]-- approximateSize db ("0", "z") >>= liftIO . print
+ examples/iterforkio.hs view
@@ -0,0 +1,36 @@+{-# LANGUAGE OverloadedStrings #-}+{-# OPTIONS_GHC -fno-warn-unused-do-bind #-}++-- |+-- Simplistic demo of 'Iterator' synchronization, using the 'Base" API+--+module Main where++import Control.Concurrent+import Control.Concurrent.Async+import Control.Exception+import Data.Default++import Database.LevelDB.Base++import qualified Data.ByteString.Char8 as BS++main :: IO ()+main = bracket (open "/tmp/leveltest" def{ createIfMissing = True }) close $ \ db -> do++ let xs = [1..100] :: [Int]++ write db def (map (\ x -> Put (BS.pack . show $ x) "") xs)++ bracket (createIter db def) releaseIter $ \ iter -> do+ _ <- iterFirst iter+ lck <- newMVar iter+ es <- mapConcurrently (getEntry lck) xs+ mapM (\ (i,e) -> putStrLn $ "#" ++ show i ++ ": " ++ show e) es++ return ()+ where+ getEntry lck i = withMVar lck $ \ iter -> do+ entry <- iterEntry iter+ iterNext iter+ return (i, entry)
leveldb-haskell.cabal view
@@ -1,21 +1,18 @@ name: leveldb-haskell-version: 0.2.0+version: 0.3.0 synopsis: Haskell bindings to LevelDB homepage: http://github.com/kim/leveldb-haskell bug-reports: http://github.com/kim/leveldb-haskell/issues license: BSD3 license-file: LICENSE-author: Kim Altintop <kim.altintop@gmail.com>- , Austin Seipp <mad.one@gmail.com>- , Michael Lazarev <lazarev.michael@gmail.com>- , Will Moss <wbmoss@gmail.com>+author: Kim Altintop et.al. (see AUTHORS file) maintainer: kim.altintop@gmail.com-copyright: Copyright (c) 2012 The leveldb-haskell Authors+copyright: Copyright (c) 2012-2014 The leveldb-haskell Authors category: Database, FFI stability: Experimental build-type: Simple cabal-version: >=1.10-tested-with: GHC == 7.2.2, GHC == 7.4.1+tested-with: GHC == 7.2.2, GHC == 7.4.1, GHC == 7.6.3 description: From <http://leveldb.googlecode.com>: .@@ -30,34 +27,125 @@ v0.1.0 of this library, LevelDB is no longer bundled and must be installed on the target system (version 1.7 or greater is required). -extra-source-files: Readme.md, examples/*.hs+extra-source-files: Readme.md, AUTHORS, CHANGELOG examples/*.hs source-repository head type: git location: git://github.com/kim/leveldb-haskell.git +Flag Examples+ description: Build examples+ default: False+ manual: True+ library exposed-modules: Database.LevelDB- other-modules: Database.LevelDB.Base+ , Database.LevelDB.Base+ , Database.LevelDB.C+ , Database.LevelDB.Internal+ , Database.LevelDB.Iterator+ , Database.LevelDB.MonadResource+ , Database.LevelDB.Types default-language: Haskell2010- default-extensions:- CPP+ other-extensions: CPP , ForeignFunctionInterface , EmptyDataDecls , RecordWildCards build-depends: base >= 3 && < 5 , bytestring+ , data-default , filepath- , transformers , resourcet > 0.3.2- , data-default+ , transformers - ghc-options: -Wall -O2 -rtsopts- -funbox-strict-fields+ ghc-options: -Wall -rtsopts -funbox-strict-fields ghc-prof-options: -prof -auto-all hs-source-dirs: src extra-libraries: leveldb++executable leveldb-example-comparator+ main-is: comparator.hs++ default-language: Haskell2010++ build-depends: base >= 3 && < 5+ , transformers+ , data-default+ , leveldb-haskell++ ghc-options: -Wall -Werror -O -rtsopts+ ghc-prof-options: -prof -auto-all++ hs-source-dirs: examples++ if flag(Examples)+ buildable: True+ else+ buildable: False++executable leveldb-example-features+ main-is: features.hs++ default-language: Haskell2010++ build-depends: base >= 3 && < 5+ , bytestring+ , transformers+ , resourcet > 0.3.2+ , data-default+ , leveldb-haskell++ ghc-options: -Wall -Werror -O -rtsopts+ ghc-prof-options: -prof -auto-all++ hs-source-dirs: examples++ if flag(Examples)+ buildable: True+ else+ buildable: False++executable leveldb-example-filterpolicy+ main-is: filterpolicy.hs++ default-language: Haskell2010++ build-depends: base >= 3 && < 5+ , transformers+ , data-default+ , leveldb-haskell++ ghc-options: -Wall -Werror -O -rtsopts+ ghc-prof-options: -prof -auto-all++ hs-source-dirs: examples++ if flag(Examples)+ buildable: True+ else+ buildable: False++executable leveldb-example-iterforkio+ main-is: iterforkio.hs++ default-language: Haskell2010++ build-depends: base >= 3 && < 5+ , async+ , bytestring+ , data-default+ , leveldb-haskell++ ghc-options: -Wall -Werror -O -rtsopts+ ghc-prof-options: -prof -auto-all++ hs-source-dirs: examples++ if flag(Examples)+ buildable: True+ else+ buildable: False
src/Database/LevelDB.hs view
@@ -1,7 +1,6 @@-{-# LANGUAGE RecordWildCards #-} -- | -- Module : Database.LevelDB--- Copyright : (c) 2012 Kim Altintop+-- Copyright : (c) 2012-2013 The leveldb-haskell Authors -- License : BSD3 -- Maintainer : kim.altintop@gmail.com -- Stability : experimental@@ -12,934 +11,6 @@ -- The API closely follows the C-API of LevelDB. -- For more information, see: <http://leveldb.googlecode.com> -module Database.LevelDB (- -- * Exported Types- DB- , BatchOp(..)- , Comparator(..)- , Compression(..)- , Options(..)- , ReadOptions(..)- , Snapshot- , WriteBatch- , WriteOptions(..)- , Range-- -- * Defaults- , defaultOptions- , defaultWriteOptions- , defaultReadOptions-- -- * Basic Database Manipulation- , withSnapshot- , open- , put- , delete- , write- , get- , createSnapshot- , createSnapshot'-- -- * Filter Policy / Bloom Filter- , FilterPolicy(..)- , bloomFilter-- -- * Administrative Functions- , Property(..), getProperty- , destroy- , repair- , approximateSize- , version-- -- * Iteration- , Iterator- , withIterator- , iterOpen- , iterOpen'- , iterValid- , iterSeek- , iterFirst- , iterLast- , iterNext- , iterPrev- , iterKey- , iterValue- , iterGetError- , mapIter- , iterItems- , iterKeys- , iterValues-- -- * Re-exports- , MonadResource(..)- , runResourceT- , resourceForkIO-) where--import Control.Applicative ((<$>), (<*>))-import Control.Concurrent (MVar, withMVar, newMVar)-import Control.Exception (throwIO)-import Control.Monad (liftM, when)-import Control.Monad.IO.Class (liftIO)-import Control.Monad.Trans.Resource-import Data.ByteString (ByteString)-import Data.ByteString.Internal (ByteString(..))-import Data.Default-import Data.Maybe (catMaybes)-import Foreign-import Foreign.C.Error (throwErrnoIfNull)-import Foreign.C.String (withCString, peekCString)-import Foreign.C.Types (CSize, CInt)--import Database.LevelDB.Base--import qualified Data.ByteString as BS-import qualified Data.ByteString.Char8 as BC-import qualified Data.ByteString.Unsafe as BU---- import Debug.Trace---- | Database handle-newtype DB = DB LevelDBPtr deriving (Eq)---- | Iterator handle-data Iterator = Iterator- { _iterPtr :: !IteratorPtr- , _iterLock :: !(MVar ())- } deriving (Eq)---- | Snapshot handle-newtype Snapshot = Snapshot SnapshotPtr deriving (Eq)---- | Compression setting-data Compression = NoCompression | Snappy deriving (Eq, Show)---- | User-defined comparator-newtype Comparator = Comparator (ByteString -> ByteString -> Ordering)--data Comparator' = Comparator' (FunPtr CompareFun)- (FunPtr Destructor)- (FunPtr NameFun)- ComparatorPtr---- | User-defined filter policy-data FilterPolicy = FilterPolicy- { fpName :: String- , createFilter :: [ByteString] -> ByteString- , keyMayMatch :: ByteString -> ByteString -> Bool- }--data FilterPolicy' = FilterPolicy' (FunPtr CreateFilterFun)- (FunPtr KeyMayMatchFun)- (FunPtr Destructor)- (FunPtr NameFun)- FilterPolicyPtr---- | Represents the built-in Bloom Filter-newtype BloomFilter = BloomFilter FilterPolicyPtr--bloomFilter :: MonadResource m => Int -> m BloomFilter-bloomFilter i = do- let i' = fromInteger . toInteger $ i- fp_ptr <- snd <$> allocate (c_leveldb_filterpolicy_create_bloom i')- (c_leveldb_filterpolicy_destroy)- return . BloomFilter $ fp_ptr----- | Options when opening a database-data Options = Options- { blockRestartInterval :: !Int- -- ^ Number of keys between restart points for delta encoding of keys.- --- -- This parameter can be changed dynamically. Most clients should leave- -- this parameter alone.- --- -- Default: 16- , blockSize :: !Int- -- ^ Approximate size of user data packed per block.- --- -- Note that the block size specified here corresponds to uncompressed- -- data. The actual size of the unit read from disk may be smaller if- -- compression is enabled.- --- -- This parameter can be changed dynamically.- --- -- Default: 4k- , cacheSize :: !Int- -- ^ Control over blocks (user data is stored in a set of blocks, and a- -- block is the unit of reading from disk).- --- -- If > 0, use the specified cache (in bytes) for blocks. If 0, leveldb- -- will automatically create and use an 8MB internal cache.- --- -- Default: 0- , comparator :: !(Maybe Comparator)- -- ^ Comparator used to defined the order of keys in the table.- --- -- If 'Nothing', the default comparator is used, which uses lexicographic- -- bytes-wise ordering.- --- -- NOTE: the client must ensure that the comparator supplied here has the- -- same name and orders keys /exactly/ the same as the comparator provided- -- to previous open calls on the same DB.- --- -- Default: Nothing- , compression :: !Compression- -- ^ Compress blocks using the specified compression algorithm.- --- -- This parameter can be changed dynamically.- --- -- Default: 'Snappy'- , createIfMissing :: !Bool- -- ^ If true, the database will be created if it is missing.- --- -- Default: False- , errorIfExists :: !Bool- -- ^ It true, an error is raised if the database already exists.- --- -- Default: False- , maxOpenFiles :: !Int- -- ^ Number of open files that can be used by the DB.- --- -- You may need to increase this if your database has a large working set- -- (budget one open file per 2MB of working set).- --- -- Default: 1000- , paranoidChecks :: !Bool- -- ^ If true, the implementation will do aggressive checking of the data- -- it is processing and will stop early if it detects any errors.- --- -- This may have unforeseen ramifications: for example, a corruption of- -- one DB entry may cause a large number of entries to become unreadable- -- or for the entire DB to become unopenable.- --- -- Default: False- , writeBufferSize :: !Int- -- ^ Amount of data to build up in memory (backed by an unsorted log on- -- disk) before converting to a sorted on-disk file.- --- -- Larger values increase performance, especially during bulk loads. Up to- -- to write buffers may be held in memory at the same time, so you may- -- with to adjust this parameter to control memory usage. Also, a larger- -- write buffer will result in a longer recovery time the next time the- -- database is opened.- --- -- Default: 4MB- , filterPolicy :: !(Maybe (Either BloomFilter FilterPolicy))- }--defaultOptions :: Options-defaultOptions = Options- { blockRestartInterval = 16- , blockSize = 4096- , cacheSize = 0- , comparator = Nothing- , compression = Snappy- , createIfMissing = False- , errorIfExists = False- , maxOpenFiles = 1000- , paranoidChecks = False- , writeBufferSize = 4 `shift` 20- , filterPolicy = Nothing- }--instance Default Options where- def = defaultOptions--data Options' = Options'- { _optsPtr :: !OptionsPtr- , _cachePtr :: !(Maybe CachePtr)- , _comp :: !(Maybe Comparator')- , _fpPtr :: !(Maybe (Either FilterPolicyPtr FilterPolicy'))- }---- | Options for write operations-data WriteOptions = WriteOptions- { sync :: !Bool- -- ^ If true, the write will be flushed from the operating system buffer- -- cache (by calling WritableFile::Sync()) before the write is considered- -- complete. If this flag is true, writes will be slower.- --- -- If this flag is false, and the machine crashes, some recent writes may- -- be lost. Note that if it is just the process that crashes (i.e., the- -- machine does not reboot), no writes will be lost even if sync==false.- --- -- In other words, a DB write with sync==false has similar crash semantics- -- as the "write()" system call. A DB write with sync==true has similar- -- crash semantics to a "write()" system call followed by "fsync()".- --- -- Default: False- } deriving (Eq, Show)--defaultWriteOptions :: WriteOptions-defaultWriteOptions = WriteOptions { sync = False }--instance Default WriteOptions where- def = defaultWriteOptions---- | Options for read operations-data ReadOptions = ReadOptions- { verifyCheckSums :: !Bool- -- ^ If true, all data read from underlying storage will be verified- -- against corresponding checksuyms.- --- -- Default: False- , fillCache :: !Bool- -- ^ Should the data read for this iteration be cached in memory? Callers- -- may with to set this field to false for bulk scans.- --- -- Default: True- , useSnapshot :: !(Maybe Snapshot)- -- ^ If 'Just', read as of the supplied snapshot (which must belong to the- -- DB that is being read and which must not have been released). If- -- 'Nothing', use an implicit snapshot of the state at the beginning of- -- this read operation.- --- -- Default: Nothing- } deriving (Eq)--defaultReadOptions :: ReadOptions-defaultReadOptions = ReadOptions- { verifyCheckSums = False- , fillCache = True- , useSnapshot = Nothing- }--instance Default ReadOptions where- def = defaultReadOptions--type WriteBatch = [BatchOp]--- | Batch operation-data BatchOp = Put ByteString ByteString | Del ByteString- deriving (Eq, Show)---- | Properties exposed by LevelDB-data Property = NumFilesAtLevel Int | Stats | SSTables- deriving (Eq, Show)----- | Open a database------ The returned handle will automatically be released when the enclosing--- 'runResourceT' terminates.-open :: MonadResource m => FilePath -> Options -> m DB-open path opts = snd <$> open' path opts--open' :: MonadResource m => FilePath -> Options -> m (ReleaseKey, DB)-open' path opts = do- opts' <- snd <$> allocate (mkOpts opts) freeOpts- allocate (mkDB opts') freeDB-- where- mkDB (Options' opts_ptr _ _ _) =- withCString path $ \path_ptr ->- liftM DB- $ throwIfErr "open"- $ c_leveldb_open opts_ptr path_ptr-- freeDB (DB db_ptr) = c_leveldb_close db_ptr-{-# INLINE open' #-}---- | Run an action with a snapshot of the database.------ The snapshot will be released when the action terminates or throws an--- exception. Note that this function is provided for convenience and does not--- prevent the 'Snapshot' handle to escape. It will, however, be invalid after--- this function returns and should not be used anymore.-withSnapshot :: MonadResource m => DB -> (Snapshot -> m a) -> m a-withSnapshot db f = do- (rk, snap) <- createSnapshot' db- res <- f snap- release rk- return res---- | Create a snapshot of the database.------ The returned 'Snapshot' will be released automatically when the enclosing--- 'runResourceT' terminates. It is recommended to use 'createSnapshot'' instead--- and release the resource manually as soon as possible.-createSnapshot :: MonadResource m => DB -> m Snapshot-createSnapshot db = snd <$> createSnapshot' db---- | Create a snapshot of the database which can (and should) be released early.-createSnapshot' :: MonadResource m => DB -> m (ReleaseKey, Snapshot)-createSnapshot' db = allocate (mkSnap db) (freeSnap db)- where- mkSnap (DB db_ptr) =- Snapshot <$> c_leveldb_create_snapshot db_ptr-- freeSnap (DB db_ptr) (Snapshot snap) =- c_leveldb_release_snapshot db_ptr snap---- | Get a DB property-getProperty :: MonadResource m => DB -> Property -> m (Maybe ByteString)-getProperty (DB db_ptr) p = liftIO $- withCString (prop p) $ \prop_ptr -> do- val_ptr <- c_leveldb_property_value db_ptr prop_ptr- if val_ptr == nullPtr- then return Nothing- else do res <- Just <$> BS.packCString val_ptr- free val_ptr- return res-- where- prop (NumFilesAtLevel i) = "leveldb.num-files-at-level" ++ show i- prop Stats = "leveldb.stats"- prop SSTables = "leveldb.sstables"---- | Destroy the given leveldb database.-destroy :: MonadResource m => FilePath -> Options -> m ()-destroy path opts = do- (rk, opts') <- allocate (mkOpts opts) freeOpts- liftIO $ destroy' opts'- release rk-- where- destroy' (Options' opts_ptr _ _ _) =- withCString path $ \path_ptr ->- throwIfErr "destroy" $ c_leveldb_destroy_db opts_ptr path_ptr---- | Repair the given leveldb database.-repair :: MonadResource m => FilePath -> Options -> m ()-repair path opts = do- (rk, opts') <- allocate (mkOpts opts) freeOpts- liftIO $ repair' opts'- release rk-- where- repair' (Options' opts_ptr _ _ _) =- withCString path $ \path_ptr ->- throwIfErr "repair" $ c_leveldb_repair_db opts_ptr path_ptr---- TODO: support [Range], like C API does-type Range = (ByteString, ByteString)---- | Inspect the approximate sizes of the different levels-approximateSize :: MonadResource m => DB -> Range -> m Int64-approximateSize (DB db_ptr) (from, to) = liftIO $- BU.unsafeUseAsCStringLen from $ \(from_ptr, flen) ->- BU.unsafeUseAsCStringLen to $ \(to_ptr, tlen) ->- withArray [from_ptr] $ \from_ptrs ->- withArray [intToCSize flen] $ \flen_ptrs ->- withArray [to_ptr] $ \to_ptrs ->- withArray [intToCSize tlen] $ \tlen_ptrs ->- allocaArray 1 $ \size_ptrs -> do- c_leveldb_approximate_sizes db_ptr 1- from_ptrs flen_ptrs- to_ptrs tlen_ptrs- size_ptrs- liftM head $ peekArray 1 size_ptrs >>= mapM toInt64-- where- toInt64 = return . fromIntegral---- | Write a key/value pair-put :: MonadResource m => DB -> WriteOptions -> ByteString -> ByteString -> m ()-put (DB db_ptr) opts key value = do- (rk, opts_ptr) <- mkCWriteOpts opts-- liftIO $- BU.unsafeUseAsCStringLen key $ \(key_ptr, klen) ->- BU.unsafeUseAsCStringLen value $ \(val_ptr, vlen) ->- throwIfErr "put"- $ c_leveldb_put db_ptr opts_ptr- key_ptr (intToCSize klen)- val_ptr (intToCSize vlen)-- release rk---- | Read a value by key-get :: MonadResource m => DB -> ReadOptions -> ByteString -> m (Maybe ByteString)-get (DB db_ptr) opts key = do- (rk, opts_ptr) <- mkCReadOptions opts-- res <- liftIO $- BU.unsafeUseAsCStringLen key $ \(key_ptr, klen) ->- alloca $ \vlen_ptr -> do- val_ptr <- throwIfErr "get" $- c_leveldb_get db_ptr opts_ptr key_ptr (intToCSize klen) vlen_ptr- vlen <- peek vlen_ptr- if val_ptr == nullPtr- then return Nothing- else do- res' <- Just <$> BS.packCStringLen (val_ptr, cSizeToInt vlen)- free val_ptr- return res'-- release rk- return res---- | Delete a key/value pair-delete :: MonadResource m => DB -> WriteOptions -> ByteString -> m ()-delete (DB db_ptr) opts key = do- (rk, opts_ptr) <- mkCWriteOpts opts-- liftIO $ BU.unsafeUseAsCStringLen key $ \(key_ptr, klen) ->- throwIfErr "delete"- $ c_leveldb_delete db_ptr opts_ptr key_ptr (intToCSize klen)-- release rk---- | Perform a batch mutation-write :: MonadResource m => DB -> WriteOptions -> WriteBatch -> m ()-write (DB db_ptr) opts batch = do- (rk_opts, opts_ptr) <- mkCWriteOpts opts- (rk_batch, batch_ptr) <- allocate c_leveldb_writebatch_create- c_leveldb_writebatch_destroy-- mapM_ (liftIO . batchAdd batch_ptr) batch-- liftIO- $ throwIfErr "write"- $ c_leveldb_write db_ptr opts_ptr batch_ptr-- -- ensure @ByteString@s (and respective shared @CStringLen@s) aren't GC'ed- -- until here- mapM_ (liftIO . touch) batch-- release rk_opts- release rk_batch-- where- batchAdd batch_ptr (Put key val) =- BU.unsafeUseAsCStringLen key $ \(key_ptr, klen) ->- BU.unsafeUseAsCStringLen val $ \(val_ptr, vlen) ->- c_leveldb_writebatch_put batch_ptr- key_ptr (intToCSize klen)- val_ptr (intToCSize vlen)-- batchAdd batch_ptr (Del key) =- BU.unsafeUseAsCStringLen key $ \(key_ptr, klen) ->- c_leveldb_writebatch_delete batch_ptr key_ptr (intToCSize klen)-- touch (Put (PS p _ _) (PS p' _ _)) = do- touchForeignPtr p- touchForeignPtr p'-- touch (Del (PS p _ _)) = touchForeignPtr p---- | Run an action with an Iterator. The iterator will be closed after the--- action returns or an error is thrown. Thus, the iterator will /not/ be valid--- after this function terminates.-withIterator :: MonadResource m => DB -> ReadOptions -> (Iterator -> m a) -> m a-withIterator db opts f = do- (rk, iter) <- iterOpen' db opts- res <- f iter- release rk- return res---- | Create an 'Iterator'.------ The iterator will be released when the enclosing 'runResourceT' terminates.--- You may consider to use 'iterOpen'' instead and manually release the iterator--- as soon as it is no longer needed (alternatively, use 'withIterator').------ Note that an 'Iterator' creates a snapshot of the database implicitly, so--- updates written after the iterator was created are not visible. You may,--- however, specify an older 'Snapshot' in the 'ReadOptions'.-iterOpen :: MonadResource m => DB -> ReadOptions -> m Iterator-iterOpen db opts = snd <$> iterOpen' db opts---- | Create an 'Iterator' which can be released early.-iterOpen' :: MonadResource m => DB -> ReadOptions -> m (ReleaseKey, Iterator)-iterOpen' db opts = do- (rk, opts_ptr) <- mkCReadOptions opts- iter <- allocate (mkIter db opts_ptr) freeIter-- release rk- return iter-- where- mkIter (DB db_ptr) opts_ptr = do- lock <- liftIO $ newMVar ()- it_ptr <- liftIO- $ throwErrnoIfNull "create_iterator"- $ c_leveldb_create_iterator db_ptr opts_ptr- return $ Iterator it_ptr lock-- freeIter (Iterator iter lck) =- withMVar lck (\_ -> c_leveldb_iter_destroy iter)---- | An iterator is either positioned at a key/value pair, or not valid. This--- function returns /true/ iff the iterator is valid.-iterValid :: MonadResource m => Iterator -> m Bool-iterValid (Iterator iter _) = do- x <- liftIO $ c_leveldb_iter_valid iter- return (x /= 0)---- | Position at the first key in the source that is at or past target. The--- iterator is /valid/ after this call iff the source contains an entry that--- comes at or past target.-iterSeek :: MonadResource m => Iterator -> ByteString -> m ()-iterSeek (Iterator iter lck) key = liftIO $ withMVar lck go- where- go _ = BU.unsafeUseAsCStringLen key $ \(key_ptr, klen) ->- c_leveldb_iter_seek iter key_ptr (intToCSize klen)---- | Position at the first key in the source. The iterator is /valid/ after this--- call iff the source is not empty.-iterFirst :: MonadResource m => Iterator -> m ()-iterFirst (Iterator iter lck) = liftIO $ withMVar lck go- where- go _ = c_leveldb_iter_seek_to_first iter---- | Position at the last key in the source. The iterator is /valid/ after this--- call iff the source is not empty.-iterLast :: MonadResource m => Iterator -> m ()-iterLast (Iterator iter lck) = liftIO $ withMVar lck go- where- go _ = c_leveldb_iter_seek_to_last iter---- | Moves to the next entry in the source. After this call, 'iterValid' is--- /true/ iff the iterator was not positioned at the last entry in the source.------ If the iterator is not valid, this function does nothing. Note that this is a--- shortcoming of the C API: an 'iterPrev' might still be possible, but we can't--- determine if we're at the last or first entry.-iterNext :: MonadResource m => Iterator -> m ()-iterNext iter@(Iterator iter_ptr lck) = do- valid <- iterValid iter- when valid $ liftIO $ withMVar lck go-- where- go _ = c_leveldb_iter_next iter_ptr---- | Moves to the previous entry in the source. After this call, 'iterValid' is--- /true/ iff the iterator was not positioned at the first entry in the source.------ If the iterator is not valid, this function does nothing. Note that this is a--- shortcoming of the C API: an 'iterNext' might still be possible, but we can't--- determine if we're at the last or first entry.-iterPrev :: MonadResource m => Iterator -> m ()-iterPrev iter@(Iterator iter_ptr lck) = do- valid <- iterValid iter- when valid $ liftIO $ withMVar lck go-- where- go _ = c_leveldb_iter_prev iter_ptr---- | Return the key for the current entry if the iterator is currently--- positioned at an entry, ie. 'iterValid'.-iterKey :: MonadResource m => Iterator -> m (Maybe ByteString)-iterKey iter = do- valid <- iterValid iter- if not valid- then return Nothing- else iterKey' iter-- where- iterKey' (Iterator iter_ptr _) = liftIO $- alloca $ \len_ptr -> do- key_ptr <- c_leveldb_iter_key iter_ptr len_ptr- if key_ptr == nullPtr- then return Nothing- else do- klen <- peek len_ptr- Just <$> BS.packCStringLen (key_ptr, cSizeToInt klen)---- | Return the value for the current entry if the iterator is currently--- positioned at an entry, ie. 'iterValid'.-iterValue :: MonadResource m => Iterator -> m (Maybe ByteString)-iterValue iter = do- valid <- iterValid iter- if not valid- then return Nothing- else iterValue' iter-- where- iterValue' (Iterator iter_ptr _) = liftIO $- alloca $ \len_ptr -> do- val_ptr <- c_leveldb_iter_value iter_ptr len_ptr- if val_ptr == nullPtr- then return Nothing- else do- vlen <- peek len_ptr- Just <$> BS.packCStringLen (val_ptr, cSizeToInt vlen)---- | Check for errors------ Note that this captures somewhat severe errors such as a corrupted database.-iterGetError :: MonadResource m => Iterator -> m (Maybe ByteString)-iterGetError (Iterator iter_ptr _) = liftIO $- alloca $ \err_ptr -> do- poke err_ptr nullPtr- c_leveldb_iter_get_error iter_ptr err_ptr- erra <- peek err_ptr- if erra == nullPtr- then return Nothing- else do- err <- peekCString erra- return . Just . BC.pack $ err---- | Map a function over an iterator, advancing the iterator forward and--- returning the value. The iterator should be put in the right position prior--- to calling the function.------ Note that this function accumulates the result strictly, ie. it reads all--- values into memory until the iterator is exhausted. This is most likely not--- what you want for large ranges. You may consider using conduits instead, for--- an example see: <https://gist.github.com/adc8ec348f03483446a5>-mapIter :: MonadResource m => (Iterator -> m a) -> Iterator -> m [a]-mapIter = go []-- where- go acc f iter = do- valid <- iterValid iter- if not valid- then return acc- else do- val <- f iter- _ <- iterNext iter- go (val : acc) f iter---- | Return a list of key and value tuples from an iterator. The iterator--- should be put in the right position prior to calling this with the iterator.------ See strictness remarks on 'mapIter'.-iterItems :: MonadResource m => Iterator -> m [(ByteString, ByteString)]-iterItems iter = catMaybes <$> mapIter iterItems' iter-- where- iterItems' iter' = do- mkey <- iterKey iter'- mval <- iterValue iter'- return $ (,) <$> mkey <*> mval---- | Return a list of key from an iterator. The iterator should be put--- in the right position prior to calling this with the iterator.------ See strictness remarks on 'mapIter'-iterKeys :: MonadResource m => Iterator -> m [ByteString]-iterKeys iter = catMaybes <$> mapIter iterKey iter---- | Return a list of values from an iterator. The iterator should be put--- in the right position prior to calling this with the iterator.------ See strictness remarks on 'mapIter'-iterValues :: MonadResource m => Iterator -> m [ByteString]-iterValues iter = catMaybes <$> mapIter iterValue iter----- | Return the runtime version of the underlying LevelDB library as a (major,--- minor) pair.-version :: MonadResource m => m (Int, Int)-version = do- major <- liftIO c_leveldb_major_version- minor <- liftIO c_leveldb_minor_version-- return (cIntToInt major, cIntToInt minor)------- Internal-----mkOpts :: Options -> IO Options'-mkOpts Options{..} = do- opts_ptr <- c_leveldb_options_create-- c_leveldb_options_set_block_restart_interval opts_ptr- $ intToCInt blockRestartInterval- c_leveldb_options_set_block_size opts_ptr- $ intToCSize blockSize- c_leveldb_options_set_compression opts_ptr- $ ccompression compression- c_leveldb_options_set_create_if_missing opts_ptr- $ boolToNum createIfMissing- c_leveldb_options_set_error_if_exists opts_ptr- $ boolToNum errorIfExists- c_leveldb_options_set_max_open_files opts_ptr- $ intToCInt maxOpenFiles- c_leveldb_options_set_paranoid_checks opts_ptr- $ boolToNum paranoidChecks- c_leveldb_options_set_write_buffer_size opts_ptr- $ intToCSize writeBufferSize-- cache <- maybeSetCache opts_ptr cacheSize- cmp <- maybeSetCmp opts_ptr comparator- fp <- maybeSetFilterPolicy opts_ptr filterPolicy-- return (Options' opts_ptr cache cmp fp)-- where- ccompression NoCompression = noCompression- ccompression Snappy = snappyCompression-- maybeSetCache :: OptionsPtr -> Int -> IO (Maybe CachePtr)- maybeSetCache opts_ptr size =- if size <= 0- then return Nothing- else do- cache_ptr <- c_leveldb_cache_create_lru $ intToCSize size- c_leveldb_options_set_cache opts_ptr cache_ptr- return . Just $ cache_ptr-- maybeSetCmp :: OptionsPtr -> Maybe Comparator -> IO (Maybe Comparator')- maybeSetCmp opts_ptr (Just mcmp) = Just <$> setcmp opts_ptr mcmp- maybeSetCmp _ Nothing = return Nothing-- setcmp :: OptionsPtr -> Comparator -> IO Comparator'- setcmp opts_ptr (Comparator cmp) = do- cmp'@(Comparator' _ _ _ cmp_ptr) <- mkComparator "user-defined" cmp- c_leveldb_options_set_comparator opts_ptr cmp_ptr- return cmp'-- maybeSetFilterPolicy :: OptionsPtr- -> Maybe (Either BloomFilter FilterPolicy)- -> IO (Maybe (Either FilterPolicyPtr FilterPolicy'))- maybeSetFilterPolicy _ Nothing = return Nothing- maybeSetFilterPolicy opts_ptr (Just (Left (BloomFilter bloom_ptr))) = do- c_leveldb_options_set_filter_policy opts_ptr bloom_ptr- return Nothing -- bloom filter is freed automatically- maybeSetFilterPolicy opts_ptr (Just (Right fp)) = do- fp'@(FilterPolicy' _ _ _ _ fp_ptr) <- mkFilterPolicy fp- c_leveldb_options_set_filter_policy opts_ptr fp_ptr- return . Just . Right $ fp'--freeOpts :: Options' -> IO ()-freeOpts (Options' opts_ptr mcache_ptr mcmp_ptr mfp) = do- c_leveldb_options_destroy opts_ptr- maybe (return ()) c_leveldb_cache_destroy mcache_ptr- maybe (return ()) freeComparator mcmp_ptr- maybe (return ())- (either c_leveldb_filterpolicy_destroy freeFilterPolicy)- mfp-- return ()--mkCWriteOpts :: MonadResource m => WriteOptions -> m (ReleaseKey, WriteOptionsPtr)-mkCWriteOpts WriteOptions{..} = do- (rk, opts_ptr) <- allocate c_leveldb_writeoptions_create- c_leveldb_writeoptions_destroy-- liftIO- $ c_leveldb_writeoptions_set_sync opts_ptr- $ boolToNum sync-- return (rk, opts_ptr)--mkCReadOptions:: MonadResource m => ReadOptions -> m (ReleaseKey, ReadOptionsPtr)-mkCReadOptions ReadOptions{..} = do- (rk, opts_ptr) <- allocate c_leveldb_readoptions_create- c_leveldb_readoptions_destroy-- liftIO- $ c_leveldb_readoptions_set_verify_checksums opts_ptr- $ boolToNum verifyCheckSums-- liftIO- $ c_leveldb_readoptions_set_verify_checksums opts_ptr- $ boolToNum fillCache-- maybeSetSnapshot opts_ptr useSnapshot-- return (rk, opts_ptr)-- where- maybeSetSnapshot opts_ptr (Just (Snapshot snap_ptr)) =- liftIO $ c_leveldb_readoptions_set_snapshot opts_ptr snap_ptr-- maybeSetSnapshot _ Nothing = return ()--throwIfErr :: String -> (ErrPtr -> IO a) -> IO a-throwIfErr s f = alloca $ \err_ptr -> do- poke err_ptr nullPtr- res <- f err_ptr- erra <- peek err_ptr- when (erra /= nullPtr) $ do- err <- peekCString erra- throwIO $ userError $ s ++ ": " ++ err- return res--cSizeToInt :: CSize -> Int-cSizeToInt = fromIntegral-{-# INLINE cSizeToInt #-}--intToCSize :: Int -> CSize-intToCSize = fromIntegral-{-# INLINE intToCSize #-}--intToCInt :: Int -> CInt-intToCInt = fromIntegral-{-# INLINE intToCInt #-}--cIntToInt :: CInt -> Int-cIntToInt = fromIntegral-{-# INLINE cIntToInt #-}--boolToNum :: Num b => Bool -> b-boolToNum True = fromIntegral (1 :: Int)-boolToNum False = fromIntegral (0 :: Int)-{-# INLINE boolToNum #-}--mkCompareFun :: (ByteString -> ByteString -> Ordering) -> CompareFun-mkCompareFun cmp = cmp'-- where- cmp' _ a alen b blen = do- a' <- BS.packCStringLen (a, fromInteger . toInteger $ alen)- b' <- BS.packCStringLen (b, fromInteger . toInteger $ blen)- return $ case cmp a' b' of- EQ -> 0- GT -> 1- LT -> -1--mkComparator :: String -> (ByteString -> ByteString -> Ordering) -> IO Comparator'-mkComparator name f =- withCString name $ \cs -> do- ccmpfun <- mkCmp . mkCompareFun $ f- cdest <- mkDest $ \_ -> ()- cname <- mkName $ \_ -> cs- ccmp <- c_leveldb_comparator_create nullPtr cdest ccmpfun cname- return $ Comparator' ccmpfun cdest cname ccmp---freeComparator :: Comparator' -> IO ()-freeComparator (Comparator' ccmpfun cdest cname ccmp) = do- c_leveldb_comparator_destroy ccmp- freeHaskellFunPtr ccmpfun- freeHaskellFunPtr cdest- freeHaskellFunPtr cname--mkCreateFilterFun :: ([ByteString] -> ByteString) -> CreateFilterFun-mkCreateFilterFun f = f'-- where- f' _ ks ks_lens n_ks flen = do- let n_ks' = fromInteger . toInteger $ n_ks- ks' <- peekArray n_ks' ks- ks_lens' <- peekArray n_ks' ks_lens- keys <- mapM bstr (zip ks' ks_lens')- let res = f keys- poke flen (fromIntegral . BS.length $ res)- BS.useAsCString res $ \cstr -> return cstr-- bstr (x,len) = BS.packCStringLen (x, fromInteger . toInteger $ len)--mkKeyMayMatchFun :: (ByteString -> ByteString -> Bool) -> KeyMayMatchFun-mkKeyMayMatchFun g = g'-- where- g' _ k klen f flen = do- k' <- BS.packCStringLen (k, fromInteger . toInteger $ klen)- f' <- BS.packCStringLen (f, fromInteger . toInteger $ flen)- return . boolToNum $ g k' f'---mkFilterPolicy :: FilterPolicy -> IO FilterPolicy'-mkFilterPolicy FilterPolicy{..} =- withCString fpName $ \cs -> do- cname <- mkName $ \_ -> cs- cdest <- mkDest $ \_ -> ()- ccffun <- mkCF . mkCreateFilterFun $ createFilter- ckmfun <- mkKMM . mkKeyMayMatchFun $ keyMayMatch- cfp <- c_leveldb_filterpolicy_create nullPtr cdest ccffun ckmfun cname-- return $ FilterPolicy' ccffun ckmfun cdest cname cfp+module Database.LevelDB (module R) where -freeFilterPolicy :: FilterPolicy' -> IO ()-freeFilterPolicy (FilterPolicy' ccffun ckmfun cdest cname cfp) = do- c_leveldb_filterpolicy_destroy cfp- freeHaskellFunPtr ccffun- freeHaskellFunPtr ckmfun- freeHaskellFunPtr cdest- freeHaskellFunPtr cname+import Database.LevelDB.MonadResource as R
+ src/Database/LevelDB/Base.hs view
@@ -0,0 +1,254 @@+-- |+-- Module : Database.LevelDB.Base+-- Copyright : (c) 2012-2013 The leveldb-haskell Authors+-- License : BSD3+-- Maintainer : kim.altintop@gmail.com+-- Stability : experimental+-- Portability : non-portable+--+-- LevelDB Haskell binding.+--+-- The API closely follows the C-API of LevelDB.+-- For more information, see: <http://leveldb.googlecode.com>++module Database.LevelDB.Base+ ( -- * Exported Types+ DB+ , BatchOp (..)+ , Comparator (..)+ , Compression (..)+ , Options (..)+ , ReadOptions (..)+ , Snapshot+ , WriteBatch+ , WriteOptions (..)+ , Range++ -- * Defaults+ , defaultOptions+ , defaultReadOptions+ , defaultWriteOptions++ -- * Basic Database Manipulations+ , open+ , close+ , put+ , delete+ , write+ , get+ , withSnapshot+ , createSnapshot+ , releaseSnapshot++ -- * Filter Policy / Bloom Filter+ , FilterPolicy (..)+ , BloomFilter+ , createBloomFilter+ , releaseBloomFilter++ -- * Administrative Functions+ , Property (..), getProperty+ , destroy+ , repair+ , approximateSize+ , version++ -- * Iteration+ , module Database.LevelDB.Iterator+ )+where++import Control.Applicative ((<$>))+import Control.Exception (bracket, bracketOnError, finally)+import Control.Monad (liftM)+import Control.Monad.IO.Class (MonadIO (liftIO))+import Data.ByteString (ByteString)+import Data.ByteString.Internal (ByteString (..))+import Foreign+import Foreign.C.String (withCString)++import Database.LevelDB.C+import Database.LevelDB.Internal+import Database.LevelDB.Iterator+import Database.LevelDB.Types++import qualified Data.ByteString as BS+import qualified Data.ByteString.Unsafe as BU+++-- | Open a database.+--+-- The returned handle should be released with 'close'.+open :: MonadIO m => FilePath -> Options -> m DB+open path opts = liftIO $ bracketOnError (mkOpts opts) freeOpts mkDB+ where+ mkDB opts'@(Options' opts_ptr _ _ _) =+ withCString path $ \path_ptr ->+ liftM (`DB` opts')+ $ throwIfErr "open"+ $ c_leveldb_open opts_ptr path_ptr++-- | Close a database.+--+-- The handle will be invalid after calling this action and should no+-- longer be used.+close :: MonadIO m => DB -> m ()+close (DB db_ptr opts_ptr) = liftIO $+ c_leveldb_close db_ptr `finally` freeOpts opts_ptr+++-- | Run an action with a 'Snapshot' of the database.+withSnapshot :: MonadIO m => DB -> (Snapshot -> IO a) -> m a+withSnapshot db act = liftIO $+ bracket (createSnapshot db) (releaseSnapshot db) act++-- | Create a snapshot of the database.+--+-- The returned 'Snapshot' should be released with 'releaseSnapshot'.+createSnapshot :: MonadIO m => DB -> m Snapshot+createSnapshot (DB db_ptr _) = liftIO $+ Snapshot <$> c_leveldb_create_snapshot db_ptr++-- | Release a snapshot.+--+-- The handle will be invalid after calling this action and should no+-- longer be used.+releaseSnapshot :: MonadIO m => DB -> Snapshot -> m ()+releaseSnapshot (DB db_ptr _) (Snapshot snap) = liftIO $+ c_leveldb_release_snapshot db_ptr snap++-- | Get a DB property.+getProperty :: MonadIO m => DB -> Property -> m (Maybe ByteString)+getProperty (DB db_ptr _) p = liftIO $+ withCString (prop p) $ \prop_ptr -> do+ val_ptr <- c_leveldb_property_value db_ptr prop_ptr+ if val_ptr == nullPtr+ then return Nothing+ else do res <- Just <$> BS.packCString val_ptr+ free val_ptr+ return res+ where+ prop (NumFilesAtLevel i) = "leveldb.num-files-at-level" ++ show i+ prop Stats = "leveldb.stats"+ prop SSTables = "leveldb.sstables"++-- | Destroy the given LevelDB database.+destroy :: MonadIO m => FilePath -> Options -> m ()+destroy path opts = liftIO $ bracket (mkOpts opts) freeOpts destroy'+ where+ destroy' (Options' opts_ptr _ _ _) =+ withCString path $ \path_ptr ->+ throwIfErr "destroy" $ c_leveldb_destroy_db opts_ptr path_ptr++-- | Repair the given LevelDB database.+repair :: MonadIO m => FilePath -> Options -> m ()+repair path opts = liftIO $ bracket (mkOpts opts) freeOpts repair'+ where+ repair' (Options' opts_ptr _ _ _) =+ withCString path $ \path_ptr ->+ throwIfErr "repair" $ c_leveldb_repair_db opts_ptr path_ptr+++-- TODO: support [Range], like C API does+type Range = (ByteString, ByteString)++-- | Inspect the approximate sizes of the different levels.+approximateSize :: MonadIO m => DB -> Range -> m Int64+approximateSize (DB db_ptr _) (from, to) = liftIO $+ BU.unsafeUseAsCStringLen from $ \(from_ptr, flen) ->+ BU.unsafeUseAsCStringLen to $ \(to_ptr, tlen) ->+ withArray [from_ptr] $ \from_ptrs ->+ withArray [intToCSize flen] $ \flen_ptrs ->+ withArray [to_ptr] $ \to_ptrs ->+ withArray [intToCSize tlen] $ \tlen_ptrs ->+ allocaArray 1 $ \size_ptrs -> do+ c_leveldb_approximate_sizes db_ptr 1+ from_ptrs flen_ptrs+ to_ptrs tlen_ptrs+ size_ptrs+ liftM head $ peekArray 1 size_ptrs >>= mapM toInt64++ where+ toInt64 = return . fromIntegral+++-- | Write a key/value pair.+put :: MonadIO m => DB -> WriteOptions -> ByteString -> ByteString -> m ()+put (DB db_ptr _) opts key value = liftIO $ withCWriteOpts opts $ \opts_ptr ->+ BU.unsafeUseAsCStringLen key $ \(key_ptr, klen) ->+ BU.unsafeUseAsCStringLen value $ \(val_ptr, vlen) ->+ throwIfErr "put"+ $ c_leveldb_put db_ptr opts_ptr+ key_ptr (intToCSize klen)+ val_ptr (intToCSize vlen)++-- | Read a value by key.+get :: MonadIO m => DB -> ReadOptions -> ByteString -> m (Maybe ByteString)+get (DB db_ptr _) opts key = liftIO $ withCReadOpts opts $ \opts_ptr ->+ BU.unsafeUseAsCStringLen key $ \(key_ptr, klen) ->+ alloca $ \vlen_ptr -> do+ val_ptr <- throwIfErr "get" $+ c_leveldb_get db_ptr opts_ptr key_ptr (intToCSize klen) vlen_ptr+ vlen <- peek vlen_ptr+ if val_ptr == nullPtr+ then return Nothing+ else do+ res' <- Just <$> BS.packCStringLen (val_ptr, cSizeToInt vlen)+ free val_ptr+ return res'++-- | Delete a key/value pair.+delete :: MonadIO m => DB -> WriteOptions -> ByteString -> m ()+delete (DB db_ptr _) opts key = liftIO $ withCWriteOpts opts $ \opts_ptr ->+ BU.unsafeUseAsCStringLen key $ \(key_ptr, klen) ->+ throwIfErr "delete"+ $ c_leveldb_delete db_ptr opts_ptr key_ptr (intToCSize klen)++-- | Perform a batch mutation.+write :: MonadIO m => DB -> WriteOptions -> WriteBatch -> m ()+write (DB db_ptr _) opts batch = liftIO $ withCWriteOpts opts $ \opts_ptr ->+ bracket c_leveldb_writebatch_create c_leveldb_writebatch_destroy $ \batch_ptr -> do++ mapM_ (batchAdd batch_ptr) batch++ throwIfErr "write" $ c_leveldb_write db_ptr opts_ptr batch_ptr++ -- ensure @ByteString@s (and respective shared @CStringLen@s) aren't GC'ed+ -- until here+ mapM_ (liftIO . touch) batch++ where+ batchAdd batch_ptr (Put key val) =+ BU.unsafeUseAsCStringLen key $ \(key_ptr, klen) ->+ BU.unsafeUseAsCStringLen val $ \(val_ptr, vlen) ->+ c_leveldb_writebatch_put batch_ptr+ key_ptr (intToCSize klen)+ val_ptr (intToCSize vlen)++ batchAdd batch_ptr (Del key) =+ BU.unsafeUseAsCStringLen key $ \(key_ptr, klen) ->+ c_leveldb_writebatch_delete batch_ptr key_ptr (intToCSize klen)++ touch (Put (PS p _ _) (PS p' _ _)) = do+ touchForeignPtr p+ touchForeignPtr p'++ touch (Del (PS p _ _)) = touchForeignPtr p++-- | Return the runtime version of the underlying LevelDB library as a (major,+-- minor) pair.+version :: MonadIO m => m (Int, Int)+version = do+ major <- liftIO c_leveldb_major_version+ minor <- liftIO c_leveldb_minor_version++ return (cIntToInt major, cIntToInt minor)++createBloomFilter :: MonadIO m => Int -> m BloomFilter+createBloomFilter i = do+ let i' = fromInteger . toInteger $ i+ fp_ptr <- liftIO $ c_leveldb_filterpolicy_create_bloom i'+ return $ BloomFilter fp_ptr++releaseBloomFilter :: MonadIO m => BloomFilter -> m ()+releaseBloomFilter (BloomFilter fp) = liftIO $ c_leveldb_filterpolicy_destroy fp
− src/Database/LevelDB/Base.hsc
@@ -1,355 +0,0 @@-{-# LANGUAGE CPP, ForeignFunctionInterface, EmptyDataDecls #-}--- |--- Module : Database.LevelDB.Base--- Copyright : (c) 2012 Kim Altintop--- License : BSD3--- Maintainer : kim.altintop@gmail.com--- Stability : experimental--- Portability : non-portable-----module Database.LevelDB.Base where--import Foreign-import Foreign.C.Types-import Foreign.C.String--#include <leveldb/c.h>--data LevelDB-data LCache-data LComparator-data LIterator-data LLogger-data LOptions-data LReadOptions-data LSnapshot-data LWriteBatch-data LWriteOptions-data LFilterPolicy--type LevelDBPtr = Ptr LevelDB-type CachePtr = Ptr LCache-type ComparatorPtr = Ptr LComparator-type IteratorPtr = Ptr LIterator-type LoggerPtr = Ptr LLogger-type OptionsPtr = Ptr LOptions-type ReadOptionsPtr = Ptr LReadOptions-type SnapshotPtr = Ptr LSnapshot-type WriteBatchPtr = Ptr LWriteBatch-type WriteOptionsPtr = Ptr LWriteOptions-type FilterPolicyPtr = Ptr LFilterPolicy--type DBName = CString-type ErrPtr = Ptr CString-type Key = CString-type Val = CString--newtype CompressionOpt = CompressionOpt { compressionOpt :: CInt }- deriving (Eq, Show)-#{enum CompressionOpt, CompressionOpt- , noCompression = 0- , snappyCompression = 1- }---foreign import ccall safe "leveldb/c.h leveldb_open"- c_leveldb_open :: OptionsPtr -> DBName -> ErrPtr -> IO LevelDBPtr--foreign import ccall safe "leveldb/c.h leveldb_close"- c_leveldb_close :: LevelDBPtr -> IO ()---foreign import ccall safe "leveldb/c.h leveldb_put"- c_leveldb_put :: LevelDBPtr- -> WriteOptionsPtr- -> Key -> CSize- -> Val -> CSize- -> ErrPtr- -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_delete"- c_leveldb_delete :: LevelDBPtr- -> WriteOptionsPtr- -> Key -> CSize- -> ErrPtr- -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_write"- c_leveldb_write :: LevelDBPtr- -> WriteOptionsPtr- -> WriteBatchPtr- -> ErrPtr- -> IO ()---- | Returns NULL if not found. A malloc()ed array otherwise. Stores the length--- of the array in *vallen.-foreign import ccall safe "leveldb/c.h leveldb_get"- c_leveldb_get :: LevelDBPtr- -> ReadOptionsPtr- -> Key -> CSize- -> Ptr CSize -- ^ value length- -> ErrPtr- -> IO CString--foreign import ccall safe "leveldb/c.h leveldb_create_snapshot"- c_leveldb_create_snapshot :: LevelDBPtr -> IO SnapshotPtr--foreign import ccall safe "leveldb/c.h leveldb_release_snapshot"- c_leveldb_release_snapshot :: LevelDBPtr -> SnapshotPtr -> IO ()---- | Returns NULL if property name is unknown. Else returns a pointer to a--- malloc()-ed null-terminated value.-foreign import ccall safe "leveldb/c.h leveldb_property_value"- c_leveldb_property_value :: LevelDBPtr -> CString -> IO CString--foreign import ccall safe "leveldb/c.h leveldb_approximate_sizes"- c_leveldb_approximate_sizes :: LevelDBPtr- -> CInt -- ^ num ranges- -> Ptr CString -> Ptr CSize -- ^ range start keys (array)- -> Ptr CString -> Ptr CSize -- ^ range limit keys (array)- -> Ptr Word64 -- ^ array of approx. sizes of ranges- -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_destroy_db"- c_leveldb_destroy_db :: OptionsPtr -> DBName -> ErrPtr -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_repair_db"- c_leveldb_repair_db :: OptionsPtr -> DBName -> ErrPtr -> IO ()-------- Iterator-----foreign import ccall safe "leveldb/c.h leveldb_create_iterator"- c_leveldb_create_iterator :: LevelDBPtr -> ReadOptionsPtr -> IO IteratorPtr--foreign import ccall safe "leveldb/c.h leveldb_iter_destroy"- c_leveldb_iter_destroy :: IteratorPtr -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_iter_valid"- c_leveldb_iter_valid :: IteratorPtr -> IO CUChar--foreign import ccall safe "leveldb/c.h leveldb_iter_seek_to_first"- c_leveldb_iter_seek_to_first :: IteratorPtr -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_iter_seek_to_last"- c_leveldb_iter_seek_to_last :: IteratorPtr -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_iter_seek"- c_leveldb_iter_seek :: IteratorPtr -> Key -> CSize -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_iter_next"- c_leveldb_iter_next :: IteratorPtr -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_iter_prev"- c_leveldb_iter_prev :: IteratorPtr -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_iter_key"- c_leveldb_iter_key :: IteratorPtr -> Ptr CSize -> IO Key--foreign import ccall safe "leveldb/c.h leveldb_iter_value"- c_leveldb_iter_value :: IteratorPtr -> Ptr CSize -> IO Val--foreign import ccall safe "leveldb/c.h leveldb_iter_get_error"- c_leveldb_iter_get_error :: IteratorPtr -> ErrPtr -> IO ()-------- Write batch-----foreign import ccall safe "leveldb/c.h leveldb_writebatch_create"- c_leveldb_writebatch_create :: IO WriteBatchPtr--foreign import ccall safe "leveldb/c.h leveldb_writebatch_destroy"- c_leveldb_writebatch_destroy :: WriteBatchPtr -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_writebatch_clear"- c_leveldb_writebatch_clear :: WriteBatchPtr -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_writebatch_put"- c_leveldb_writebatch_put :: WriteBatchPtr- -> Key -> CSize- -> Val -> CSize- -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_writebatch_delete"- c_leveldb_writebatch_delete :: WriteBatchPtr -> Key -> CSize -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_writebatch_iterate"- c_leveldb_writebatch_iterate :: WriteBatchPtr- -> Ptr () -- ^ state- -> FunPtr (Ptr () -> Key -> CSize -> Val -> CSize) -- ^ put- -> FunPtr (Ptr () -> Key -> CSize) -- ^ delete- -> IO ()-------- Options-----foreign import ccall safe "leveldb/c.h leveldb_options_create"- c_leveldb_options_create :: IO OptionsPtr--foreign import ccall safe "leveldb/c.h leveldb_options_destroy"- c_leveldb_options_destroy :: OptionsPtr -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_options_set_comparator"- c_leveldb_options_set_comparator :: OptionsPtr -> ComparatorPtr -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_options_set_filter_policy"- c_leveldb_options_set_filter_policy :: OptionsPtr -> FilterPolicyPtr -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_options_set_create_if_missing"- c_leveldb_options_set_create_if_missing :: OptionsPtr -> CUChar -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_options_set_error_if_exists"- c_leveldb_options_set_error_if_exists :: OptionsPtr -> CUChar -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_options_set_paranoid_checks"- c_leveldb_options_set_paranoid_checks :: OptionsPtr -> CUChar -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_options_set_info_log"- c_leveldb_options_set_info_log :: OptionsPtr -> LoggerPtr -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_options_set_write_buffer_size"- c_leveldb_options_set_write_buffer_size :: OptionsPtr -> CSize -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_options_set_max_open_files"- c_leveldb_options_set_max_open_files :: OptionsPtr -> CInt -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_options_set_block_size"- c_leveldb_options_set_block_size :: OptionsPtr -> CSize -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_options_set_block_restart_interval"- c_leveldb_options_set_block_restart_interval :: OptionsPtr -> CInt -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_options_set_compression"- c_leveldb_options_set_compression :: OptionsPtr -> CompressionOpt -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_options_set_cache"- c_leveldb_options_set_cache :: OptionsPtr -> CachePtr -> IO ()-------- Comparator-----type StatePtr = Ptr ()-type Destructor = StatePtr -> ()-type CompareFun = StatePtr -> CString -> CSize -> CString -> CSize -> IO CInt-type NameFun = StatePtr -> CString---- | Make a FunPtr to a user-defined comparator function-foreign import ccall "wrapper" mkCmp :: CompareFun -> IO (FunPtr CompareFun)---- | Make a destructor FunPtr-foreign import ccall "wrapper" mkDest :: Destructor -> IO (FunPtr Destructor)---- | Make a name FunPtr-foreign import ccall "wrapper" mkName :: NameFun -> IO (FunPtr NameFun)--foreign import ccall safe "leveldb/c.h leveldb_comparator_create"- c_leveldb_comparator_create :: StatePtr- -> FunPtr Destructor- -> FunPtr CompareFun- -> FunPtr NameFun- -> IO ComparatorPtr--foreign import ccall safe "leveldb/c.h leveldb_comparator_destroy"- c_leveldb_comparator_destroy :: ComparatorPtr -> IO ()-------- Filter Policy-----type CreateFilterFun = StatePtr- -> Ptr CString -- ^ key array- -> Ptr CSize -- ^ key length array- -> CInt -- ^ num keys- -> Ptr CSize -- ^ filter length- -> IO CString -- ^ the filter-type KeyMayMatchFun = StatePtr- -> CString -- ^ key- -> CSize -- ^ key length- -> CString -- ^ filter- -> CSize -- ^ filter length- -> IO CUChar -- ^ whether key is in filter---- | Make a FunPtr to a user-defined create_filter function-foreign import ccall "wrapper" mkCF :: CreateFilterFun -> IO (FunPtr CreateFilterFun)---- | Make a FunPtr to a user-defined key_may_match function-foreign import ccall "wrapper" mkKMM :: KeyMayMatchFun -> IO (FunPtr KeyMayMatchFun)--foreign import ccall safe "leveldb/c.h leveldb_filterpolicy_create"- c_leveldb_filterpolicy_create :: StatePtr- -> FunPtr Destructor- -> FunPtr CreateFilterFun- -> FunPtr KeyMayMatchFun- -> FunPtr NameFun- -> IO FilterPolicyPtr--foreign import ccall safe "leveldb/c.h leveldb_filterpolicy_destroy"- c_leveldb_filterpolicy_destroy :: FilterPolicyPtr -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_filterpolicy_create_bloom"- c_leveldb_filterpolicy_create_bloom :: CInt -> IO FilterPolicyPtr------- Read options-----foreign import ccall safe "leveldb/c.h leveldb_readoptions_create"- c_leveldb_readoptions_create :: IO ReadOptionsPtr--foreign import ccall safe "leveldb/c.h leveldb_readoptions_destroy"- c_leveldb_readoptions_destroy :: ReadOptionsPtr -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_readoptions_set_verify_checksums"- c_leveldb_readoptions_set_verify_checksums :: ReadOptionsPtr -> CUChar -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_readoptions_set_fill_cache"- c_leveldb_readoptions_set_fill_cache :: ReadOptionsPtr -> CUChar -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_readoptions_set_snapshot"- c_leveldb_readoptions_set_snapshot :: ReadOptionsPtr -> SnapshotPtr -> IO ()-------- Write options-----foreign import ccall safe "leveldb/c.h leveldb_writeoptions_create"- c_leveldb_writeoptions_create :: IO WriteOptionsPtr--foreign import ccall safe "leveldb/c.h leveldb_writeoptions_destroy"- c_leveldb_writeoptions_destroy :: WriteOptionsPtr -> IO ()--foreign import ccall safe "leveldb/c.h leveldb_writeoptions_set_sync"- c_leveldb_writeoptions_set_sync :: WriteOptionsPtr -> CUChar -> IO ()-------- Cache-----foreign import ccall safe "leveldb/c.h leveldb_cache_create_lru"- c_leveldb_cache_create_lru :: CSize -> IO CachePtr--foreign import ccall safe "leveldb/c.h leveldb_cache_destroy"- c_leveldb_cache_destroy :: CachePtr -> IO ()-------- Version-----foreign import ccall unsafe "leveldb/c.h leveldb_major_version"- c_leveldb_major_version :: IO CInt--foreign import ccall unsafe "leveldb/c.h leveldb_minor_version"- c_leveldb_minor_version :: IO CInt
+ src/Database/LevelDB/C.hsc view
@@ -0,0 +1,355 @@+{-# LANGUAGE CPP, ForeignFunctionInterface, EmptyDataDecls #-}+-- |+-- Module : Database.LevelDB.C+-- Copyright : (c) 2012-2013 The leveldb-haskell Authors+-- License : BSD3+-- Maintainer : kim.altintop@gmail.com+-- Stability : experimental+-- Portability : non-portable+--++module Database.LevelDB.C where++import Foreign+import Foreign.C.Types+import Foreign.C.String++#include <leveldb/c.h>++data LevelDB+data LCache+data LComparator+data LIterator+data LLogger+data LOptions+data LReadOptions+data LSnapshot+data LWriteBatch+data LWriteOptions+data LFilterPolicy++type LevelDBPtr = Ptr LevelDB+type CachePtr = Ptr LCache+type ComparatorPtr = Ptr LComparator+type IteratorPtr = Ptr LIterator+type LoggerPtr = Ptr LLogger+type OptionsPtr = Ptr LOptions+type ReadOptionsPtr = Ptr LReadOptions+type SnapshotPtr = Ptr LSnapshot+type WriteBatchPtr = Ptr LWriteBatch+type WriteOptionsPtr = Ptr LWriteOptions+type FilterPolicyPtr = Ptr LFilterPolicy++type DBName = CString+type ErrPtr = Ptr CString+type Key = CString+type Val = CString++newtype CompressionOpt = CompressionOpt { compressionOpt :: CInt }+ deriving (Eq, Show)+#{enum CompressionOpt, CompressionOpt+ , noCompression = 0+ , snappyCompression = 1+ }+++foreign import ccall safe "leveldb/c.h leveldb_open"+ c_leveldb_open :: OptionsPtr -> DBName -> ErrPtr -> IO LevelDBPtr++foreign import ccall safe "leveldb/c.h leveldb_close"+ c_leveldb_close :: LevelDBPtr -> IO ()+++foreign import ccall safe "leveldb/c.h leveldb_put"+ c_leveldb_put :: LevelDBPtr+ -> WriteOptionsPtr+ -> Key -> CSize+ -> Val -> CSize+ -> ErrPtr+ -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_delete"+ c_leveldb_delete :: LevelDBPtr+ -> WriteOptionsPtr+ -> Key -> CSize+ -> ErrPtr+ -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_write"+ c_leveldb_write :: LevelDBPtr+ -> WriteOptionsPtr+ -> WriteBatchPtr+ -> ErrPtr+ -> IO ()++-- | Returns NULL if not found. A malloc()ed array otherwise. Stores the length+-- of the array in *vallen.+foreign import ccall safe "leveldb/c.h leveldb_get"+ c_leveldb_get :: LevelDBPtr+ -> ReadOptionsPtr+ -> Key -> CSize+ -> Ptr CSize -- ^ value length+ -> ErrPtr+ -> IO CString++foreign import ccall safe "leveldb/c.h leveldb_create_snapshot"+ c_leveldb_create_snapshot :: LevelDBPtr -> IO SnapshotPtr++foreign import ccall safe "leveldb/c.h leveldb_release_snapshot"+ c_leveldb_release_snapshot :: LevelDBPtr -> SnapshotPtr -> IO ()++-- | Returns NULL if property name is unknown. Else returns a pointer to a+-- malloc()-ed null-terminated value.+foreign import ccall safe "leveldb/c.h leveldb_property_value"+ c_leveldb_property_value :: LevelDBPtr -> CString -> IO CString++foreign import ccall safe "leveldb/c.h leveldb_approximate_sizes"+ c_leveldb_approximate_sizes :: LevelDBPtr+ -> CInt -- ^ num ranges+ -> Ptr CString -> Ptr CSize -- ^ range start keys (array)+ -> Ptr CString -> Ptr CSize -- ^ range limit keys (array)+ -> Ptr Word64 -- ^ array of approx. sizes of ranges+ -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_destroy_db"+ c_leveldb_destroy_db :: OptionsPtr -> DBName -> ErrPtr -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_repair_db"+ c_leveldb_repair_db :: OptionsPtr -> DBName -> ErrPtr -> IO ()+++--+-- Iterator+--++foreign import ccall safe "leveldb/c.h leveldb_create_iterator"+ c_leveldb_create_iterator :: LevelDBPtr -> ReadOptionsPtr -> IO IteratorPtr++foreign import ccall safe "leveldb/c.h leveldb_iter_destroy"+ c_leveldb_iter_destroy :: IteratorPtr -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_iter_valid"+ c_leveldb_iter_valid :: IteratorPtr -> IO CUChar++foreign import ccall safe "leveldb/c.h leveldb_iter_seek_to_first"+ c_leveldb_iter_seek_to_first :: IteratorPtr -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_iter_seek_to_last"+ c_leveldb_iter_seek_to_last :: IteratorPtr -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_iter_seek"+ c_leveldb_iter_seek :: IteratorPtr -> Key -> CSize -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_iter_next"+ c_leveldb_iter_next :: IteratorPtr -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_iter_prev"+ c_leveldb_iter_prev :: IteratorPtr -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_iter_key"+ c_leveldb_iter_key :: IteratorPtr -> Ptr CSize -> IO Key++foreign import ccall safe "leveldb/c.h leveldb_iter_value"+ c_leveldb_iter_value :: IteratorPtr -> Ptr CSize -> IO Val++foreign import ccall safe "leveldb/c.h leveldb_iter_get_error"+ c_leveldb_iter_get_error :: IteratorPtr -> ErrPtr -> IO ()+++--+-- Write batch+--++foreign import ccall safe "leveldb/c.h leveldb_writebatch_create"+ c_leveldb_writebatch_create :: IO WriteBatchPtr++foreign import ccall safe "leveldb/c.h leveldb_writebatch_destroy"+ c_leveldb_writebatch_destroy :: WriteBatchPtr -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_writebatch_clear"+ c_leveldb_writebatch_clear :: WriteBatchPtr -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_writebatch_put"+ c_leveldb_writebatch_put :: WriteBatchPtr+ -> Key -> CSize+ -> Val -> CSize+ -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_writebatch_delete"+ c_leveldb_writebatch_delete :: WriteBatchPtr -> Key -> CSize -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_writebatch_iterate"+ c_leveldb_writebatch_iterate :: WriteBatchPtr+ -> Ptr () -- ^ state+ -> FunPtr (Ptr () -> Key -> CSize -> Val -> CSize) -- ^ put+ -> FunPtr (Ptr () -> Key -> CSize) -- ^ delete+ -> IO ()+++--+-- Options+--++foreign import ccall safe "leveldb/c.h leveldb_options_create"+ c_leveldb_options_create :: IO OptionsPtr++foreign import ccall safe "leveldb/c.h leveldb_options_destroy"+ c_leveldb_options_destroy :: OptionsPtr -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_options_set_comparator"+ c_leveldb_options_set_comparator :: OptionsPtr -> ComparatorPtr -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_options_set_filter_policy"+ c_leveldb_options_set_filter_policy :: OptionsPtr -> FilterPolicyPtr -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_options_set_create_if_missing"+ c_leveldb_options_set_create_if_missing :: OptionsPtr -> CUChar -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_options_set_error_if_exists"+ c_leveldb_options_set_error_if_exists :: OptionsPtr -> CUChar -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_options_set_paranoid_checks"+ c_leveldb_options_set_paranoid_checks :: OptionsPtr -> CUChar -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_options_set_info_log"+ c_leveldb_options_set_info_log :: OptionsPtr -> LoggerPtr -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_options_set_write_buffer_size"+ c_leveldb_options_set_write_buffer_size :: OptionsPtr -> CSize -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_options_set_max_open_files"+ c_leveldb_options_set_max_open_files :: OptionsPtr -> CInt -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_options_set_block_size"+ c_leveldb_options_set_block_size :: OptionsPtr -> CSize -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_options_set_block_restart_interval"+ c_leveldb_options_set_block_restart_interval :: OptionsPtr -> CInt -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_options_set_compression"+ c_leveldb_options_set_compression :: OptionsPtr -> CompressionOpt -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_options_set_cache"+ c_leveldb_options_set_cache :: OptionsPtr -> CachePtr -> IO ()+++--+-- Comparator+--++type StatePtr = Ptr ()+type Destructor = StatePtr -> ()+type CompareFun = StatePtr -> CString -> CSize -> CString -> CSize -> IO CInt+type NameFun = StatePtr -> CString++-- | Make a FunPtr to a user-defined comparator function+foreign import ccall "wrapper" mkCmp :: CompareFun -> IO (FunPtr CompareFun)++-- | Make a destructor FunPtr+foreign import ccall "wrapper" mkDest :: Destructor -> IO (FunPtr Destructor)++-- | Make a name FunPtr+foreign import ccall "wrapper" mkName :: NameFun -> IO (FunPtr NameFun)++foreign import ccall safe "leveldb/c.h leveldb_comparator_create"+ c_leveldb_comparator_create :: StatePtr+ -> FunPtr Destructor+ -> FunPtr CompareFun+ -> FunPtr NameFun+ -> IO ComparatorPtr++foreign import ccall safe "leveldb/c.h leveldb_comparator_destroy"+ c_leveldb_comparator_destroy :: ComparatorPtr -> IO ()+++--+-- Filter Policy+--++type CreateFilterFun = StatePtr+ -> Ptr CString -- ^ key array+ -> Ptr CSize -- ^ key length array+ -> CInt -- ^ num keys+ -> Ptr CSize -- ^ filter length+ -> IO CString -- ^ the filter+type KeyMayMatchFun = StatePtr+ -> CString -- ^ key+ -> CSize -- ^ key length+ -> CString -- ^ filter+ -> CSize -- ^ filter length+ -> IO CUChar -- ^ whether key is in filter++-- | Make a FunPtr to a user-defined create_filter function+foreign import ccall "wrapper" mkCF :: CreateFilterFun -> IO (FunPtr CreateFilterFun)++-- | Make a FunPtr to a user-defined key_may_match function+foreign import ccall "wrapper" mkKMM :: KeyMayMatchFun -> IO (FunPtr KeyMayMatchFun)++foreign import ccall safe "leveldb/c.h leveldb_filterpolicy_create"+ c_leveldb_filterpolicy_create :: StatePtr+ -> FunPtr Destructor+ -> FunPtr CreateFilterFun+ -> FunPtr KeyMayMatchFun+ -> FunPtr NameFun+ -> IO FilterPolicyPtr++foreign import ccall safe "leveldb/c.h leveldb_filterpolicy_destroy"+ c_leveldb_filterpolicy_destroy :: FilterPolicyPtr -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_filterpolicy_create_bloom"+ c_leveldb_filterpolicy_create_bloom :: CInt -> IO FilterPolicyPtr++--+-- Read options+--++foreign import ccall safe "leveldb/c.h leveldb_readoptions_create"+ c_leveldb_readoptions_create :: IO ReadOptionsPtr++foreign import ccall safe "leveldb/c.h leveldb_readoptions_destroy"+ c_leveldb_readoptions_destroy :: ReadOptionsPtr -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_readoptions_set_verify_checksums"+ c_leveldb_readoptions_set_verify_checksums :: ReadOptionsPtr -> CUChar -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_readoptions_set_fill_cache"+ c_leveldb_readoptions_set_fill_cache :: ReadOptionsPtr -> CUChar -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_readoptions_set_snapshot"+ c_leveldb_readoptions_set_snapshot :: ReadOptionsPtr -> SnapshotPtr -> IO ()+++--+-- Write options+--++foreign import ccall safe "leveldb/c.h leveldb_writeoptions_create"+ c_leveldb_writeoptions_create :: IO WriteOptionsPtr++foreign import ccall safe "leveldb/c.h leveldb_writeoptions_destroy"+ c_leveldb_writeoptions_destroy :: WriteOptionsPtr -> IO ()++foreign import ccall safe "leveldb/c.h leveldb_writeoptions_set_sync"+ c_leveldb_writeoptions_set_sync :: WriteOptionsPtr -> CUChar -> IO ()+++--+-- Cache+--++foreign import ccall safe "leveldb/c.h leveldb_cache_create_lru"+ c_leveldb_cache_create_lru :: CSize -> IO CachePtr++foreign import ccall safe "leveldb/c.h leveldb_cache_destroy"+ c_leveldb_cache_destroy :: CachePtr -> IO ()+++--+-- Version+--++foreign import ccall unsafe "leveldb/c.h leveldb_major_version"+ c_leveldb_major_version :: IO CInt++foreign import ccall unsafe "leveldb/c.h leveldb_minor_version"+ c_leveldb_minor_version :: IO CInt
+ src/Database/LevelDB/Internal.hs view
@@ -0,0 +1,291 @@+{-# LANGUAGE RecordWildCards #-}+-- |+-- Module : Database.LevelDB.Internal+-- Copyright : (c) 2012-2013 The leveldb-haskell Authors+-- License : BSD3+-- Maintainer : kim.altintop@gmail.com+-- Stability : experimental+-- Portability : non-portable+--++module Database.LevelDB.Internal+ ( -- * Types+ DB (..)+ , Comparator'+ , FilterPolicy'+ , Options' (..)++ -- * "Smart" constructors and deconstructors+ , freeCReadOpts+ , freeComparator+ , freeFilterPolicy+ , freeOpts+ , mkCReadOpts+ , mkComparator+ , mkCompareFun+ , mkCreateFilterFun+ , mkFilterPolicy+ , mkKeyMayMatchFun+ , mkOpts++ -- * combinators+ , withCWriteOpts+ , withCReadOpts++ -- * Utilities+ , throwIfErr+ , cSizeToInt+ , intToCSize+ , intToCInt+ , cIntToInt+ , boolToNum+ )+where++import Control.Applicative ((<$>))+import Control.Exception (bracket, onException, throwIO)+import Control.Monad (when)+import Data.ByteString (ByteString)+import Foreign+import Foreign.C.String (peekCString, withCString)+import Foreign.C.Types (CInt, CSize)++import Database.LevelDB.C+import Database.LevelDB.Types++import qualified Data.ByteString as BS+++-- | Database handle+data DB = DB LevelDBPtr Options'++instance Eq DB where+ (DB pt1 _) == (DB pt2 _) = pt1 == pt2++-- | Internal representation of a 'Comparator'+data Comparator' = Comparator' (FunPtr CompareFun)+ (FunPtr Destructor)+ (FunPtr NameFun)+ ComparatorPtr++-- | Internal representation of a 'FilterPolicy'+data FilterPolicy' = FilterPolicy' (FunPtr CreateFilterFun)+ (FunPtr KeyMayMatchFun)+ (FunPtr Destructor)+ (FunPtr NameFun)+ FilterPolicyPtr++-- | Internal representation of the 'Options'+data Options' = Options'+ { _optsPtr :: !OptionsPtr+ , _cachePtr :: !(Maybe CachePtr)+ , _comp :: !(Maybe Comparator')+ , _fpPtr :: !(Maybe (Either FilterPolicyPtr FilterPolicy'))+ }+++mkOpts :: Options -> IO Options'+mkOpts Options{..} = do+ opts_ptr <- c_leveldb_options_create++ c_leveldb_options_set_block_restart_interval opts_ptr+ $ intToCInt blockRestartInterval+ c_leveldb_options_set_block_size opts_ptr+ $ intToCSize blockSize+ c_leveldb_options_set_compression opts_ptr+ $ ccompression compression+ c_leveldb_options_set_create_if_missing opts_ptr+ $ boolToNum createIfMissing+ c_leveldb_options_set_error_if_exists opts_ptr+ $ boolToNum errorIfExists+ c_leveldb_options_set_max_open_files opts_ptr+ $ intToCInt maxOpenFiles+ c_leveldb_options_set_paranoid_checks opts_ptr+ $ boolToNum paranoidChecks+ c_leveldb_options_set_write_buffer_size opts_ptr+ $ intToCSize writeBufferSize++ cache <- maybeSetCache opts_ptr cacheSize+ cmp <- maybeSetCmp opts_ptr comparator+ fp <- maybeSetFilterPolicy opts_ptr filterPolicy++ return (Options' opts_ptr cache cmp fp)++ where+ ccompression NoCompression = noCompression+ ccompression Snappy = snappyCompression++ maybeSetCache :: OptionsPtr -> Int -> IO (Maybe CachePtr)+ maybeSetCache opts_ptr size =+ if size <= 0+ then return Nothing+ else do+ cache_ptr <- c_leveldb_cache_create_lru $ intToCSize size+ c_leveldb_options_set_cache opts_ptr cache_ptr+ return . Just $ cache_ptr++ maybeSetCmp :: OptionsPtr -> Maybe Comparator -> IO (Maybe Comparator')+ maybeSetCmp opts_ptr (Just mcmp) = Just <$> setcmp opts_ptr mcmp+ maybeSetCmp _ Nothing = return Nothing++ setcmp :: OptionsPtr -> Comparator -> IO Comparator'+ setcmp opts_ptr (Comparator cmp) = do+ cmp'@(Comparator' _ _ _ cmp_ptr) <- mkComparator "user-defined" cmp+ c_leveldb_options_set_comparator opts_ptr cmp_ptr+ return cmp'++ maybeSetFilterPolicy :: OptionsPtr+ -> Maybe (Either BloomFilter FilterPolicy)+ -> IO (Maybe (Either FilterPolicyPtr FilterPolicy'))+ maybeSetFilterPolicy _ Nothing =+ return Nothing+ maybeSetFilterPolicy opts_ptr (Just (Left (BloomFilter bloom_ptr))) = do+ c_leveldb_options_set_filter_policy opts_ptr bloom_ptr+ return Nothing -- bloom filter is freed automatically+ maybeSetFilterPolicy opts_ptr (Just (Right fp)) = do+ fp'@(FilterPolicy' _ _ _ _ fp_ptr) <- mkFilterPolicy fp+ c_leveldb_options_set_filter_policy opts_ptr fp_ptr+ return . Just . Right $ fp'++freeOpts :: Options' -> IO ()+freeOpts (Options' opts_ptr mcache_ptr mcmp_ptr mfp) = do+ c_leveldb_options_destroy opts_ptr+ maybe (return ()) c_leveldb_cache_destroy mcache_ptr+ maybe (return ()) freeComparator mcmp_ptr+ maybe (return ())+ (either c_leveldb_filterpolicy_destroy freeFilterPolicy)+ mfp++ return ()++withCWriteOpts :: WriteOptions -> (WriteOptionsPtr -> IO a) -> IO a+withCWriteOpts WriteOptions{..} = bracket mkCWriteOpts freeCWriteOpts+ where+ mkCWriteOpts = do+ opts_ptr <- c_leveldb_writeoptions_create+ onException+ (c_leveldb_writeoptions_set_sync opts_ptr $ boolToNum sync)+ (c_leveldb_writeoptions_destroy opts_ptr)+ return opts_ptr++ freeCWriteOpts = c_leveldb_writeoptions_destroy++mkCompareFun :: (ByteString -> ByteString -> Ordering) -> CompareFun+mkCompareFun cmp = cmp'+ where+ cmp' _ a alen b blen = do+ a' <- BS.packCStringLen (a, fromInteger . toInteger $ alen)+ b' <- BS.packCStringLen (b, fromInteger . toInteger $ blen)+ return $ case cmp a' b' of+ EQ -> 0+ GT -> 1+ LT -> -1++mkComparator :: String -> (ByteString -> ByteString -> Ordering) -> IO Comparator'+mkComparator name f =+ withCString name $ \cs -> do+ ccmpfun <- mkCmp . mkCompareFun $ f+ cdest <- mkDest $ const ()+ cname <- mkName $ const cs+ ccmp <- c_leveldb_comparator_create nullPtr cdest ccmpfun cname+ return $ Comparator' ccmpfun cdest cname ccmp+++freeComparator :: Comparator' -> IO ()+freeComparator (Comparator' ccmpfun cdest cname ccmp) = do+ c_leveldb_comparator_destroy ccmp+ freeHaskellFunPtr ccmpfun+ freeHaskellFunPtr cdest+ freeHaskellFunPtr cname++mkCreateFilterFun :: ([ByteString] -> ByteString) -> CreateFilterFun+mkCreateFilterFun f = f'+ where+ f' _ ks ks_lens n_ks flen = do+ let n_ks' = fromInteger . toInteger $ n_ks+ ks' <- peekArray n_ks' ks+ ks_lens' <- peekArray n_ks' ks_lens+ keys <- mapM bstr (zip ks' ks_lens')+ let res = f keys+ poke flen (fromIntegral . BS.length $ res)+ BS.useAsCString res $ \cstr -> return cstr++ bstr (x,len) = BS.packCStringLen (x, fromInteger . toInteger $ len)++mkKeyMayMatchFun :: (ByteString -> ByteString -> Bool) -> KeyMayMatchFun+mkKeyMayMatchFun g = g'+ where+ g' _ k klen f flen = do+ k' <- BS.packCStringLen (k, fromInteger . toInteger $ klen)+ f' <- BS.packCStringLen (f, fromInteger . toInteger $ flen)+ return . boolToNum $ g k' f'+++mkFilterPolicy :: FilterPolicy -> IO FilterPolicy'+mkFilterPolicy FilterPolicy{..} =+ withCString fpName $ \cs -> do+ cname <- mkName $ const cs+ cdest <- mkDest $ const ()+ ccffun <- mkCF . mkCreateFilterFun $ createFilter+ ckmfun <- mkKMM . mkKeyMayMatchFun $ keyMayMatch+ cfp <- c_leveldb_filterpolicy_create nullPtr cdest ccffun ckmfun cname++ return $ FilterPolicy' ccffun ckmfun cdest cname cfp++freeFilterPolicy :: FilterPolicy' -> IO ()+freeFilterPolicy (FilterPolicy' ccffun ckmfun cdest cname cfp) = do+ c_leveldb_filterpolicy_destroy cfp+ freeHaskellFunPtr ccffun+ freeHaskellFunPtr ckmfun+ freeHaskellFunPtr cdest+ freeHaskellFunPtr cname++mkCReadOpts :: ReadOptions -> IO ReadOptionsPtr+mkCReadOpts ReadOptions{..} = do+ opts_ptr <- c_leveldb_readoptions_create+ flip onException (c_leveldb_readoptions_destroy opts_ptr) $ do+ c_leveldb_readoptions_set_verify_checksums opts_ptr $ boolToNum verifyCheckSums+ c_leveldb_readoptions_set_fill_cache opts_ptr $ boolToNum fillCache++ case useSnapshot of+ Just (Snapshot snap_ptr) -> c_leveldb_readoptions_set_snapshot opts_ptr snap_ptr+ Nothing -> return ()++ return opts_ptr++freeCReadOpts :: ReadOptionsPtr -> IO ()+freeCReadOpts = c_leveldb_readoptions_destroy++withCReadOpts :: ReadOptions -> (ReadOptionsPtr -> IO a) -> IO a+withCReadOpts opts = bracket (mkCReadOpts opts) freeCReadOpts++throwIfErr :: String -> (ErrPtr -> IO a) -> IO a+throwIfErr s f = alloca $ \err_ptr -> do+ poke err_ptr nullPtr+ res <- f err_ptr+ erra <- peek err_ptr+ when (erra /= nullPtr) $ do+ err <- peekCString erra+ throwIO $ userError $ s ++ ": " ++ err+ return res++cSizeToInt :: CSize -> Int+cSizeToInt = fromIntegral+{-# INLINE cSizeToInt #-}++intToCSize :: Int -> CSize+intToCSize = fromIntegral+{-# INLINE intToCSize #-}++intToCInt :: Int -> CInt+intToCInt = fromIntegral+{-# INLINE intToCInt #-}++cIntToInt :: CInt -> Int+cIntToInt = fromIntegral+{-# INLINE cIntToInt #-}++boolToNum :: Num b => Bool -> b+boolToNum True = fromIntegral (1 :: Int)+boolToNum False = fromIntegral (0 :: Int)+{-# INLINE boolToNum #-}
+ src/Database/LevelDB/Iterator.hs view
@@ -0,0 +1,227 @@+-- |+-- Module : Database.LevelDB.Iterator+-- Copyright : (c) 2012-2013 The leveldb-haskell Authors+-- License : BSD3+-- Maintainer : kim.altintop@gmail.com+-- Stability : experimental+-- Portability : non-portable+--+-- Iterating over key ranges.+--++module Database.LevelDB.Iterator+ ( Iterator+ , createIter+ , iterEntry+ , iterFirst+ , iterGetError+ , iterItems+ , iterKey+ , iterKeys+ , iterLast+ , iterNext+ , iterPrev+ , iterSeek+ , iterValid+ , iterValue+ , iterValues+ , mapIter+ , releaseIter+ , withIter+ )+where++import Control.Applicative ((<$>), (<*>))+import Control.Exception (bracket, finally, onException)+import Control.Monad (when)+import Control.Monad.IO.Class (MonadIO (liftIO))+import Data.ByteString (ByteString)+import Data.Maybe (catMaybes)+import Foreign+import Foreign.C.Error (throwErrnoIfNull)+import Foreign.C.String (CString, peekCString)+import Foreign.C.Types (CSize)++import Database.LevelDB.C+import Database.LevelDB.Internal+import Database.LevelDB.Types++import qualified Data.ByteString as BS+import qualified Data.ByteString.Char8 as BC+import qualified Data.ByteString.Unsafe as BU++-- | Iterator handle+--+-- Note that an 'Iterator' requires external synchronization if it is shared+-- between multiple threads which mutate it's state. See+-- @examples/iterforkio.hs@ for a simple example of how to do that.+data Iterator = Iterator !IteratorPtr !ReadOptionsPtr deriving (Eq)++-- | Create an 'Iterator'.+--+-- The iterator should be released with 'releaseIter'.+--+-- Note that an 'Iterator' creates a snapshot of the database implicitly, so+-- updates written after the iterator was created are not visible. You may,+-- however, specify an older 'Snapshot' in the 'ReadOptions'.+createIter :: MonadIO m => DB -> ReadOptions -> m Iterator+createIter (DB db_ptr _) opts = liftIO $ do+ opts_ptr <- mkCReadOpts opts+ flip onException (freeCReadOpts opts_ptr) $ do+ iter_ptr <- throwErrnoIfNull "create_iterator" $+ c_leveldb_create_iterator db_ptr opts_ptr+ return $ Iterator iter_ptr opts_ptr++-- | Release an 'Iterator'.+--+-- The handle will be invalid after calling this action and should no+-- longer be used. Calling this function with an already released 'Iterator'+-- will cause a double-free error!+releaseIter :: MonadIO m => Iterator -> m ()+releaseIter (Iterator iter_ptr opts) = liftIO $+ c_leveldb_iter_destroy iter_ptr `finally` freeCReadOpts opts++-- | Run an action with an 'Iterator'+withIter :: MonadIO m => DB -> ReadOptions -> (Iterator -> IO a) -> m a+withIter db opts = liftIO . bracket (createIter db opts) releaseIter++-- | An iterator is either positioned at a key/value pair, or not valid. This+-- function returns /true/ iff the iterator is valid.+iterValid :: MonadIO m => Iterator -> m Bool+iterValid (Iterator iter_ptr _) = liftIO $ do+ x <- c_leveldb_iter_valid iter_ptr+ return (x /= 0)++-- | Position at the first key in the source that is at or past target. The+-- iterator is /valid/ after this call iff the source contains an entry that+-- comes at or past target.+iterSeek :: MonadIO m => Iterator -> ByteString -> m ()+iterSeek (Iterator iter_ptr _) key = liftIO $+ BU.unsafeUseAsCStringLen key $ \(key_ptr, klen) ->+ c_leveldb_iter_seek iter_ptr key_ptr (intToCSize klen)++-- | Position at the first key in the source. The iterator is /valid/ after this+-- call iff the source is not empty.+iterFirst :: MonadIO m => Iterator -> m ()+iterFirst (Iterator iter_ptr _) = liftIO $ c_leveldb_iter_seek_to_first iter_ptr++-- | Position at the last key in the source. The iterator is /valid/ after this+-- call iff the source is not empty.+iterLast :: MonadIO m => Iterator -> m ()+iterLast (Iterator iter_ptr _) = liftIO $ c_leveldb_iter_seek_to_last iter_ptr++-- | Moves to the next entry in the source. After this call, 'iterValid' is+-- /true/ iff the iterator was not positioned at the last entry in the source.+--+-- If the iterator is not valid, this function does nothing. Note that this is a+-- shortcoming of the C API: an 'iterPrev' might still be possible, but we can't+-- determine if we're at the last or first entry.+iterNext :: MonadIO m => Iterator -> m ()+iterNext (Iterator iter_ptr _) = liftIO $ do+ valid <- c_leveldb_iter_valid iter_ptr+ when (valid /= 0) $ c_leveldb_iter_next iter_ptr++-- | Moves to the previous entry in the source. After this call, 'iterValid' is+-- /true/ iff the iterator was not positioned at the first entry in the source.+--+-- If the iterator is not valid, this function does nothing. Note that this is a+-- shortcoming of the C API: an 'iterNext' might still be possible, but we can't+-- determine if we're at the last or first entry.+iterPrev :: MonadIO m => Iterator -> m ()+iterPrev (Iterator iter_ptr _) = liftIO $ do+ valid <- c_leveldb_iter_valid iter_ptr+ when (valid /= 0) $ c_leveldb_iter_prev iter_ptr++-- | Return the key for the current entry if the iterator is currently+-- positioned at an entry, ie. 'iterValid'.+iterKey :: MonadIO m => Iterator -> m (Maybe ByteString)+iterKey = liftIO . flip iterString c_leveldb_iter_key++-- | Return the value for the current entry if the iterator is currently+-- positioned at an entry, ie. 'iterValid'.+iterValue :: MonadIO m => Iterator -> m (Maybe ByteString)+iterValue = liftIO . flip iterString c_leveldb_iter_value++-- | Return the current entry as a pair, if the iterator is currently positioned+-- at an entry, ie. 'iterValid'.+iterEntry :: MonadIO m => Iterator -> m (Maybe (ByteString, ByteString))+iterEntry iter = liftIO $ do+ mkey <- iterKey iter+ mval <- iterValue iter+ return $ (,) <$> mkey <*> mval++-- | Check for errors+--+-- Note that this captures somewhat severe errors such as a corrupted database.+iterGetError :: MonadIO m => Iterator -> m (Maybe ByteString)+iterGetError (Iterator iter_ptr _) = liftIO $+ alloca $ \err_ptr -> do+ poke err_ptr nullPtr+ c_leveldb_iter_get_error iter_ptr err_ptr+ erra <- peek err_ptr+ if erra == nullPtr+ then return Nothing+ else do+ err <- peekCString erra+ return . Just . BC.pack $ err++-- | Map a function over an iterator, advancing the iterator forward and+-- returning the value. The iterator should be put in the right position prior+-- to calling the function.+--+-- Note that this function accumulates the result strictly, ie. it reads all+-- values into memory until the iterator is exhausted. This is most likely not+-- what you want for large ranges. You may consider using conduits instead, for+-- an example see: <https://gist.github.com/adc8ec348f03483446a5>+mapIter :: MonadIO m => (Iterator -> m a) -> Iterator -> m [a]+mapIter f iter@(Iterator iter_ptr _) = go []+ where+ go acc = do+ valid <- liftIO $ c_leveldb_iter_valid iter_ptr+ if valid == 0+ then return acc+ else do+ val <- f iter+ () <- liftIO $ c_leveldb_iter_next iter_ptr+ go (val : acc)++-- | Return a list of key and value tuples from an iterator. The iterator+-- should be put in the right position prior to calling this with the iterator.+--+-- See strictness remarks on 'mapIter'.+iterItems :: (Functor m, MonadIO m) => Iterator -> m [(ByteString, ByteString)]+iterItems iter = catMaybes <$> mapIter iterEntry iter++-- | Return a list of key from an iterator. The iterator should be put+-- in the right position prior to calling this with the iterator.+--+-- See strictness remarks on 'mapIter'+iterKeys :: (Functor m, MonadIO m) => Iterator -> m [ByteString]+iterKeys iter = catMaybes <$> mapIter iterKey iter++-- | Return a list of values from an iterator. The iterator should be put+-- in the right position prior to calling this with the iterator.+--+-- See strictness remarks on 'mapIter'+iterValues :: (Functor m, MonadIO m) => Iterator -> m [ByteString]+iterValues iter = catMaybes <$> mapIter iterValue iter+++--+-- Internal+--++iterString :: Iterator+ -> (IteratorPtr -> Ptr CSize -> IO CString)+ -> IO (Maybe ByteString)+iterString (Iterator iter_ptr _) f = do+ valid <- c_leveldb_iter_valid iter_ptr+ if valid == 0+ then return Nothing+ else alloca $ \len_ptr -> do+ ptr <- f iter_ptr len_ptr+ if ptr == nullPtr+ then return Nothing+ else do+ len <- peek len_ptr+ Just <$> BS.packCStringLen (ptr, cSizeToInt len)
+ src/Database/LevelDB/MonadResource.hs view
@@ -0,0 +1,285 @@+-- |+-- Module : Database.LevelDB.MonadResource+-- Copyright : (c) 2012-2013 The leveldb-haskell Authors+-- License : BSD3+-- Maintainer : kim.altintop@gmail.com+-- Stability : experimental+-- Portability : non-portable+--++module Database.LevelDB.MonadResource+ ( -- * Exported Types+ DB+ , BatchOp(..)+ , Comparator(..)+ , Compression(..)+ , Options(..)+ , ReadOptions(..)+ , Snapshot+ , WriteBatch+ , WriteOptions(..)+ , Range++ -- * Defaults+ , defaultOptions+ , defaultWriteOptions+ , defaultReadOptions++ -- * Basic Database Manipulation+ , withSnapshot+ , open+ , put+ , delete+ , write+ , get+ , createSnapshot+ , createSnapshot'++ -- * Filter Policy / Bloom Filter+ , FilterPolicy(..)+ , bloomFilter++ -- * Administrative Functions+ , Property(..), getProperty+ , destroy+ , repair+ , approximateSize+ , version++ -- * Iteration+ , Iterator+ , withIterator+ , iterOpen+ , iterOpen'+ , iterValid+ , iterSeek+ , iterFirst+ , iterLast+ , iterNext+ , iterPrev+ , iterKey+ , iterValue+ , iterGetError+ , mapIter+ , iterItems+ , iterKeys+ , iterValues++ -- * Re-exports+ , MonadResource (..)+ , runResourceT+ , resourceForkIO+ )+where++import Control.Applicative ((<$>))+import Control.Monad.Trans.Resource+import Data.ByteString (ByteString)+import Data.Int (Int64)++import Database.LevelDB.Base (BatchOp, BloomFilter, Comparator,+ Compression, DB, FilterPolicy,+ Iterator, Options, Property,+ Range, ReadOptions, Snapshot,+ WriteBatch, WriteOptions,+ defaultOptions,+ defaultReadOptions,+ defaultWriteOptions)+import qualified Database.LevelDB.Base as Base+++-- | Create a 'BloomFilter'+bloomFilter :: MonadResource m => Int -> m BloomFilter+bloomFilter i =+ snd <$> allocate (Base.createBloomFilter i)+ Base.releaseBloomFilter++-- | Open a database+--+-- The returned handle will automatically be released when the enclosing+-- 'runResourceT' terminates.+open :: MonadResource m => FilePath -> Options -> m DB+open path opts = snd <$> open' path opts++open' :: MonadResource m => FilePath -> Options -> m (ReleaseKey, DB)+open' path opts = allocate (Base.open path opts) Base.close+{-# INLINE open' #-}++-- | Run an action with a snapshot of the database.+--+-- The snapshot will be released when the action terminates or throws an+-- exception. Note that this function is provided for convenience and does not+-- prevent the 'Snapshot' handle to escape. It will, however, be invalid after+-- this function returns and should not be used anymore.+withSnapshot :: MonadResource m => DB -> (Snapshot -> m a) -> m a+withSnapshot db f = do+ (rk, snap) <- createSnapshot' db+ res <- f snap+ release rk+ return res++-- | Create a snapshot of the database.+--+-- The returned 'Snapshot' will be released automatically when the enclosing+-- 'runResourceT' terminates. It is recommended to use 'createSnapshot'' instead+-- and release the resource manually as soon as possible.+createSnapshot :: MonadResource m => DB -> m Snapshot+createSnapshot db = snd <$> createSnapshot' db++-- | Create a snapshot of the database which can (and should) be released early.+createSnapshot' :: MonadResource m => DB -> m (ReleaseKey, Snapshot)+createSnapshot' db = allocate (Base.createSnapshot db) (Base.releaseSnapshot db)++-- | Get a DB property+getProperty :: MonadResource m => DB -> Property -> m (Maybe ByteString)+getProperty = Base.getProperty++-- | Destroy the given leveldb database.+destroy :: MonadResource m => FilePath -> Options -> m ()+destroy = Base.destroy++-- | Repair the given leveldb database.+repair :: MonadResource m => FilePath -> Options -> m ()+repair = Base.repair+++-- | Inspect the approximate sizes of the different levels+approximateSize :: MonadResource m => DB -> Range -> m Int64+approximateSize = Base.approximateSize++-- | Write a key/value pair+put :: MonadResource m => DB -> WriteOptions -> ByteString -> ByteString -> m ()+put = Base.put++-- | Read a value by key+get :: MonadResource m => DB -> ReadOptions -> ByteString -> m (Maybe ByteString)+get = Base.get++-- | Delete a key/value pair+delete :: MonadResource m => DB -> WriteOptions -> ByteString -> m ()+delete = Base.delete++-- | Perform a batch mutation+write :: MonadResource m => DB -> WriteOptions -> WriteBatch -> m ()+write = Base.write+++-- | Run an action with an Iterator. The iterator will be closed after the+-- action returns or an error is thrown. Thus, the iterator will /not/ be valid+-- after this function terminates.+withIterator :: MonadResource m => DB -> ReadOptions -> (Iterator -> m a) -> m a+withIterator db opts f = do+ (rk, iter) <- iterOpen' db opts+ res <- f iter+ release rk+ return res++-- | Create an 'Iterator'.+--+-- The iterator will be released when the enclosing 'runResourceT' terminates.+-- You may consider to use 'iterOpen'' instead and manually release the iterator+-- as soon as it is no longer needed (alternatively, use 'withIterator').+--+-- Note that an 'Iterator' creates a snapshot of the database implicitly, so+-- updates written after the iterator was created are not visible. You may,+-- however, specify an older 'Snapshot' in the 'ReadOptions'.+iterOpen :: MonadResource m => DB -> ReadOptions -> m Iterator+iterOpen db opts = snd <$> iterOpen' db opts++-- | Create an 'Iterator' which can be released early.+iterOpen' :: MonadResource m => DB -> ReadOptions -> m (ReleaseKey, Iterator)+iterOpen' db opts = allocate (Base.createIter db opts) Base.releaseIter++-- | An iterator is either positioned at a key/value pair, or not valid. This+-- function returns /true/ iff the iterator is valid.+iterValid :: MonadResource m => Iterator -> m Bool+iterValid = Base.iterValid++-- | Position at the first key in the source that is at or past target. The+-- iterator is /valid/ after this call iff the source contains an entry that+-- comes at or past target.+iterSeek :: MonadResource m => Iterator -> ByteString -> m ()+iterSeek = Base.iterSeek++-- | Position at the first key in the source. The iterator is /valid/ after this+-- call iff the source is not empty.+iterFirst :: MonadResource m => Iterator -> m ()+iterFirst = Base.iterFirst++-- | Position at the last key in the source. The iterator is /valid/ after this+-- call iff the source is not empty.+iterLast :: MonadResource m => Iterator -> m ()+iterLast = Base.iterLast++-- | Moves to the next entry in the source. After this call, 'iterValid' is+-- /true/ iff the iterator was not positioned at the last entry in the source.+--+-- If the iterator is not valid, this function does nothing. Note that this is a+-- shortcoming of the C API: an 'iterPrev' might still be possible, but we can't+-- determine if we're at the last or first entry.+iterNext :: MonadResource m => Iterator -> m ()+iterNext = Base.iterNext++-- | Moves to the previous entry in the source. After this call, 'iterValid' is+-- /true/ iff the iterator was not positioned at the first entry in the source.+--+-- If the iterator is not valid, this function does nothing. Note that this is a+-- shortcoming of the C API: an 'iterNext' might still be possible, but we can't+-- determine if we're at the last or first entry.+iterPrev :: MonadResource m => Iterator -> m ()+iterPrev = Base.iterPrev++-- | Return the key for the current entry if the iterator is currently+-- positioned at an entry, ie. 'iterValid'.+iterKey :: MonadResource m => Iterator -> m (Maybe ByteString)+iterKey = Base.iterKey++-- | Return the value for the current entry if the iterator is currently+-- positioned at an entry, ie. 'iterValid'.+iterValue :: MonadResource m => Iterator -> m (Maybe ByteString)+iterValue = Base.iterValue++-- | Check for errors+--+-- Note that this captures somewhat severe errors such as a corrupted database.+iterGetError :: MonadResource m => Iterator -> m (Maybe ByteString)+iterGetError = Base.iterGetError+++-- | Map a function over an iterator, advancing the iterator forward and+-- returning the value. The iterator should be put in the right position prior+-- to calling the function.+--+-- Note that this function accumulates the result strictly, ie. it reads all+-- values into memory until the iterator is exhausted. This is most likely not+-- what you want for large ranges. You may consider using conduits instead, for+-- an example see: <https://gist.github.com/adc8ec348f03483446a5>+mapIter :: MonadResource m => (Iterator -> m a) -> Iterator -> m [a]+mapIter = Base.mapIter++-- | Return a list of key and value tuples from an iterator. The iterator+-- should be put in the right position prior to calling this with the iterator.+--+-- See strictness remarks on 'mapIter'.+iterItems :: MonadResource m => Iterator -> m [(ByteString, ByteString)]+iterItems = Base.iterItems++-- | Return a list of key from an iterator. The iterator should be put+-- in the right position prior to calling this with the iterator.+--+-- See strictness remarks on 'mapIter'+iterKeys :: MonadResource m => Iterator -> m [ByteString]+iterKeys = Base.iterKeys++-- | Return a list of values from an iterator. The iterator should be put+-- in the right position prior to calling this with the iterator.+--+-- See strictness remarks on 'mapIter'+iterValues :: MonadResource m => Iterator -> m [ByteString]+iterValues = Base.iterValues+++-- | Return the runtime version of the underlying LevelDB library as a (major,+-- minor) pair.+version :: MonadResource m => m (Int, Int)+version = Base.version
+ src/Database/LevelDB/Types.hs view
@@ -0,0 +1,217 @@+-- |+-- Module : Database.LevelDB.Types+-- Copyright : (c) 2012-2013 The leveldb-haskell Authors+-- License : BSD3+-- Maintainer : kim.altintop@gmail.com+-- Stability : experimental+-- Portability : non-portable+--++module Database.LevelDB.Types+ ( BatchOp (..)+ , BloomFilter (..)+ , Comparator (..)+ , Compression (..)+ , FilterPolicy (..)+ , Options (..)+ , Property (..)+ , ReadOptions (..)+ , Snapshot (..)+ , WriteBatch+ , WriteOptions (..)++ , defaultOptions+ , defaultReadOptions+ , defaultWriteOptions+ )+where++import Data.ByteString (ByteString)+import Data.Default+import Foreign++import Database.LevelDB.C++-- | Snapshot handle+newtype Snapshot = Snapshot SnapshotPtr deriving (Eq)++-- | Compression setting+data Compression = NoCompression | Snappy deriving (Eq, Show)++-- | User-defined comparator+newtype Comparator = Comparator (ByteString -> ByteString -> Ordering)++-- | User-defined filter policy+data FilterPolicy = FilterPolicy+ { fpName :: String+ , createFilter :: [ByteString] -> ByteString+ , keyMayMatch :: ByteString -> ByteString -> Bool+ }++-- | Represents the built-in Bloom Filter+newtype BloomFilter = BloomFilter FilterPolicyPtr++-- | Options when opening a database+data Options = Options+ { blockRestartInterval :: !Int+ -- ^ Number of keys between restart points for delta encoding of keys.+ --+ -- This parameter can be changed dynamically. Most clients should leave+ -- this parameter alone.+ --+ -- Default: 16+ , blockSize :: !Int+ -- ^ Approximate size of user data packed per block.+ --+ -- Note that the block size specified here corresponds to uncompressed+ -- data. The actual size of the unit read from disk may be smaller if+ -- compression is enabled.+ --+ -- This parameter can be changed dynamically.+ --+ -- Default: 4k+ , cacheSize :: !Int+ -- ^ Control over blocks (user data is stored in a set of blocks, and a+ -- block is the unit of reading from disk).+ --+ -- If > 0, use the specified cache (in bytes) for blocks. If 0, leveldb+ -- will automatically create and use an 8MB internal cache.+ --+ -- Default: 0+ , comparator :: !(Maybe Comparator)+ -- ^ Comparator used to defined the order of keys in the table.+ --+ -- If 'Nothing', the default comparator is used, which uses lexicographic+ -- bytes-wise ordering.+ --+ -- NOTE: the client must ensure that the comparator supplied here has the+ -- same name and orders keys /exactly/ the same as the comparator provided+ -- to previous open calls on the same DB.+ --+ -- Default: Nothing+ , compression :: !Compression+ -- ^ Compress blocks using the specified compression algorithm.+ --+ -- This parameter can be changed dynamically.+ --+ -- Default: 'Snappy'+ , createIfMissing :: !Bool+ -- ^ If true, the database will be created if it is missing.+ --+ -- Default: False+ , errorIfExists :: !Bool+ -- ^ It true, an error is raised if the database already exists.+ --+ -- Default: False+ , maxOpenFiles :: !Int+ -- ^ Number of open files that can be used by the DB.+ --+ -- You may need to increase this if your database has a large working set+ -- (budget one open file per 2MB of working set).+ --+ -- Default: 1000+ , paranoidChecks :: !Bool+ -- ^ If true, the implementation will do aggressive checking of the data+ -- it is processing and will stop early if it detects any errors.+ --+ -- This may have unforeseen ramifications: for example, a corruption of+ -- one DB entry may cause a large number of entries to become unreadable+ -- or for the entire DB to become unopenable.+ --+ -- Default: False+ , writeBufferSize :: !Int+ -- ^ Amount of data to build up in memory (backed by an unsorted log on+ -- disk) before converting to a sorted on-disk file.+ --+ -- Larger values increase performance, especially during bulk loads. Up to+ -- to write buffers may be held in memory at the same time, so you may+ -- with to adjust this parameter to control memory usage. Also, a larger+ -- write buffer will result in a longer recovery time the next time the+ -- database is opened.+ --+ -- Default: 4MB+ , filterPolicy :: !(Maybe (Either BloomFilter FilterPolicy))+ }++defaultOptions :: Options+defaultOptions = Options+ { blockRestartInterval = 16+ , blockSize = 4096+ , cacheSize = 0+ , comparator = Nothing+ , compression = Snappy+ , createIfMissing = False+ , errorIfExists = False+ , maxOpenFiles = 1000+ , paranoidChecks = False+ , writeBufferSize = 4 `shift` 20+ , filterPolicy = Nothing+ }++instance Default Options where+ def = defaultOptions++-- | Options for write operations+data WriteOptions = WriteOptions+ { sync :: !Bool+ -- ^ If true, the write will be flushed from the operating system buffer+ -- cache (by calling WritableFile::Sync()) before the write is considered+ -- complete. If this flag is true, writes will be slower.+ --+ -- If this flag is false, and the machine crashes, some recent writes may+ -- be lost. Note that if it is just the process that crashes (i.e., the+ -- machine does not reboot), no writes will be lost even if sync==false.+ --+ -- In other words, a DB write with sync==false has similar crash semantics+ -- as the "write()" system call. A DB write with sync==true has similar+ -- crash semantics to a "write()" system call followed by "fsync()".+ --+ -- Default: False+ } deriving (Eq, Show)++defaultWriteOptions :: WriteOptions+defaultWriteOptions = WriteOptions { sync = False }++instance Default WriteOptions where+ def = defaultWriteOptions++-- | Options for read operations+data ReadOptions = ReadOptions+ { verifyCheckSums :: !Bool+ -- ^ If true, all data read from underlying storage will be verified+ -- against corresponding checksuyms.+ --+ -- Default: False+ , fillCache :: !Bool+ -- ^ Should the data read for this iteration be cached in memory? Callers+ -- may with to set this field to false for bulk scans.+ --+ -- Default: True+ , useSnapshot :: !(Maybe Snapshot)+ -- ^ If 'Just', read as of the supplied snapshot (which must belong to the+ -- DB that is being read and which must not have been released). If+ -- 'Nothing', use an implicit snapshot of the state at the beginning of+ -- this read operation.+ --+ -- Default: Nothing+ } deriving (Eq)++defaultReadOptions :: ReadOptions+defaultReadOptions = ReadOptions+ { verifyCheckSums = False+ , fillCache = True+ , useSnapshot = Nothing+ }++instance Default ReadOptions where+ def = defaultReadOptions++type WriteBatch = [BatchOp]++-- | Batch operation+data BatchOp = Put ByteString ByteString | Del ByteString+ deriving (Eq, Show)++-- | Properties exposed by LevelDB+data Property = NumFilesAtLevel Int | Stats | SSTables+ deriving (Eq, Show)