packages feed

tokyocabinet-haskell-0.0.2: Database/TokyoCabinet/BDB.hs

-- | Interface to B+ tree based DBM. See also,
-- <http://tokyocabinet.sourceforge.net/spex-en.html#tcbdbapi> for details
module Database.TokyoCabinet.BDB
    (
    -- $doc
    -- * Constructors
      BDB
    , ECODE(..)
    , OpenMode(..)
    , TuningOption(..)
    -- * Basic API (tokyocabinet.idl compliant)
    , new
    , delete
    , ecode
    , errmsg
    , tune
    , setcache
    , setxmsiz
    , open
    , close
    , put
    , putkeep
    , putcat
    , putdup
    , putlist
    , out
    , outlist
    , get
    , getlist
    , vnum
    , vsiz
    , range
    , fwmkeys
    , addint
    , adddouble
    , sync
    , optimize
    , vanish
    , copy
    , tranbegin
    , trancommit
    , tranabort
    , path
    , rnum
    , fsiz
    ) where

import Data.Int
import Data.Word

import Foreign.Ptr
import Foreign.ForeignPtr
import Foreign.Storable (peek)
import Foreign.Marshal (alloca)

import Database.TokyoCabinet.Error
import Database.TokyoCabinet.BDB.C
import Database.TokyoCabinet.List.C
import Database.TokyoCabinet.Internal
import Database.TokyoCabinet.Storable
import Database.TokyoCabinet.Sequence

