You are viewing a plain text version of this content. The canonical link for it is here.
Posted to ojb-dev@db.apache.org by ol...@ppi.de on 2003/06/17 10:23:36 UTC

how to implement a TwoLevelCache, was: RE: caching enhancements

Hello,

I would like to share some experiences with you.

> -----Original Message-----
> 
> Caching between client interfaces: locking and cloning
> ------------------------------------------------------
> 
> Whenever a persistence manager would use an object that was 
> seen before by a different persistence manager, this object 
> could wear dirty data if simply the reference would be used. 
> Check out this example:
> 
> 2002-12-24 08:34pm      PM1 starts a transaction
> 2002-12-24 08:35pm      PM1 loads object "reindeer3" from the 
> database, with
>                         state "tired"
> 2002-12-24 08:36pm      PM2 starts a transaction
> 2002-12-24 08:37pm      PM2 searches for "reindeer3" and gets 
> a reference to
>                         the "reindeer2" used by PM1
> 2002-12-24 08:38pm      PM1 feeds "reindeer3" and changes 
> it's state to
>                         "christmas ready"
> 2002-12-24 08:39pm      PM2 sets the state for "reindeer3" to 
> "sleeping" in
>                         order to make sure it is ready for 2002-12-25
> 
> You know what? If both PMs would commit now, both would 
> update a "sleeping" state for the reindeer. To find a 
> way out of this, at least three solutions are open to be 
> implemented:
> 
> - Make sure PM2 gets a different copy of reindeer3 - by 
>   CLONING the reindeer from the cache 
> - Make sure PM2 gets a different copy of reindeer3 - by 
>   materializing the reindeer again from the database
> - Do not allow using reindeer3 multiple times :(

> [thma] I'm not a frient of this cloning business. I know the 
> JDORI simply use different cache instances for all 
> PersistenceManagers. Those caches are strictly separated and 
> will be emptied at transaction end.
> 
> IMO that's all that is needed.
> 
> I know that TopLink got in serious trouble with their cloning 

Thomas, can you tell us more about these troubles?

> cache implementation. A lot of user complained. It's not that 
> easy to implement. And I don't know if it is worth the effort.
> Needs more discussion. [/thma]

O.K., I would like to continue that discussion.

I have tried to implement a class TwoLevelBrokerCache that 
implements ObjectCache.  The idea is as follows:

The cache is supposed to work in an environment where all
database clients are in the same VM.  There is one global cache
that is always consistent with the data in the database.  
Besides, there is one cache for each broker.

References to objects in the global cache are never passed to
the application.  When objects enter or leave the global cache,
they are cloned.  (In the original posting, there is a section 
on how to do that cloning, but let us not worry about that.
In my situtation, the persistence-capable classes provide a method
cacheClone() that does the job).

When an object is inserted in the per-broker-cache, a clone of it
is inserted into the global cache.

When the transactin terminates, the per-broker-cache gets cleared.

When an object is lookup up in the cache, we first look into the
per-broker-cache and then, if that fails, in the global cache.

I bet the idea is so obvious that other users must have done
this before?!

Here are my experiences:

(1) Inside PersistenceBrokerImpl.getDBObject(), the method 
    ObjectCache.cache(oid, newObj) is called fairly early - 
    namely before newObj's references and collections 
    are initialized.  
    (This is to be able to handle cyclic references.)
    If we clone the object inside ObjectCache.cache(..), then
    the clone has uninitialized references and collections.

(2) In order to cope with (1), I would like to initialize
    those references and collections with suitable proxies.
    However, I had to cut-and-paste and adapt that code from 
    PersistenceBrokerImpl because it is hidden in private 
    methods.

(3) When testing the implementation, I use two brokers in the 
    same thread.  I encountered the PersistenceBrokerThreadMapping.
    I had not known before that the concept of a Thread's current
    broker is present in the PB API.  I needed to call 
     PersistenceBrokerThreadMapping.setCurrentPersistenceBroker
    in order to to mix up the two per-broker-caches when traversing
    references.

It seems that the current API is not optimal for that two-level 
cache strategy.  What do you think?  Has anyone tried something 
similar?

I would expect that a clever caching strategy can give a high 
perfomance gain, so almost any effort is worth it.

Olli