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