-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Data caching and Persistent STM transactions -- -- 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 -- -- This version support the backward compatible stuff, that permits -- transparent retrievals of objects and transcactions between objects -- without directly using STM references ('with*Resource(s)' calls), Now -- it goes in the oposite direction by providing explicit STM persistent -- references (called 'DBRefÅ›') that leverage the nice and traditional -- haskell reference syntax for performing database transactions. -- -- DBRefs are in essence, persistent TVars indexed in the cache, -- with a traditional readDBRef, writeDBRef Haskell -- interface in the STM monad. Additionally, because DBRefs are -- serializable, they can be embeded in serializable registers. Because -- they are references,they point to other serializable registers. This -- permits persistent mutable and efficient Inter-object relations. -- -- Triggers are also included in this release. They are user defined -- hooks that are called back on register updates. That can be used for -- easing the actualization of inter-object relations and also permit -- more higuer level and customizable accesses. The internal indexes used -- for the query language uses triggers. -- -- It also implements an straighforwards non-intrusive pure-haskell type -- safe query language based on register field relations. This module -- must be imported separately. See Data.TCache.IndexQuery for -- further information -- -- Now the file persistence is more reliable.The IO reads are safe inside -- STM transactions. -- -- To ease the implementation of other user-defined persistence, -- Data.TCache.FIlePersistence needed to be imported explcitly for -- deriving file persistence instances. -- -- In this release some stuff has been supressed without losing -- functionality. Dynamic interfaces are not needed since TCache can -- handle heterogeneous data. @package TCache @version 0.8.0.2 module Data.TCache.IResource -- | An IResource instance that must be defined for every object being -- cached. there are a set of implicit IResource instance trough utiliy -- classes (See below) class IResource a keyResource :: IResource a => a -> String readResourceByKey :: IResource a => String -> IO (Maybe a) writeResource :: IResource a => a -> IO () delResource :: IResource a => a -> IO () -- | Resources data definition used by withSTMResources data Resources a b -- | forces a retry Retry :: Resources a b Resources :: [a] -> [a] -> b -> Resources a b -- | resources to be inserted back in the cache toAdd :: Resources a b -> [a] -- | resources to be deleted from the cache and from permanent storage toDelete :: Resources a b -> [a] -- | result to be returned toReturn :: Resources a b -> b -- | Empty resources: resources= Resources [] [] () resources :: Resources a () -- | 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
key :: Indexable a => a -> String
defPath :: Indexable a => a -> String
-- | 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 serializationdeserialization is tofrom ordinary
-- Strings serialization/deserialization are not performance critical in
-- TCache
class Serializable a
serialize :: Serializable a => a -> String
deserialize :: Serializable a => String -> a
defaultReadResource :: (Serializable a, Indexable a, Typeable a) => a -> IO (Maybe a)
defaultReadResourceByKey :: (Serializable a, Indexable a) => String -> IO (Maybe a)
defaultWriteResource :: (Serializable a, Indexable a) => a -> IO ()
defaultDelResource :: Indexable a => a -> IO ()
module Data.TCache.FilePersistence
instance (Serializable a, Indexable a) => IResource a
instance (Show a, Read a) => Serializable a
module Data.TCache.Defs
type AccessTime = Integer
type ModifTime = Integer
data Status a
NotRead :: Status a
DoNotExist :: Status a
Exist :: a -> Status a
data Elem a
Elem :: a -> AccessTime -> ModifTime -> Elem a
type TPVar a = TVar (Status (Elem a))
data DBRef a
DBRef :: String -> (TPVar a) -> DBRef a
instance Typeable1 Status
instance Typeable1 Elem
instance Typeable1 DBRef
module Data.TCache.Triggers
data DBRef a
DBRef :: String -> (TPVar a) -> DBRef a
data Elem a
Elem :: a -> AccessTime -> ModifTime -> Elem a
data Status a
NotRead :: Status a
DoNotExist :: Status a
Exist :: a -> Status a
-- | Add an user defined trigger to the list of triggers Trriggers are
-- called just before an object of the given type is created, modified or
-- deleted. The DBRef to the object and the new value is passed to the
-- trigger. The called trigger function has two parameters: the DBRef
-- being accesed (which still contains the old value), and the new value.
-- If the content of the DBRef is being deleted, the second parameter is
-- Nothing. if the DBRef contains Nothing, then the object is
-- being created
addTrigger :: (IResource a, Typeable a) => ((DBRef a) -> Maybe a -> STM ()) -> IO ()
applyTriggers :: (IResource a, Typeable a) => [DBRef a] -> [Maybe a] -> STM ()
instance Typeable1 TriggerType
-- | TCache is a transactional cache with configurable persitence that
-- permits STM transactions with objects thar syncronize sincromous or
-- asyncronously with their user defined storages. Default persistence in
-- files is provided for testing purposes
--
-- In this release some stuff has been supressed without losing
-- functionality. Dynamic interfaces are not needed since TCache can
-- handle heterogeneous data. The new things in this release, besides the
-- backward compatible stuf are:
--
-- TCache now implements. ''DBRef' 's . They are persistent STM
-- references with a traditional readDBRef, writeDBRef
-- Haskell interface. simitar to TVars, but with aded. persistence
-- Additionally, because DBRefs are serializable, they can be embeded in
-- serializable registers. Because they are references,they point to
-- other serializable registers. This permits persistent mutable
-- Inter-object relations
--
-- Triggers are user defined hooks that are called back on register
-- updates. That can be used for:
--
--
-- 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
key :: Indexable a => a -> String
defPath :: Indexable a => a -> String
-- | Empty resources: resources= Resources [] [] ()
resources :: Resources a ()
-- | This is the main function for the *Resource(s) calls. All the rest
-- derive from it. The results are kept in the STM monad so it can be
-- part of a larger STM transaction involving other DBRefs The
-- Resources register returned by the user-defined function is
-- interpreted as such:
--
-- -- withResource r f= withResources [r] ([mr]-> [f mr]) --withResource :: (IResource a, Typeable a) => a -> (Maybe a -> a) -> IO () getResources :: (IResource a, Typeable a) => [a] -> IO [Maybe a] -- | to read a resource from the cache. getResource :: (IResource a, Typeable a) => a -> IO (Maybe a) -- | delete the list of resources from cache and from persistent storage. deleteResources :: (IResource a, Typeable a) => [a] -> IO () -- | delete the resource from cache and from persistent storage. -- deleteResource r= deleteResources [r] deleteResource :: (IResource a, Typeable a) => a -> IO () -- | Add an user defined trigger to the list of triggers Trriggers are -- called just before an object of the given type is created, modified or -- deleted. The DBRef to the object and the new value is passed to the -- trigger. The called trigger function has two parameters: the DBRef -- being accesed (which still contains the old value), and the new value. -- If the content of the DBRef is being deleted, the second parameter is -- Nothing. if the DBRef contains Nothing, then the object is -- being created addTrigger :: (IResource a, Typeable a) => ((DBRef a) -> Maybe a -> STM ()) -> IO () -- | deletes the pointed object from the cache, not the database (see -- delDBRef) useful for cache invalidation when the database is -- modified by other process flushDBRef :: (IResource a, Typeable a) => DBRef a -> STM () -- | drops the entire cache. flushAll :: STM () type Cache = IORef (Ht, Integer) -- | set the cache. this is useful for hot loaded modules that will update -- an existing cache. Experimental setCache :: Cache -> IO () -- | newCache creates a new cache. Experimental newCache :: IO (Ht, Integer) refcache :: Cache -- | Force the atomic write of all cached objects modified since the last -- save into permanent storage Cache writes allways save a coherent state syncCache :: IO () -- | stablishes the procedures to call before and after saving with -- syncCache, clearSyncCache or clearSyncCacheProc. -- The postcondition of database persistence should be a commit. setConditions :: IO () -> IO () -> IO () -- | Saves the unsaved elems of the cache Cache writes allways save a -- coherent state delete some elems of the cache when the number of elems -- > sizeObjects. The deletion depends on the check criteria. -- defaultCheck is the one implemented clearSyncCache :: (Integer -> Integer -> Integer -> Bool) -> Int -> IO () -- | return the total number of DBRefs in the cache. For debug purposes -- This does not count the number of objects in the cache since many of -- the DBRef may not have the pointed object loaded. It O(n). numElems :: IO Int -- | Start the thread that periodically call clearSyncCache to clean -- and writes on the persistent storage. Otherwise, syncCache must -- be invoked explicitly or no persistence will exist. Cache writes -- allways save a coherent state clearSyncCacheProc :: Int -> (Integer -> Integer -> Integer -> Bool) -> Int -> IO ThreadId -- | ths is a default cache clearance check. It forces to drop from the -- cache all the elems not accesed since half the time between now and -- the last sync if it returns True, the object will be discarded from -- the cache it is invoked when the cache size exceeds the number of -- objects configured in clearSyncCacheProc or -- clearSyncCache defaultCheck :: Integer -> Integer -> Integer -> Bool readFileStrict :: FilePath -> IO [Char] defaultReadResource :: (Serializable a, Indexable a, Typeable a) => a -> IO (Maybe a) defaultReadResourceByKey :: (Serializable a, Indexable a) => String -> IO (Maybe a) defaultWriteResource :: (Serializable a, Indexable a) => a -> IO () defaultDelResource :: Indexable a => a -> IO () instance Ord (DBRef a) instance Eq (DBRef a) instance (IResource a, Typeable a) => Read (DBRef a) instance Show (DBRef a) -- | This module implements an experimental typed query language for TCache -- build on pure haskell. It is minimally intrusive (no special data -- definitions, no special syntax, no template haskell). It uses the same -- register fields from the data definitions. Both for query conditions -- and selections. It is executed in haskell, no external database -- support is needed. -- -- it includes -- --
-- import Data.TCache
-- import Data.TCache.IndexQuery
-- import Data.TCache.FilePersistence
-- import Data.Typeable
--
-- data Person= Person {pname :: String} deriving (Show, Read, Eq, Typeable)
-- data Car= Car{owner :: DBRef Person , cname:: String} deriving (Show, Read, Eq, Typeable)
--
-- instance Indexable Person where key Person{pname= n} = "Person " ++ n
-- instance Indexable Car where key Car{cname= n} = "Car " ++ n
--
-- main = do
-- index owner
-- index pname
-- index cname
-- bruce <- atomically $ newDBRef $ Person "bruce"
-- atomically $ mapM_ newDBRef [Car bruce "Bat Mobile", Car bruce "Porsche"]
-- r <- atomically $ cname .==. "Porsche"
-- print r
-- r <- atomically $ select (cname, owner) $ (owner .==. bruce) .&&. (cname .>=. "Bat Mobile")
-- print r
--
--
-- Will produce:
--
--
-- [DBRef "Car Porsche"]
-- [("Porsche",DBRef "Person bruce")]
--
--
-- NOTES:
--
--
-- data Person = Person {name , surname :: String}
--
--
-- then a query for name .==. Bruce is
-- indistinguishable from surname .==. Bruce
--
-- Will return all the registers with surname Bruce as well. So if
-- two or more fields in a registers are to be indexed, they must have
-- different types.
module Data.TCache.IndexQuery
-- | Register a trigger for indexing the values of the field passed as
-- parameter. the indexed field can be used to perform relational-like
-- searches
index :: (Typeable reg, Typeable a, Read reg, Show reg, Read a, Show a, Ord a, IResource reg, Indexable reg) => (reg -> a) -> IO ()
-- | implement the relational-like operators, operating on record fields
class RelationOps field1 field2 res | field1 field2 -> res
(.==.) :: RelationOps field1 field2 res => field1 -> field2 -> STM res
(.>.) :: RelationOps field1 field2 res => field1 -> field2 -> STM res
(.>=.) :: RelationOps field1 field2 res => field1 -> field2 -> STM res
(.<=.) :: RelationOps field1 field2 res => field1 -> field2 -> STM res
(.<.) :: RelationOps field1 field2 res => field1 -> field2 -> STM res
recordsWith :: (IResource a, Typeable a) => STM [DBRef a] -> STM [a]
(.&&.) :: SetOperations set set' setResult => STM set -> STM set' -> STM setResult
(.||.) :: SetOperations set set' setResult => STM set -> STM set' -> STM setResult
class Select selector a res | selector a -> res
select :: Select selector a res => selector -> a -> res
instance [incoherent] Typeable2 Index
instance [incoherent] (Ord a, Read a, Typeable reg, IResource reg) => Read (Index reg a)
instance [incoherent] Show a => Show (Index reg a)
instance [incoherent] (Typeable reg, IResource reg, Typeable reg', IResource reg', Select (reg -> a) (STM [DBRef reg]) (STM [a]), Select (reg' -> b) (STM [DBRef reg']) (STM [b])) => Select (reg -> a, reg' -> b) (STM (JoinData reg reg')) (STM [([a], [b])])
instance [incoherent] (Typeable reg, IResource reg, Select (reg -> a) (STM [DBRef reg]) (STM [a]), Select (reg -> b) (STM [DBRef reg]) (STM [b]), Select (reg -> c) (STM [DBRef reg]) (STM [c]), Select (reg -> d) (STM [DBRef reg]) (STM [d])) => Select (reg -> a, reg -> b, reg -> c, reg -> d) (STM [DBRef reg]) (STM [(a, b, c, d)])
instance [incoherent] (Typeable reg, IResource reg, Select (reg -> a) (STM [DBRef reg]) (STM [a]), Select (reg -> b) (STM [DBRef reg]) (STM [b]), Select (reg -> c) (STM [DBRef reg]) (STM [c])) => Select (reg -> a, reg -> b, reg -> c) (STM [DBRef reg]) (STM [(a, b, c)])
instance [incoherent] (Typeable reg, IResource reg, Select (reg -> a) (STM [DBRef reg]) (STM [a]), Select (reg -> b) (STM [DBRef reg]) (STM [b])) => Select (reg -> a, reg -> b) (STM [DBRef reg]) (STM [(a, b)])
instance [incoherent] (Typeable reg, IResource reg) => Select (reg -> a) (STM [DBRef reg]) (STM [a])
instance [incoherent] SetOperations (JoinData a a') [DBRef a'] (JoinData a a')
instance [incoherent] SetOperations [DBRef a] (JoinData a a') (JoinData a a')
instance [incoherent] SetOperations (JoinData a a') [DBRef a] (JoinData a a')
instance [incoherent] SetOperations [DBRef a] [DBRef a] [DBRef a]
instance [incoherent] (IResource reg, Typeable reg, IResource reg', Typeable reg', Typeable a, Ord a, Read a, Show a, Read reg, Show reg, Read reg', Show reg', Serializable a) => RelationOps (reg -> a) (reg' -> a) (JoinData reg reg')
instance [incoherent] (Indexable reg, Typeable reg, Typeable a, Show reg, Ord a, Show a, Read a, IResource reg, Read reg) => RelationOps (reg -> a) a [DBRef reg]
instance [incoherent] (Typeable reg, Typeable a, Read reg, Show reg, Read a, Show a, Ord a, IResource reg) => IResource (Index reg a)
instance [incoherent] (IResource reg, Typeable reg, Ord a, Read reg, Read a, Show reg, Show a) => Serializable (Index reg a)
instance [incoherent] (Typeable reg, Typeable a) => Indexable (Index reg a)