TCache is a transactional cache with configurable persitence that permits
STM transactions with objects that syncronize sincromous or asyncronously with
their user defined storages. Default persistence in files is provided by default

TCache implements ''DBRef' 's . They are persistent STM references with a typical Haskell interface.
simitar to TVars (newDBRef, readDBRef, writeDBRef etc) but with added. persistence
. DBRefs are serializable, so they can be stored and retrieved.
Because they are references,they point to other serializable registers.
This permits persistent mutable Inter-object relations

For simple transactions of lists of objects of the same type TCache implements
inversion of control primitives withSTMResources and variants, that call pure user defined code for registers update. Examples below.

Triggers in Data.TCache.Triggers are user defined hooks that are called back on register updates.
.They are used internally for indexing.

Data.TCache.IndexQuery implements an straighforwards pure haskell type safe query language based
on register field relations. This module must be imported separately.

Data.TCache.DefaultPersistence has instances for key indexation , serialization
and default file persistence. The file persistence is more reliable, and the embedded IO reads inside STM transactions are safe.

Data.Persistent.Collection implements a persistent, transactional collection with Queue interface as well as
indexed access by key

You cannot use atomically inside an unsafePerformIO or unsafeInterleaveIO.
Any attempt to do so will result in a runtime error. (Reason: allowing
this would effectively allow a transaction inside a transaction, depending
on exactly when the thunk is evaluated.)

Unsafely performs IO in the STM monad. Beware: this is a highly
dangerous thing to do.

The STM implementation will often run transactions multiple
times, so you need to be prepared for this if your IO has any
side effects.

The STM implementation will abort transactions that are known to
be invalid and need to be restarted. This may happen in the middle
of unsafeIOToSTM, so make sure you don't acquire any resources
that need releasing (exception handlers are ignored when aborting
the transaction). That includes doing any IO using Handles, for
example. Getting this wrong will probably lead to random deadlocks.

The transaction may have seen an inconsistent view of memory when
the IO runs. Invariants that you expect to be true throughout
your program may not be true inside a transaction, due to the
way transactions are implemented. Normally this wouldn't be visible
to the programmer, but using unsafeIOToSTM can expose it.

Assures that the IO computation finalizes no matter if the STM transaction
is aborted or retried. The IO computation run in a different thread.
The STM transaction wait until the completion of the IO procedure (or retry as usual)
it can be retried if the embedding STM computation is retried
so the IO computation must be idempotent.
Exceptions are bubbled up to the STM transaction

Operations with cached database references

DBRefs are persistent cached database references in the STM monad
with read/write primitives, so the traditional syntax of Haskell STM references
can be used for interfacing with databases. As expected, the DBRefs are transactional,
because they operate in the STM monad.

A DBRef is associated with its referred object trough its key.
Since DBRefs are serializable, they can be elements of mutable cached objects themselves. They could point to other mutable objects
and so on, so DBRefs can act as "hardwired" relations from mutable objects
to other mutable objects in the database/cache. their referred objects are loaded, saved and flused
to and from the cache automatically depending on the cache handling policies and the access needs

DBRefs are univocally identified by its pointed object keys, so they can be compared, ordered checked for equality so on.
The creation of a DBRef, trough getDBRef is pure. This permits an efficient lazy access to the
registers trouth their DBRefs by lazy marshalling of the register content on demand.

DBRefs, once the pointed cached object is looked up in the cache and found at creation, they does
not perform any further cache lookup afterwards, so reads and writes from/to DBRefs are faster
than *Resource(s) calls, which perform cache lookups everytime the object is accessed

DBRef's and *Resource(s) primitives are completely interoperable. The latter operate implicitly with DBRef's

Get the reference to the object in the cache. if it does not exist, the reference is created empty.
Every execution of getDBRef returns the same unique reference to this key,
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.
Tbis also avoid unnecesary cache lookups of the pointed objects.

Create the object passed as parameter (if it does not exist) and
-- return its reference in the IO monad.
-- If an object with the same key already exists, it is returned as is
-- If not, the reference is created with the new value.
-- If you like to update in any case, use getDBRef and writeDBRef 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

Create the object passed as parameter (if it does not exist) and
return its reference in the STM monad.
If an object with the same key already exists, it is returned as is
If not, the reference is created with the new value.
If you like to update in any case, use getDBRef and writeDBRef combined
if you need to create the reference and the reference content, use newDBRef

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.
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.

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.
. 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 to
persistent storage, writeResource must retry until success.

Operations with cached objects

implement inversion of control primitives where the user defines the objects to retrive. The primitives
then call a the defined function that, determines how to transform the objects retrieved,wich are sent
back to the storage and a result is returned.

In this example "buy" is a transaction where the user buy an item.
The spent amount is increased and the stock of the product is decreased:

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:

WARNING: To catch evaluations errors at the right place, the values to be written must be fully evaluated.
Errors in delayed evaluations at serialization time can cause inconsistencies in the database.

Trigger operations

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

Example:

Every time a car is added, or deleted, the owner's list is updated.
This is done by the user defined trigger addCar

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

Saves the unsaved elems of the cache.
Cache writes allways save a coherent state.
Unlike syncChace this call deletes some elems of the cache when the number of elems > sizeObjects.
The deletion depends on the check criteria, expressed by the first parameter.
defaultCheck is the one implemented to be passed by default. Look at it to understand the clearing criteria.

Start the thread that periodically call clearSyncCache to clean and writes on the persistent storage.
Otherwise, syncCache or clearSyncCache or atomicallySync must be invoked explicitly or no persistence will exist.
Cache writes allways save a coherent state

return true for all the elems not accesed since half the time between now and the last sync

This 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