úΘã’ÝK      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJfSerialize is an abstract serialization ionterface in order to define implicit instances of IResource. XThe deserialization must be as lazy as possible if deserialized objects contain DBRefs, Wlazy deserialization avoid unnecesary DBRef instantiations when they are not accessed, 8since DBRefs instantiations involve extra cache lookups For this reason serializationdeserialization is tofrom ordinary Strings  serialization/7deserialization are not performance critical in TCache DIndexable is an utility class used to derive instances of IResource  Example:  8data Person= Person{ pname :: String, cars :: [DBRef Car]"} deriving (Show, Read, Typeable) Zdata Car= Car{owner :: DBRef Person , cname:: String} deriving (Show, Read, Eq, Typeable) &Since Person and Car are instances of K ans L, by defining the  instance Dwill implicitly define the IResource instance for file persistence:  7instance Indexable Person where key Person{pname=n} = "Person " ++ n 1instance Indexable Car where key Car{cname= n} = "Car " ++ n -additional extension for default file paths.  The default value is data/. "Resources data definition used by withSTMResources +resources to be inserted back in the cache Bresources to be deleted from the cache and from permanent storage result to be returned forces a retry JAn IResource instance that must be defined for every object being cached. Qthere are a set of implicit IResource instance trough utiliy classes (See below) must be defined B implements the database access and marshalling or of the object. h while the database access must be strict, the marshaling must be lazy if, as is often the case, 9 some parts of the object are not really accesed. V Moreover, if the object contains DBRefs, this avoids unnecesary cache lookups % this method is called inside 4 blocks and thus may be interrupted without calling » 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 @the write operation in 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 D all the new obbects are writeen to the database on synchromization ' so writeResource must not autocommit. 8 Commit code must be located in the postcondition. (see  setConditions) .is called syncronously. It must autocommit Empty resources: resources= Resources [] [] ()  MN  OFSerializable, Indexable instances are implicit instances of IResource P>Read, Show, instances are implicit instances of Serializable   !"#  !"# #"!  !  !"#QRSTU$4Add 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. DThe DBRef to the object and the new value is passed to the trigger. HThe called trigger function has two parameters: the DBRef being accesed 9(which still contains the old value), and the new value. FIf the content of the DBRef is being deleted, the second parameter is V. @if the DBRef contains Nothing, then the object is being created %  !$% ! $%$%)WXYZ[&\]^'fset the cache. this is useful for hot loaded modules that will update an existing cache. Experimental ()6newCache creates a new cache. Experimental *Dreturn the total number of DBRefs in the cache. For debug purposes P This does not count the number of objects in the cache since many of the DBRef 3 may not have the pointed object loaded. It O(n). _+Ereturn the reference value. If it is not in the cache, it is fetched  from the database. ,write in the reference a value M 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 -5return the key of the object pointed to by the DBRef .dget the reference to the object in the cache. if it does not exist, the reference is created empty.  Every execution of .0 returns the same unique reference to this key, X so it can be safely considered pure. This is a property useful because deserialization & of objects with unused embedded DBRef'(s do not need to marshall them eagerly C Tbis also avoid unnecesary cache lookups of the pointed objects. `ACreate the object passed as parameter (if it does not exist) and )-- return its reference in the IO monad. G-- If an object with the same key already exists, it is returned as is 8-- If not, the reference is created with the new value. *-- If you like to update in any case, use . and , combined <newDBRefIO :: (IResource a,Typeable a) => a -> IO (DBRef a) newDBRefIO x= do  let key = keyResource x  mdbref <- mDBRefIO key  case mdbref of  Right dbref -> return dbref Left cache -> do  tv<- newTVarIO DoNotExist  let dbref= DBRef key tv  w <2- mkWeakPtr dbref . Just $ deleteFromCache dbref . H.update cache key (CacheElem Nothing w)  t <- timeInteger  atomically $ do  applyTriggers [dbref] [Just x] --a (before ++key) * writeTVar tv . Exist $ Elem x t t  return dbref Nthe list of partial object definitions for which keyResource can be extracted $The TVars that contain such objects /ACreate the object passed as parameter (if it does not exist) and ( return its reference in the STM monad. E If an object with the same key already exists, it is returned as is 6 If not, the reference is created with the new value. ( If you like to update in any case, use . and , combined 0Jdelete the content of the DBRef form the cache and from permanent storage 1Adeletes the pointed object from the cache, not the database (see 0) N useful for cache invalidation when the database is modified by other process 2drops the entire cache. 3yThis is the main function for the *Resource(s) calls. All the rest derive from it. The results are kept in the STM monad F so it can be part of a larger STM transaction involving other DBRefs  The  J register returned by the user-defined function is interpreted as such:   *: the content of this field will be added/updated to the cache   V: the content of this field will be removed from the cache and from permanent storage   0: the content of this field will be returned by 3 &the list of resources to be retrieved OThe function that process the resources found and return a Resources structure #The return value in the STM monad. 4'update of a single object in the cache withResource r f= 5 [r] ([mr]-> [f mr])Nprototypes of the object to be retrieved for which keyResource can be derived 0update function that return another full object 5to atomically add/!modify many objects in the cache 6#to read a resource from the cache. 78>delete the resource from cache and from persistent storage.   deleteResource r= 9 [r]  9Edelete the list of resources from cache and from persistent storage. bcdef:(Start the thread that periodically call <1 to clean and writes on the persistent storage.  Otherwise, ;: must be invoked explicitly or no persistence will exist. , Cache writes allways save a coherent state Inumber of seconds betwen checks. objects not written to disk are written ?The user-defined check-for-cleanup-from-cache for each object. = is an example EThe max number of objects in the cache, if more, the cleanup starts !Identifier of the thread created ;aForce the atomic write of all cached objects modified since the last save into permanent storage , Cache writes allways save a coherent state <%Saves the unsaved elems of the cache , Cache writes allways save a coherent state J delete some elems of the cache when the number of elems > sizeObjects. . The deletion depends on the check criteria. = is the one implemented =Qths is a default cache clearance check. It forces to drop from the cache all the E elems not accesed since half the time between now and the last sync A if it returns True, the object will be discarded from the cache L it is invoked when the cache size exceeds the number of objects configured  in : or < current time in seconds $last access time for a given object 7last cache syncronization (with the persisten storage) \return true for all the elems not accesed since half the time between now and the last sync >?stablishes the procedures to call before and after saving with ;, < or :. The postcondition of * database persistence should be a commit. g4 $&'()*+,-./0123456789:;<=>4.-/+,03 547698$12&')(;><*:=&'()*+,-./0123456789:;<=>?@hABiCDimplement the relational-like operators, operating on record fields DEFGHjklmnopqrsIMRegister a trigger for indexing the values of the field passed as parameter. C the indexed field can be used to perform relational-like searches tuJ ?@ABCDEFGHIJ ICDEFGHJBA?@ ?@@ABCDEFGHDEFGHIJv      !!"##$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYYZZ[\]^^_`abccdefghijklmnoopqrsstuvwxyTCache-0.8.0.2 Data.TCacheData.TCache.IResourceData.TCache.DefsData.TCache.TriggersData.TCache.IndexQueryData.TCache.FilePersistencebase GHC.Conc.Sync atomicallySTM Serializable serialize deserialize IndexablekeydefPath ResourcestoAddtoDeletetoReturnRetry IResource keyResourcereadResourceByKey writeResource delResource resourcesdefaultReadResourcedefaultReadResourceByKeydefaultWriteResourcedefaultDelResourcereadFileStrictDBRefTPVarElemStatusExist DoNotExistNotRead ModifTime AccessTime addTrigger applyTriggersCachesetCacherefcachenewCachenumElems readDBRef writeDBRef keyObjDBRefgetDBRefnewDBRefdelDBRef flushDBRefflushAllwithSTMResources withResource withResources getResource getResourcesdeleteResourcedeleteResourcesclearSyncCacheProc syncCacheclearSyncCache defaultCheck setConditionsSelectselect.||..&&. RelationOps.==..>..>=..<=..<.index recordsWithGHC.ReadReadGHC.ShowShowcastErr safeWrite $fIResourcea$fSerializablea CMTrigger TriggerType cmtriggers Data.MaybeNothingFilteredCheckTPVarFlags NoAddToHash AddToHashHt CacheElemdeleteFromCachemDBRefIOdebug takeDBRefs takeDBRef releaseTPVars releaseTPVardelListFromHash safeIOToSTM SetOperationsJoinData PersistIndexreadIndexByKey writeIndex deleteIndexIndexsetPersistIndex persistIndex selectorIndexjoinretrieveIndexes