TCache 0.10.0.0 → 0.10.0.1
raw patch · 8 files changed
+93/−83 lines, 8 files
Files
- Data/Persistent/Collection.hs +22/−25
- Data/TCache/DefaultPersistence.hs +6/−26
- Data/TCache/Defs.hs +23/−11
- Data/TCache/IResource.hs +12/−10
- Data/TCache/IndexQuery.hs +15/−3
- Data/TCache/IndexText.hs +1/−0
- Data/TCache/Memoization.hs +7/−6
- TCache.cabal +7/−2
Data/Persistent/Collection.hs view
@@ -7,16 +7,13 @@ -XUndecidableInstances -XFunctionalDependencies -- -IControl/Workflow- #-} {- |-This module implements a persistent, transactional collection with Queue interface as well as+A persistent, transactional collection with Queue interface as well as indexed access by key. - The Queue uses default persistence. See "Data.TCache.DefaultPersistence"+ Uses default persistence. See "Data.TCache.DefaultPersistence" -} @@ -77,7 +74,7 @@ serialize = runW . showp deserialize = runR readp --- | a queue reference+-- | A queue reference type RefQueue a= DBRef (Queue a) unreadSTM :: (Typeable a, Serialize a) => RefQueue a -> a -> STM ()@@ -88,7 +85,7 @@ doit (Queue n imp out) = Queue n imp ( x : out) --- | check if the queue is empty+-- | Check if the queue is empty isEmpty :: (Typeable a, Serialize a) => RefQueue a -> IO Bool isEmpty = atomically . isEmptySTM @@ -102,20 +99,20 @@ --- | get the reference to new or existing queue trough its name+-- | Get the reference to new or existing queue trough its name getQRef :: (Typeable a, Serialize a) => String -> RefQueue a getQRef n = getDBRef . key $ Queue n undefined undefined --- | empty the queue (factually, it is deleted)+-- | Empty the queue (factually, it is deleted) flush :: (Typeable a, Serialize a) => RefQueue a -> IO () flush = atomically . flushSTM --- | version in the STM monad+-- | Version in the STM monad flushSTM :: (Typeable a, Serialize a) => RefQueue a -> STM () flushSTM tv= delDBRef tv --- | read the first element in the queue and delete it (pop)+-- | Read the first element in the queue and delete it (pop) pop :: (Typeable a, Serialize a) => RefQueue a -- ^ Queue name -> IO a -- ^ the returned elems@@ -133,7 +130,7 @@ Just dx -> return dx --- | version in the STM monad+-- | Version in the STM monad popSTM :: (Typeable a, Serialize a) => RefQueue a -> STM a popSTM tv=do@@ -151,7 +148,7 @@ writeDBRef tv (Queue n imp (Prelude.tail list )) return $ Prelude.head list --- | read the first element in the queue but it does not delete it+-- | Read the first element in the queue but it does not delete it pick :: (Typeable a, Serialize a) => RefQueue a -- ^ Queue name -> IO a -- ^ the returned elems@@ -164,30 +161,30 @@ doit (Queue n imp []) = doit (Queue n [] $ Prelude.reverse imp) doit (Queue n imp list ) = return $ Prelude.head list --- | push an element in the queue+-- | Push an element in the queue push :: (Typeable a, Serialize a) => RefQueue a -> a -> IO () push tv v = atomically $ pushSTM tv v --- | version in the STM monad+-- | Version in the STM monad pushSTM :: (Typeable a, Serialize a) => RefQueue a -> a -> STM () pushSTM tv v= readQRef tv >>= \ ((Queue n imp out)) -> writeDBRef tv $ Queue n (v : imp) out --- | return the list of all elements in the queue. The queue remains unchanged+-- | Return the list of all elements in the queue. The queue remains unchanged pickAll :: (Typeable a, Serialize a) => RefQueue a -> IO [a] pickAll= atomically . pickAllSTM --- | version in the STM monad+-- | Version in the STM monad pickAllSTM :: (Typeable a, Serialize a) => RefQueue a -> STM [a] pickAllSTM tv= do (Queue name imp out) <- readQRef tv return $ out ++ Prelude.reverse imp --- | return the first element in the queue that has the given key+-- | Return the first element in the queue that has the given key pickElem ::(Indexable a,Typeable a, Serialize a) => RefQueue a -> String -> IO(Maybe a) pickElem tv key= atomically $ pickElemSTM tv key --- | version in the STM monad+-- | Version in the STM monad pickElemSTM :: (Indexable a,Typeable a, Serialize a) => RefQueue a -> String -> STM(Maybe a) pickElemSTM tv key1= do@@ -198,12 +195,12 @@ [] -> return $ Nothing (x:_) -> return $ Just x --- | update the first element of the queue with a new element with the same key+-- | Update the first element of the queue with a new element with the same key updateElem :: (Indexable a,Typeable a, Serialize a) => RefQueue a -> a -> IO() updateElem tv x = atomically $ updateElemSTM tv x --- | version in the STM monad+-- | Version in the STM monad updateElemSTM :: (Indexable a,Typeable a, Serialize a) => RefQueue a -> a -> STM() updateElemSTM tv v= do@@ -214,22 +211,22 @@ where n= key v --- | return the list of all elements in the queue and empty it+-- | Return the list of all elements in the queue and empty it readAll :: (Typeable a, Serialize a) => RefQueue a -> IO [a] readAll= atomically . readAllSTM --- | a version in the STM monad+-- | A version in the STM monad readAllSTM :: (Typeable a, Serialize a) => RefQueue a -> STM [a] readAllSTM tv= do Queue name imp out <- readQRef tv writeDBRef tv $ Queue name [] [] return $ out ++ Prelude.reverse imp --- | delete all the elements of the queue that has the key of the parameter passed+-- | Delete all the elements of the queue that has the key of the parameter passed deleteElem :: (Indexable a,Typeable a, Serialize a) => RefQueue a-> a -> IO () deleteElem tv x= atomically $ deleteElemSTM tv x --- | verison in the STM monad+-- | Verison in the STM monad deleteElemSTM :: (Typeable a, Serialize a,Indexable a) => RefQueue a-> a -> STM () deleteElemSTM tv x= do Queue name imp out <- readQRef tv
Data/TCache/DefaultPersistence.hs view
@@ -1,18 +1,15 @@-{- |--This module decouples the interface of 'IResource" class in two classes-one for key extraction 'Indexable' and other ('Serializable" for serlalization and persistence-.This last one defines persistence in files as default, but it can be changed-to persistence in databases, for examople.---} {-# LANGUAGE FlexibleInstances, UndecidableInstances , MultiParamTypeClasses, FunctionalDependencies , ExistentialQuantification , ScopedTypeVariables- #-}++{- | This module decouples the 'IResource" class in two classes+ one for key extraction 'Indexable' and other ('Serializable" for serlalization and persistence+ .The last one defines persistence in files as default, but it can be changed+ to persistence in databases, for examople.+-} module Data.TCache.DefaultPersistence(Indexable(..),Serializable(..),defaultPersist,Persist(..)) where import System.IO.Unsafe@@ -22,23 +19,6 @@ import Data.TCache --{- | Indexable is an utility class used to derive instances of IResource--Example:--@data Person= Person{ pname :: String, cars :: [DBRef Car]} deriving (Show, Read, Typeable)-data Car= Car{owner :: DBRef Person , cname:: String} deriving (Show, Read, Eq, Typeable)-@--Since Person and Car are instances of 'Read' ans 'Show', by defining the 'Indexable' instance-will implicitly define the IResource instance for file persistence:--@-instance Indexable Person where key Person{pname=n} = \"Person \" ++ n-instance Indexable Car where key Car{cname= n} = \"Car \" ++ n-@--} instance (Typeable a, Indexable a, Serializable a ) => IResource a where
Data/TCache/Defs.hs view
@@ -46,22 +46,33 @@ Just x -> x +{- | Indexable is an utility class used to derive instances of IResource++Example:++@data Person= Person{ pname :: String, cars :: [DBRef Car]} deriving (Show, Read, Typeable)+data Car= Car{owner :: DBRef Person , cname:: String} deriving (Show, Read, Eq, Typeable)+@++Since Person and Car are instances of 'Read' ans 'Show', by defining the 'Indexable' instance+will implicitly define the IResource instance for file persistence:++@+instance Indexable Person where key Person{pname=n} = \"Person \" ++ n+instance Indexable Car where key Car{cname= n} = \"Car \" ++ n+@+-} class Indexable a where key:: a -> String defPath :: a -> String -- ^ additional extension for default file paths.- -- The default value is "data/".- -- IMPORTANT: defPath must depend on the datatype, not the value (must be constant). Default is "TCacheData/" defPath = const "TCacheData/" --instance IResource a => Indexable a where -- key x= keyResource x -{- | Serialize is an abstract serialization ionterface in order to define implicit instances of IResource.-The deserialization must be as lazy as possible if deserialized objects contain DBRefs,-lazy deserialization avoid unnecesary DBRef instantiations when they are not accessed,-since DBRefs instantiations involve extra cache lookups-For this reason serialization/deserialization is to/from ordinary Strings+{- | Serialize is an alternative to the IResource class for defining persistence in TCache.+The deserialization must be as lazy as possible. serialization/deserialization are not performance critical in TCache Read, Show, instances are implicit instances of Serializable@@ -69,13 +80,13 @@ > serialize = show > deserialize= read -Since write and read to disk of to/from the cache must not be very often+Since write and read to disk of to/from the cache are not be very frequent The performance of serialization is not critical. -} class Serializable a where serialize :: a -> B.ByteString deserialize :: B.ByteString -> a- setPersist :: a -> Persist+ setPersist :: a -> Persist -- ^ `defaultPersist`if not overriden setPersist _= defaultPersist --instance (Show a, Read a)=> Serializable a where@@ -86,10 +97,11 @@ -- | a persist mechanism has to implement these three primitives -- 'defaultpersist' is the default file persistence data Persist = Persist{- readByKey :: (String -> IO(Maybe B.ByteString)) -- ^ read by key- , write :: (String -> B.ByteString -> IO()) -- ^ write+ readByKey :: (String -> IO(Maybe B.ByteString)) -- ^ read by key. It must be strict+ , write :: (String -> B.ByteString -> IO()) -- ^ write. It must be strict , delete :: (String -> IO())} -- ^ delete +-- | Implements default persistence of objects in files with their keys as filenames defaultPersist= Persist {readByKey= defaultReadByKey ,write= defaultWrite
Data/TCache/IResource.hs view
@@ -15,7 +15,7 @@ import Data.List(isInfixOf) -{- | must be defined for every object to be cached.+{- | Must be defined for every object to be cached. -} class IResource a where {- The `keyResource string must be a unique since this is used to index it in the hash table. @@ -37,29 +37,31 @@ -} keyResource :: a -> String -- ^ must be defined - {- | 'readResourceByKey' implements the database access and marshalling or of the object.+ {- | Implements the database access and marshalling of the object. while the database access must be strict, the marshaling must be lazy if, as is often the case, some parts of the object are not really accesed.- Moreover, if the object contains DBRefs, this avoids unnecesary cache lookups.- This method is called inside 'atomically' blocks and thus may be interrupted without calling+ If the object contains DBRefs, this avoids unnecesary cache lookups.+ This method is called inside 'atomically' blocks. Since STM transactions retry, readResourceByKey may be called twice in strange situations. So it must be idempotent, not only in the result but also in the effect in the database+ . However, because it is executed by 'safeIOToSTM' it is guaranteed that the execution is not interrupted. -} readResourceByKey :: String -> IO(Maybe a) - -- To permit accesses not by key. (it defaults as readResourceByKey)+ -- To allow accesses not by key. (it defaults as @readResourceByKey $ keyResource x@) readResource :: a -> IO (Maybe a) readResource x = readResourceByKey $ keyResource x - -- | The write operation in persistent storage. It must be strict. + -- | To write into persistent storage. It must be strict. -- Since STM transactions may retry, @writeResource@ must be idempotent, not only in the result but also in the effect in the database.- -- All the new obbects are writeen to the database on synchromization- -- so writeResource when using a database for persistence must not autocommit.+ -- . However, because it is executed by 'safeIOToSTM' it is guaranteed that the execution is not interrupted.+ -- All the new obbects are writeen to the database on synchromization,+ -- so writeResource must not autocommit. -- Commit code must be located in the postcondition. (see `setConditions`)- -- Since there is no provision for rollback from failure in writing fromIDyn+ -- Since there is no provision for rollback from failure in writing to -- persistent storage, 'writeResource' must retry until success. writeResource:: a-> IO() - -- | Delete the resource. It is called syncronously. It must autocommit + -- | Delete the resource. It is called syncronously. So it must tocommit delResource:: a-> IO()
Data/TCache/IndexQuery.hs view
@@ -76,7 +76,7 @@ module Data.TCache.IndexQuery(index, RelationOps(..), indexOf, recordsWith, (.&&.), (.||.), Select(..)) where import Data.TCache-import Data.TCache.DefaultPersistence+import Data.TCache.Defs import Data.List import Data.Typeable import Control.Concurrent.STM@@ -87,8 +87,22 @@ import System.IO.Unsafe import Data.ByteString.Lazy.Char8(pack, unpack) +class (Read reg, Read a, Show reg, Show a+ , IResource reg,Typeable reg+ , Typeable a,Ord a)+ => Queriable reg a +instance (Read reg, Read a, Show reg, Show a+ , IResource reg,Typeable reg+ , Typeable a,Ord a)+ => Queriable reg a +instance Queriable reg a => IResource (Index reg a) where+ keyResource = key+ writeResource =defWriteResource+ readResourceByKey = defReadResourceByKey+ delResource = defDelResource+ data Index reg a= Index (M.Map a [DBRef reg]) deriving ( Show, Typeable) instance (IResource reg, Typeable reg,Read reg,Show reg, Show a, Read a, Ord a)@@ -97,8 +111,6 @@ = map (\(r,s) -> (Index r, s)) rs where rs= readsPrec n str readsPrec _ s= error $ "indexQuery: can not read index: \""++s++"\"" -class (Read reg, Read a, Show reg, Show a, IResource reg,Typeable reg, Typeable a,Ord a) => Queriable reg a-instance (Read reg, Read a, Show reg, Show a, IResource reg,Typeable reg, Typeable a,Ord a) => Queriable reg a instance (Queriable reg a) => Serializable (Index reg a) where serialize= pack . show
Data/TCache/IndexText.hs view
@@ -153,6 +153,7 @@ t= show t1 ++ show t2 refIndex= getDBRef . key $ IndexText t u u u u where u= undefined +-- | return the DBRefs whose fields (usually of container type) contains the requested value. containsElem :: (IResource a, Typeable a, Typeable b) => (a -> b) -> String -> STM [DBRef a] containsElem sel wstr = do let w= T.pack wstr
Data/TCache/Memoization.hs view
@@ -37,18 +37,19 @@ -- | return a string identifier for any object-addrStr :: a -> IO String+addrStr :: MonadIO m => a -> m String addrStr x = addrHash x >>= return . show -- | return a hash of an object---addrHash :: a -> Int+addrHash :: MonadIO m => a -> m Int+ {-# NOINLINE addrHash #-} addrHash x= liftIO $ do st <- makeStableName $! x return $ hashStableName st -+-- | to execute a monad for the purpose of memoizing its result class Executable m where execute:: m a -> a @@ -93,10 +94,10 @@ cached time f a else return b --- | memoize the result of a computation for a certain time. Instead of a paramter,--- like in the case of 'cached', a string 'key' is used to index the result+-- | Memoize the result of a computation for a certain time. A string 'key' is used to index the result ----- time == 0 means infinite+-- The Int parameter is the timeout, in second after the last evaluation, after which the cached value will be discarded and the expression will be evaluated again if demanded+-- . Time == 0 means no timeout cachedByKey :: (Typeable a, Executable m,MonadIO m) => String -> Int -> m a -> m a cachedByKey key time f = cached time (\_ -> f) key
TCache.cabal view
@@ -1,5 +1,5 @@ name: TCache-version: 0.10.0.0+version: 0.10.0.1 cabal-version: >= 1.6 build-type: Simple license: BSD3@@ -8,8 +8,13 @@ synopsis: A Transactional cache with user-defined persistence description: TCache is a transactional cache with configurable persitence. It allows conventional STM transactions for objects that syncronize with- their user defined storages. Default persistence in files is provided for testing purposes+ their user defined storages. State in memory and into permanent storage is transactionally coherent.+ .+ The package implements serializable STM references, access by key and by record field value, triggers,+ full text and field indexation, default serialization and a query language based on record fields+ .+ This version add memoization and a persistent and transactional collection/queue . See "Data.TCache" for details