PageRenderTime 51ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/Database/TokyoCabinet/FDB.hs

http://github.com/tom-lpsd/tokyocabinet-haskell
Haskell | 268 lines | 167 code | 34 blank | 67 comment | 14 complexity | e6b1bf250577c81673a6dce2af486df2 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. -- | Interface to Fixed-length DBM. See also,
  2. -- <http://tokyocabinet.sourceforge.net/spex-en.html#tcfdbapi> for details
  3. module Database.TokyoCabinet.FDB
  4. (
  5. -- $doc
  6. -- * Constructors
  7. FDB
  8. , ECODE(..)
  9. , OpenMode(..)
  10. , ID(..)
  11. -- * Basic API (tokyocabinet.idl compliant)
  12. , new
  13. , delete
  14. , ecode
  15. , errmsg
  16. , tune
  17. , open
  18. , close
  19. , put
  20. , putkeep
  21. , putcat
  22. , out
  23. , get
  24. , vsiz
  25. , iterinit
  26. , iternext
  27. , range
  28. , fwmkeys
  29. , addint
  30. , adddouble
  31. , sync
  32. , optimize
  33. , vanish
  34. , copy
  35. , path
  36. , rnum
  37. , fsiz
  38. ) where
  39. import Database.TokyoCabinet.Error
  40. import Database.TokyoCabinet.FDB.C
  41. import Database.TokyoCabinet.FDB.Key
  42. import Database.TokyoCabinet.Internal
  43. import Database.TokyoCabinet.Sequence
  44. import Database.TokyoCabinet.Storable
  45. import Foreign.Ptr
  46. import Foreign.ForeignPtr
  47. import Foreign.C.Types
  48. import Foreign.Storable (peek)
  49. import Foreign.Marshal (alloca, free)
  50. import Foreign.Marshal.Array (peekArray)
  51. import Foreign.Marshal.Utils (maybePeek)
  52. import Data.Int
  53. import Data.Word
  54. import Control.Exception
  55. -- $doc
  56. -- Example
  57. --
  58. -- @
  59. -- import Control.Monad
  60. -- import Database.TokyoCabinet.FDB
  61. -- @
  62. --
  63. -- @
  64. -- main = do fdb <- new
  65. -- -- open the database
  66. -- open fdb \"casket.tcf\" [OWRITER, OCREAT] >>= err fdb
  67. -- -- store records
  68. -- puts fdb [(1, \"one\"), (12, \"twelve\"), (144, \"one forty four\")] >>=
  69. -- err fdb . (all id)
  70. -- -- retrieve records
  71. -- get fdb (1 :: Int) >>= maybe (error \"something goes wrong\") putStrLn
  72. -- -- close the database
  73. -- close fdb >>= err fdb
  74. -- where
  75. -- puts :: FDB -> [(Int, String)] -> IO [Bool]
  76. -- puts fdb = mapM (uncurry $ put fdb)
  77. -- @
  78. --
  79. -- @
  80. -- err :: FDB -> Bool -> IO ()
  81. -- err fdb = flip unless $ ecode fdb >>= error . show
  82. -- @
  83. --
  84. data FDB = FDB { unTCFDB :: !(ForeignPtr FDB') }
  85. -- | Create a Fixed-length database object.
  86. new :: IO FDB
  87. new = FDB `fmap` (c_tcfdbnew >>= newForeignPtr tcfdbFinalizer)
  88. -- | Free FDB resource forcibly.
  89. -- FDB is kept by ForeignPtr, so Haskell runtime GC cleans up memory for
  90. -- almost situation. Most always, you don't need to call this.
  91. -- After call this, you must not touch FDB object. Its behavior is undefined.
  92. delete :: FDB -> IO ()
  93. delete fdb = finalizeForeignPtr $ unTCFDB fdb
  94. -- | Return the last happened error code.
  95. ecode :: FDB -> IO ECODE
  96. ecode fdb =
  97. withForeignPtr (unTCFDB fdb) $ \fdb' ->
  98. cintToError `fmap` c_tcfdbecode fdb'
  99. -- | Set the tuning parameters.
  100. tune :: FDB -- ^ FDB object.
  101. -> Int32 -- ^ the width of the value of each record.
  102. -> Int64 -- ^ the limit size of the database file.
  103. -> IO Bool -- ^ if successful, the return value is True.
  104. tune fdb width limsiz =
  105. withForeignPtr (unTCFDB fdb) $ \fdb' -> c_tcfdbtune fdb' width limsiz
  106. -- | Open FDB database file.
  107. open :: FDB -> String -> [OpenMode] -> IO Bool
  108. open = openHelper c_tcfdbopen unTCFDB combineOpenMode
  109. -- | Close the database file.
  110. close :: FDB -> IO Bool
  111. close fdb = withForeignPtr (unTCFDB fdb) c_tcfdbclose
  112. type FunPut' = Ptr FDB' -> Int64 -> Ptr Word8 -> CInt -> IO Bool
  113. putHelper' :: (Key k, Storable v) => FunPut' -> FDB -> k -> v -> IO Bool
  114. putHelper' func fdb key val =
  115. withForeignPtr (unTCFDB fdb) $ \fdb' ->
  116. withPtrLen val $ \(vbuf, vsize) -> do
  117. key' <- keyToInt key
  118. func fdb' key' vbuf vsize
  119. -- | Stora a record (key-value pair) on FDB. Key type must be
  120. -- instance of Key class. Value type must be instance of Storable.
  121. put :: (Key k, Storable v) => FDB -> k -> v -> IO Bool
  122. put = putHelper' c_tcfdbput
  123. -- | Store a new record. If a record with the same key exists in the
  124. -- database, this function has no effect.
  125. putkeep :: (Key k, Storable v) => FDB -> k -> v -> IO Bool
  126. putkeep = putHelper' c_tcfdbputkeep
  127. -- | Concatenate a value at the end of the existing record.
  128. putcat :: (Key k, Storable v) => FDB -> k -> v -> IO Bool
  129. putcat = putHelper' c_tcfdbputcat
  130. -- | Delete a record.
  131. out :: (Key k) => FDB -> k -> IO Bool
  132. out fdb key =
  133. withForeignPtr (unTCFDB fdb) $ \fdb' ->
  134. c_tcfdbout fdb' =<< keyToInt key
  135. -- | Return the value of record.
  136. get :: (Key k, Storable v) => FDB -> k -> IO (Maybe v)
  137. get fdb key =
  138. withForeignPtr (unTCFDB fdb) $ \fdb' ->
  139. alloca $ \sizbuf -> do
  140. key' <- keyToInt key
  141. vbuf <- c_tcfdbget fdb' key' sizbuf
  142. vsize <- peek sizbuf
  143. flip maybePeek vbuf $ \vbuf' -> peekPtrLen (vbuf', vsize)
  144. -- | Return the byte size of value in a record.
  145. vsiz :: (Key k) => FDB -> k -> IO (Maybe Int)
  146. vsiz fdb key =
  147. withForeignPtr (unTCFDB fdb) $ \fdb' -> do
  148. vsize <- c_tcfdbvsiz fdb' =<< keyToInt key
  149. return $ if vsize == (-1)
  150. then Nothing
  151. else Just (fromIntegral vsize)
  152. -- | Initialize the iterator of a FDB object.
  153. iterinit :: FDB -> IO Bool
  154. iterinit fdb = withForeignPtr (unTCFDB fdb) c_tcfdbiterinit
  155. -- | Return the next key of the iterator of a FDB object.
  156. iternext :: (Key k) => FDB -> IO (Maybe k)
  157. iternext fdb =
  158. withForeignPtr (unTCFDB fdb) $ \fdb' -> do
  159. i <- c_tcfdbiternext fdb'
  160. return $ if i == 0
  161. then Nothing
  162. else Just (fromID $ ID i)
  163. -- | Return list of keys in the specified range.
  164. range :: (Key k1, Key k2) =>
  165. FDB -- ^ FDB object
  166. -> k1 -- ^ the lower limit of the range.
  167. -> k1 -- ^ the upper limit of the range.
  168. -> Int -- ^ the maximum number of keys to be fetched.
  169. -> IO [k2] -- ^ keys in the specified range.
  170. range fdb lower upper maxn =
  171. withForeignPtr (unTCFDB fdb) $ \fdb' ->
  172. alloca $ \sizbuf -> do
  173. [l, u] <- mapM keyToInt [lower, upper]
  174. rp <- c_tcfdbrange fdb' l u (fromIntegral maxn) sizbuf
  175. size <- fromIntegral `fmap` peek sizbuf
  176. keys <- peekArray size rp
  177. free rp
  178. return $ map (fromID . ID) keys
  179. -- | Return list of forward matched keys.
  180. fwmkeys :: (Storable k1, Storable k2, Sequence q) =>
  181. FDB -> k1 -> Int -> IO (q k2)
  182. fwmkeys fdb k maxn = smap fromString =<< fwmkeys' fdb k maxn
  183. where fwmkeys' = fwmHelper c_tcfdbrange4 unTCFDB
  184. -- | Increment the corresponding value. (The value specified by a key
  185. -- is treated as integer.)
  186. addint :: (Key k) => FDB -> k -> Int -> IO (Maybe Int)
  187. addint fdb key num =
  188. withForeignPtr (unTCFDB fdb) $ \fdb' -> do
  189. key' <- keyToInt key
  190. sumval <- c_tcfdbaddint fdb' key' (fromIntegral num)
  191. return $ if sumval == cINT_MIN
  192. then Nothing
  193. else Just $ fromIntegral sumval
  194. -- | Increment the corresponding value. (The value specified by a key
  195. -- is treated as double.)
  196. adddouble :: (Key k) => FDB -> k -> Double -> IO (Maybe Double)
  197. adddouble fdb key num =
  198. withForeignPtr (unTCFDB fdb) $ \fdb' -> do
  199. key' <- keyToInt key
  200. sumval <- c_tcfdbadddouble fdb' key' (realToFrac num)
  201. return $ if isNaN sumval
  202. then Nothing
  203. else Just $ realToFrac sumval
  204. -- | Synchronize updated contents of a database object with the file
  205. -- and the device.
  206. sync :: FDB -> IO Bool
  207. sync fdb = withForeignPtr (unTCFDB fdb) c_tcfdbsync
  208. -- | Optimize the file of a Hash database object.
  209. optimize :: FDB -> Int32 -> Int64 -> IO Bool
  210. optimize fdb width limsiz =
  211. withForeignPtr (unTCFDB fdb) $ \fdb' -> c_tcfdboptimize fdb' width limsiz
  212. -- | Delete all records.
  213. vanish :: FDB -> IO Bool
  214. vanish fdb = withForeignPtr (unTCFDB fdb) c_tcfdbvanish
  215. -- | Copy the database file.
  216. copy :: FDB -> String -> IO Bool
  217. copy = copyHelper c_tcfdbcopy unTCFDB
  218. -- | Return the file path of currentry opened database.
  219. path :: FDB -> IO (Maybe String)
  220. path = pathHelper c_tcfdbpath unTCFDB
  221. -- | Return the number of records in the database.
  222. rnum :: FDB -> IO Word64
  223. rnum fdb = withForeignPtr (unTCFDB fdb) c_tcfdbrnum
  224. -- | Return the size of the database file.
  225. fsiz :: FDB -> IO Word64
  226. fsiz fdb = withForeignPtr (unTCFDB fdb) c_tcfdbfsiz
  227. keyToInt :: (Key k) => k -> IO Int64
  228. keyToInt i = catchJust selector (evaluate (unID . toID $ i)) handler
  229. where
  230. selector :: ErrorCall -> Maybe ()
  231. selector e = if show e == "Prelude.read: no parse"
  232. then Just ()
  233. else Nothing
  234. handler _ = error "Database.TokyoCabinet.FDB: invalid key"