TCache 0.10.2.4 → 0.11.0.0
raw patch · 10 files changed
+151/−115 lines, 10 files
Files
- Data/TCache.hs +40/−7
- Data/TCache/DefaultPersistence.hs +6/−2
- Data/TCache/Defs.hs +6/−0
- Data/TCache/IResource.hs +17/−5
- Data/TCache/IndexQuery.hs +24/−29
- Data/TCache/IndexText.hs +1/−2
- TCache.cabal +12/−4
- demos/DynamicSample.hs +0/−66
- demos/IndexText.hs +30/−0
- demos/memoization.hs +15/−0
Data/TCache.hs view
@@ -133,6 +133,7 @@ ,newDBRef --,newDBRefIO ,readDBRef+,readDBRefs ,writeDBRef ,delDBRef @@ -379,14 +380,45 @@ return $ Just x DoNotExist -> return $ Nothing NotRead -> do- r <- safeIOToSTM $ readResourceByKey key- case r of- Nothing -> writeTVar tv DoNotExist >> return Nothing- Just x -> do+ r <- safeIOToSTM $ readResourceByKey key+ case r of+ Nothing -> writeTVar tv DoNotExist >> return Nothing+ Just x -> do t <- unsafeIOToSTM timeInteger- writeTVar tv $ Exist $ Elem x t t+ writeTVar tv $ Exist $ Elem x t (-1) return $ Just x +-- | Read multiple DBRefs in a single request using the new 'readResourcesByKey'+readDBRefs :: (IResource a, Typeable a) => [DBRef a] -> STM [(Maybe a)]+readDBRefs dbrefs= do+ let mf (DBRef key tv)= do+ r <- readTVar tv+ case r of+ Exist (Elem x _ mt) -> do+ t <- unsafeIOToSTM timeInteger+ writeTVar tv . Exist $ Elem x t mt+ return $ Right $ Just x+ DoNotExist -> return $ Right Nothing+ NotRead -> return $ Left key+ inCache <- mapM mf dbrefs+ let pairs = foldr(\pair@(x,dbr) xs -> case x of Left k -> pair:xs; _ -> xs ) [] $ zip inCache dbrefs+ let (toReadKeys, dbrs) = unzip pairs+ let fromLeft (Left k)= k+ formLeft _ = error "this will never happen"+ rs <- safeIOToSTM . readResourcesByKey $ map fromLeft toReadKeys+ let processTVar (r, DBRef key tv)= do+ case r of+ Nothing -> writeTVar tv DoNotExist+ Just x -> do+ t <- unsafeIOToSTM timeInteger+ writeTVar tv $ Exist $ Elem x t (-1)++ mapM_ processTVar $ zip rs dbrs+ let mix (Right x:xs) ys = x:mix xs ys+ mix (Left _:xs) (y:ys)= y:mix xs ys++ return $ mix inCache rs+ -- | Write in the reference a value -- The new key must be the same than the old key of the previous object stored -- otherwise, an error "law of key conservation broken" will be raised@@ -715,7 +747,8 @@ Just dbref -> return . Just $! castErr dbref Nothing -> unsafeIOToSTM (finalize w) >> takeDBRef cache flags x Nothing -> do- safeIOToSTM $ readToCache flags cache keyr -- unsafeIOToSTM $ readResourceByKey keyr+ safeIOToSTM $ readToCache flags cache keyr+ -- unsafeIOToSTM $ readResourceByKey keyr where readToCache flags cache key= do@@ -724,7 +757,7 @@ Nothing -> return Nothing Just r2 -> do ti <- timeInteger- tvr <- newTVarIO . Exist $ Elem r2 ti ti+ tvr <- newTVarIO . Exist $ Elem r2 ti (-1) case flags of NoAddToHash -> return . Just $ DBRef key tvr AddToHash -> do
Data/TCache/DefaultPersistence.hs view
@@ -8,7 +8,9 @@ {- | 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.+ to persistence in databases, for example.++ The definitions of these classes are in Defs.hs -} module Data.TCache.DefaultPersistence( Indexable(..)@@ -33,4 +35,6 @@ readResourceByKey = defReadResourceByKey delResource = defDelResource -+-- | By default the index of a `Serializable` data persist with the data.+instance Serializable a => PersistIndex a where+ persistIndex= setPersist
Data/TCache/Defs.hs view
@@ -101,10 +101,16 @@ class Serializable a where serialize :: a -> B.ByteString deserialize :: B.ByteString -> a+ deserialize= error "No deserialization defined for your data" deserialKey :: String -> B.ByteString -> a deserialKey _ v= deserialize v setPersist :: a -> Maybe Persist -- ^ `defaultPersist` if Nothing setPersist = const Nothing++-- | Used by IndexQuery for index persistence(see "Data.TCache.IndexQuery".+class PersistIndex a where+ persistIndex :: a -> Maybe Persist+ type Key= String --instance (Show a, Read a)=> Serializable a where
Data/TCache/IResource.hs view
@@ -40,11 +40,15 @@ 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. If the object contains DBRefs, this avoids unnecesary cache lookups.- This method is called inside 'atomically' blocks.+ This method is called within '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)+ readResourceByKey k= return . head =<< readResourcesByKey [k]+ -- | hopefully optimized read of many objects by key.+ readResourcesByKey :: [String] -> IO [Maybe a]+ readResourcesByKey = mapM readResourceByKey -- To allow accesses not by key but by any criteria based on the content of the record fields -- included in the -partial- definition of the input record. (it defaults as @readResourceByKey $ keyResource x@)@@ -60,11 +64,19 @@ -- Since there is no provision for rollback from failure in writing to -- persistent storage, 'writeResource' must retry until success. writeResource:: a-> IO()+ writeResource r= writeResources [r]+ + -- | multiple write (hopefully) in a single request. That is up to you and your backend+ -- . Defined by default as 'mapM_ writeResource'+ writeResources :: [a] -> IO()+ writeResources= mapM_ writeResource - -- | Delete the resource. It is called syncronously. So it must tocommit - delResource:: a-> IO() - - + -- | Delete the resource. It is called syncronously. So it must commit + delResource:: a-> IO()+ delResource x= delResources [x]+ + delResources :: [a] -> IO() + delResources= mapM_ delResource -- | Resources data definition used by 'withSTMResources' data Resources a b = Retry -- ^ forces a retry
Data/TCache/IndexQuery.hs view
@@ -53,8 +53,7 @@ NOTES: * the index is instance of 'Indexable' and 'Serializable'. This can be used to-persist in the user-defined storoage. If "Data.TCache.FilePersistence" is included-the indexes will be written in files.+persist in the user-defined storage using DefaultPersistence * The Join feature has not been properly tested @@ -72,7 +71,7 @@ {-# LANGUAGE DeriveDataTypeable, MultiParamTypeClasses , FunctionalDependencies, FlexibleInstances, UndecidableInstances-, TypeSynonymInstances, IncoherentInstances #-}+, TypeSynonymInstances, IncoherentInstances, OverlappingInstances #-} module Data.TCache.IndexQuery( index , (.==.)@@ -85,9 +84,7 @@ , (.&&.) , (.||.) , select-, Queriable-, setIndexPersist-, getIndexPersist)+, Queriable) where import Data.TCache@@ -102,21 +99,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)+ , Typeable a,Ord a,PersistIndex reg) => Queriable reg a instance (Read reg, Read a, Show reg, Show a , IResource reg,Typeable reg- , Typeable a,Ord a)+ , Typeable a,Ord a,PersistIndex reg) => Queriable reg a ---instance Queriable reg a => IResource (Index reg a) where--- keyResource = key--- writeResource =defWriteResource--- readResourceByKey = defReadResourceByKey--- delResource = defDelResource+instance Queriable reg a => IResource (Index reg a) where+ keyResource = key+ writeResource =defWriteResource+ readResourceByKey = defReadResourceByKey+ delResource = defDelResource @@ -128,34 +126,31 @@ = map (\(r,s) -> (Index r, s)) rs where rs= readsPrec n str readsPrec _ s= error $ "indexQuery: can not read index: \""++s++"\"" - instance (Queriable reg a) => Serializable (Index reg a) where serialize= pack . show deserialize= read . unpack- setPersist= const $ unsafePerformIO $ readIORef _indexPersist+ setPersist index= persistIndex $ getType index+ where+ getType :: Index reg a -> reg+ getType= undefined -- type level -_indexPersist= unsafePerformIO $ newIORef Nothing --- | Set the default persistence for the indexes------ Must be called before any other TCache sentence-setIndexPersist p= writeIORef _indexPersist $ Just p -getIndexPersist= unsafePerformIO $ readIORef _indexPersist-- keyIndex treg tv= "index " ++ show treg ++ show tv instance (Typeable reg, Typeable a) => Indexable (Index reg a) where key map= keyIndex typeofreg typeofa where [typeofreg, typeofa]= typeRepArgs $! typeOf map--instance (Queriable reg a, Typeable reg, Typeable a) => IResource (Index reg a) where- keyResource = key- writeResource =defWriteResource- readResourceByKey = defReadResourceByKey- delResource = defDelResource+-- defPath index= defPath $ ofRegister index+-- where+-- ofRegister :: Index reg a -> reg+-- ofRegister = undefined -- type level+-- instance (Queriable reg a, Typeable reg, Typeable a) => IResource (Index reg a) where+-- keyResource = key+-- writeResource =defWriteResource+-- readResourceByKey = defReadResourceByKey+-- delResource = defDelResource getIndex :: (Queriable reg a) => ( reg -> a) -> a -> STM(DBRef (Index reg a), Index reg a,[DBRef reg])
Data/TCache/IndexText.hs view
@@ -87,7 +87,6 @@ , mapDocKeyInt :: M.Map String Int , mapIntDocKey :: M.Map Int String , mapTextInteger :: M.Map T.Text Integer- } deriving (Typeable) @@ -100,7 +99,7 @@ instance Serializable IndexText where serialize= pack . show deserialize= read . unpack- setPersist= const $ getIndexPersist+ setPersist= const Nothing instance Indexable IndexText where key (IndexText v _ _ _ _)= "indextext " ++ v
TCache.cabal view
@@ -1,5 +1,5 @@ name: TCache-version: 0.10.2.4+version: 0.11.0.0 cabal-version: >= 1.6 build-type: Simple license: BSD3@@ -13,7 +13,10 @@ 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 .- 0.10.2.0 added setDefaultPersist and modified the signature of setPersist in Data.TCache.DefaultPersistence.+ 0.11.0.0 added setIndexParsist to define persistence for indexes by type. started the addition of readDBRefs, readResources and so on for simultaneous read, writes and deletes of+ objects of the same type.+ .+ 0.10.2.0 Added setDefaultPersist and modified the signature of setPersist in Data.TCache.DefaultPersistence. Fixed issues with ghc 7.6.3 . 0.10 version add memoization and a persistent and transactional collection/queue.@@ -33,9 +36,14 @@ author: Alberto Gómez Corona tested-with: GHC ==7.0.3 data-dir: ""-extra-source-files: demos/DBRef.hs demos/DynamicSample.hs- demos/IndexQuery.hs demos/basicSample.hs demos/caching.hs+extra-source-files: demos/DBRef.hs+ demos/IndexQuery.hs+ demos/IndexText.hs+ demos/basicSample.hs+ demos/caching.hs demos/triggerRelational.lhs+ demos/memoization.hs+ demos/DBRef.hs source-repository head type: git
− demos/DynamicSample.hs
@@ -1,66 +0,0 @@-{-# OPTIONS -XTypeSynonymInstances -XFlexibleInstances -XUndecidableInstances #-} --- XTypeSynonymInstances added only to permit IResource instances for Strings -module Main where-import Data.TCache-import Data.TCache.DefaultPersistence-import Data.ByteString.Lazy.Char8(pack,unpack) -import Data.Typeable - -{------------- tests--------- -example of IDynamic usage. - --} - ---very simple data: ---two objects with two different datatypes: Int and String - -instance Indexable Int where - key = show - - -instance Indexable String where - key x= take 2 x - -instance (Read a, Show a) => Serializable a where- serialize= pack . show- deserialize= read . unpack - - -main= do - putStrLn "see the code to know the meaning of he results"-- -- NOTE: registerType no longer needed- - - let x= 1:: Int-- -- now *Resources primitives suppont different datatypes- -- without the need of Data.Dynamic - withResources [] $ const [x]- withResources [] $ const ["hola"] --resources creation - - syncCache - - res <- getResource x - print res - - res <- getResource "ho" - print res -- -- to use heterogeneous data in the same transaction,- -- use DBRef's:- s <- atomically $ do- let refInt = getDBRef $ key x :: DBRef Int- refString = getDBRef $ key "ho" :: DBRef String- i <- readDBRef refInt- writeDBRef refString $ "hola, the retrieved value of x is " ++ show i- s <- readDBRef refString- return s-- print s-- -- however, retrieval of data with the incorrect type will generate an exception:- - syncCache - -
+ demos/IndexText.hs view
@@ -0,0 +1,30 @@+{-# LANGUAGE DeriveDataTypeable#-}+module Main where+import Data.TCache+import Data.TCache.DefaultPersistence+import Data.TCache.IndexQuery(select)+import Data.TCache.IndexText+import Data.ByteString.Lazy.Char8(pack,unpack)+import qualified Data.Text.Lazy as T(pack) +import Data.Typeable++data Doc= Doc{title, body :: String} deriving (Read,Show, Typeable)+instance Indexable Doc where+ key Doc{title=t}= t++instance Serializable Doc where+ serialize= pack . show+ deserialize= read . unpack++main= do+ indexText body T.pack+ let doc= Doc{title= "title", body= "hola que tal estamos"}+ rdoc <- atomically $ newDBRef doc+ r1 <- atomically $ select title $ body `contains` "hola que tal"+ print r1++ atomically $ writeDBRef rdoc doc{ body= "que tal"}+ r <- atomically $ select title $ body `contains` "hola que tal"+ print r+ if r1 == [title doc] then print "OK" else print "FAIL"+ if r== [] then print "OK" else print "FAIL"
+ demos/memoization.hs view
@@ -0,0 +1,15 @@+import Data.TCache.Memoization+import Data.TCache.DefaultPersistence+import Control.Concurrent+import System.Time++++main= do+ cachedByKey "" 4 f >>= print+ threadDelay 1000000+ main++f= do+ TOD t _ <- getClockTime+ return t