-- $doc
-- Example
--
-- @
--    import Control.Monad
--    import Database.TokyoCabinet.BDB
--    import qualified Database.TokyoCabinet.BDB.Cursor as C
-- @
--
-- @  
--    main :: IO ()
--    main =
--        do bdb <- new
--           -- open the database
--           open bdb \"casket.tcb\" [OWRITER, OCREAT] >>= err bdb
--           -- store records
--           puts bdb [ (\"foo\", \"hop\"), (\"bar\", \"step\"), (\"baz\", \"jump\") ] >>=
--                    err bdb . (all id)
--           -- retrieve records
--           get bdb \"foo\" >>= maybe (error \"something goes wrong\") putStrLn
--           -- traverse records
--           cur <- C.new bdb
--           C.first cur >>= err bdb
--           iter cur >>= putStrLn . show
--           -- close the database
--           close bdb >>= err bdb
--        where
--          puts :: BDB -> [(String, String)] -> IO [Bool]
--          puts bdb = mapM (uncurry $ put bdb)
-- @
--
-- @
--          err :: BDB -> Bool -> IO ()
--          err bdb = flip unless $ ecode bdb >>= error . show
-- @
--
-- @  
--          iter :: C.BDBCUR -> IO [(String, String)]
--          iter cur = do
--            [key, value] <- sequence [C.key cur, C.val cur]
--            case (key, value) of
--              (Just k, Just v) -> C.next cur >> iter cur >>= return . ((k,v):)
--              _ -> return []
-- @
--

-- | Create a B+ tree database object. 
new :: IO BDB
new = BDB `fmap` (c_tcbdbnew >>= newForeignPtr tcbdbFinalizer)

-- | Free BDB resource forcibly. 
-- BDB is kept by ForeignPtr, so Haskell runtime GC cleans up memory for
-- almost situation. Most always, you don't need to call this. 
-- After call this, you must not touch BDB object. Its behavior is undefined.
delete :: BDB -> IO ()
delete bdb = finalizeForeignPtr (unTCBDB bdb)

-- | Return the last happened error code.
ecode :: BDB -> IO ECODE
ecode bdb = cintToError `fmap` withForeignPtr (unTCBDB bdb) c_tcbdbecode

-- | Set the tuning parameters.
tune :: BDB   -- ^ BDB object
     -> Int32 -- ^ the number of members in each leaf page.
     -> Int32 -- ^ the number of members in each non-leaf page.
     -> Int64 -- ^ the number of elements of the bucket array. 
     -> Int8  -- ^ the size of record alignment by power of 2.
     -> Int8  -- ^ the maximum number of elements of the free block
              -- pool by power of 2.
     -> [TuningOption] -- ^ tuning options
     -> IO Bool -- ^ if successful, the return value is True.
tune bdb lmemb nmemb bnum apow fpow opts =
    withForeignPtr (unTCBDB bdb) $ \bdb' ->
        c_tcbdbtune bdb' lmemb nmemb bnum apow fpow (combineTuningOption opts)

-- | Set the caching parameters.
setcache :: BDB   -- ^ BDB object
         -> Int32 -- ^ the maximum number of leaf nodes to be cached.
         -> Int32 -- ^ the maximum number of non-leaf nodes to be cached.
         -> IO Bool -- ^ if successful, the return value is True.
setcache bdb lcnum ncnum =
    withForeignPtr (unTCBDB bdb) $ \bdb' -> c_tcbdbsetcache bdb' lcnum ncnum

-- | Set the size of extra mapped memory.
setxmsiz :: BDB -> Int64 -> IO Bool
setxmsiz bdb xmsiz =
    withForeignPtr (unTCBDB bdb) $ \bdb' -> c_tcbdbsetxmsiz bdb' xmsiz

-- | Open BDB database file.
open :: BDB -> String -> [OpenMode] -> IO Bool
open = openHelper c_tcbdbopen unTCBDB combineOpenMode

-- | Close the database file.
close :: BDB -> IO Bool
close bdb = withForeignPtr (unTCBDB bdb) c_tcbdbclose

-- | Stora a record (key-value pair) on BDB.  Key and value type must
-- be instance of Storable class.  Usually, we can use `String',
-- `ByteString' for key, `String', `ByteString', `Int', `Double' for
-- value.
put :: (Storable k, Storable v) => BDB -> k -> v -> IO Bool
put = putHelper c_tcbdbput unTCBDB

-- | Store a new record. If a record with the same key exists in the
-- database, this function has no effect.
putkeep :: (Storable k, Storable v) => BDB -> k -> v -> IO Bool
putkeep = putHelper c_tcbdbputkeep unTCBDB

-- | Concatenate a value at the end of the existing record.
putcat :: (Storable k, Storable v) => BDB -> k -> v -> IO Bool
putcat = putHelper c_tcbdbputcat unTCBDB

-- | Store a record with allowing duplication of keys. 
putdup :: (Storable k, Storable v) => BDB -> k -> v -> IO Bool
putdup = putHelper c_tcbdbputdup unTCBDB

-- | Store records with allowing duplication of keys. 
putlist :: (Storable k, Storable v, Sequence q) =>
           BDB -> k -> q v -> IO Bool
putlist bdb key vals =
    withForeignPtr (unTCBDB bdb) $ \bdb' ->
        withList vals $ \tcls ->
            withPtrLen key $ \(kbuf, ksize) ->
                alloca $ \sizbuf -> do
                    num <- c_tclistnum tcls
                    putlist' bdb' (kbuf, ksize) tcls sizbuf num
    where
      putlist' bdb' (kbuf, ksize) tcls sizbuf = put' 0
          where
            put' n num
                | n < num = do vbuf  <- c_tclistval tcls n sizbuf
                               vsize <- fromIntegral `fmap` peek sizbuf
                               res <- c_tcbdbputdup bdb' kbuf ksize vbuf vsize
                               if res then put' (n+1) num else return False
                | otherwise = return True

-- | Delete a record. If the key of duplicated records is specified,
-- the first one is deleted. 
out :: (Storable k) => BDB -> k -> IO Bool
out = outHelper c_tcbdbout unTCBDB

-- | Delete records. If the key of duplicated records is specified,
-- all of them are deleted.
outlist :: (Storable k) => BDB -> k -> IO Bool
outlist = outHelper c_tcbdbout3 unTCBDB

-- | Return the value of record. If the key of duplicated records is
-- specified, the first one is returned.
get :: (Storable k, Storable v) => BDB -> k -> IO (Maybe v)
get = getHelper c_tcbdbget unTCBDB

-- | Retrieve records. 
getlist :: (Storable k, Storable v, Sequence q) => BDB -> k -> IO (q v)
getlist bdb key =
    withForeignPtr (unTCBDB bdb) $ \bdb' ->
        withPtrLen key $ \(kbuf, ksize) -> do
          ptr <- c_tcbdbget4 bdb' kbuf ksize
          if ptr == nullPtr
            then empty
            else peekList' ptr

-- | Return the number of records corresponding to a key. 
vnum :: (Storable k) => BDB -> k -> IO (Maybe Int)
vnum bdb key =
    withForeignPtr (unTCBDB bdb) $ \bdb' ->
        withPtrLen key $ \(kbuf, ksize) -> do
            res <- c_tcbdbvnum bdb' kbuf ksize
            return $ if res == 0
                       then Nothing
                       else Just $ fromIntegral res

-- | Return the size of the value of a record. If the key of duplicated
-- records is specified, the first one is selected.
vsiz :: (Storable k) => BDB -> k -> IO (Maybe Int)
vsiz = vsizHelper c_tcbdbvsiz unTCBDB

-- | Return list of keys in the specified range.
range :: (Storable k, Sequence q) =>
         BDB     -- ^ BDB object
      -> Maybe k -- ^ the key of the beginning border. If it is
                 -- Nothing, the first record in the database is
                 -- specified.
      -> Bool    -- ^ whether the beginning border is inclusive or not. 
      -> Maybe k -- ^ the key of the ending border. If it is Nothing,
                 -- the last record is specified.
      -> Bool    -- ^ whether the ending border is inclusive or not.
      -> Int     -- ^ the maximum number of keys to be fetched. If it
                 -- is negative value, no limit is specified.
      -> IO (q k)  -- ^ keys in the specified range.
range bdb bkey binc ekey einc maxn =
    withForeignPtr (unTCBDB bdb) $ \bdb' ->
        withPtrLen' bkey $ \(bkbuf, bksiz) ->
        withPtrLen' ekey $ \(ekbuf, eksiz) ->
            c_tcbdbrange bdb' bkbuf bksiz binc ekbuf eksiz einc
                             (fromIntegral maxn) >>= peekList'
    where
      withPtrLen' (Just key) action = withPtrLen key action
      withPtrLen' Nothing action = action (nullPtr, 0)

-- | Return list of forward matched keys.
fwmkeys :: (Storable k1, Storable k2, Sequence q) =>
           BDB    -- ^ BDB object
        -> k1     -- ^ search string
        -> Int    -- ^ the maximum number of keys to be fetched. If it
                  -- is negative value, no limit is specified.
        -> IO (q k2) -- ^ keys matches specified string (in forward matching).
fwmkeys = fwmHelper c_tcbdbfwmkeys unTCBDB

-- | Increment the corresponding value. (The value specified by a key
-- is treated as integer.)
addint :: (Storable k) =>
          BDB   -- ^ BDB object.
       -> k     -- ^ Key.
       -> Int   -- ^ Amount of increment.
       -> IO (Maybe Int) -- ^ If successful, a new value is returned.
addint = addHelper c_tcbdbaddint unTCBDB fromIntegral fromIntegral (== cINT_MIN)

-- | Increment the corresponding value. (The value specified by a key
-- is treated as double.)
adddouble :: (Storable k) =>
             BDB    -- ^ BDB object.
          -> k      -- ^ Key.
          -> Double -- ^ Amount of increment.
          -> IO (Maybe Double) -- ^ If successful, a new value is returned.
adddouble = addHelper c_tcbdbadddouble unTCBDB realToFrac realToFrac isNaN

-- | Synchronize updated contents of a database object with the file
-- and the device.
sync :: BDB -> IO Bool
sync bdb = withForeignPtr (unTCBDB bdb) c_tcbdbsync

-- |  Optimize the file of a B+ tree database object.
optimize :: BDB
         -> Int32 -- ^ the number of members in each leaf page.
         -> Int32 -- ^ the number of members in each non-leaf page.
         -> Int64 -- ^ the number of elements of the bucket array. 
         -> Int8  -- ^ the size of record alignment by power of 2.
         -> Int8  -- ^ the maximum number of elements of the free block
                  -- pool by power of 2.
         -> [TuningOption] -- ^ tuning options
         -> IO Bool -- ^ if successful, the return value is True.
optimize bdb lmemb nmemb bnum apow fpow opts =
    withForeignPtr (unTCBDB bdb) $ \bdb' ->
        c_tcbdboptimize bdb' lmemb nmemb bnum apow fpow
                        (combineTuningOption opts)

-- | Delete all records.
vanish :: BDB -> IO Bool
vanish bdb = withForeignPtr (unTCBDB bdb) c_tcbdbvanish

-- | Copy the database file.
copy :: BDB -> String -> IO Bool
copy = copyHelper c_tcbdbcopy unTCBDB

-- | Begin the transaction.
tranbegin :: BDB -> IO Bool
tranbegin bdb = withForeignPtr (unTCBDB bdb) c_tcbdbtranbegin

-- | Commit the transaction.
trancommit :: BDB -> IO Bool
trancommit bdb = withForeignPtr (unTCBDB bdb) c_tcbdbtrancommit

-- | Abort the transaction.
tranabort :: BDB -> IO Bool
tranabort bdb = withForeignPtr (unTCBDB bdb) c_tcbdbtranabort

-- | Return the file path of currentry opened database.
path :: BDB -> IO (Maybe String)
path = pathHelper c_tcbdbpath unTCBDB

-- | Return the number of records in the database.
rnum :: BDB -> IO Word64
rnum bdb = withForeignPtr (unTCBDB bdb) c_tcbdbrnum

-- | Return the size of the database file.
fsiz :: BDB -> IO Word64
fsiz bdb = withForeignPtr (unTCBDB bdb) c_tcbdbfsiz