A temporary workaround for this has been added as described in
http://jira.jboss.com/jira/browse/EJBTHREE-798.
To give more details about how this works to those unfamiliar with the JBC marshalling
API, I'll go through an example here where 2 different EJB deployments (i.e. different
jars with their persistence.xml files) are deployed and used on 2 different servers in a
cluster.
I) Startup of Server 1.
A) Shared JBoss Cache instance used for entity replication is started. JBC is configured
for region based marshalling. JBC is configured "inactive at startup". This
means the cache will ignore any replication traffic it receives from across the cluster,
until the "region" (i.e. branch of the cache's tree) to which the traffic
pertains is activated.
B) EJB deployment A.jar is deployed on Server 1.
1) Hibernate discovers @Entity com.titan.Foo in A.jar.
a) Hibernate calls TreeCacheProviderHook asking for a org.hibernate.cache.Cache instance
for "com.titan.Foo".
b) TreeCacheProviderHook instantiates an instance of o.j.e.entity.JBCCache.
c) JBCCache registers the TCCL with JBC as the classloader for /com/titan/Foo.
d) JBCCache activates region /com/titan/Foo.
e) JBC requests a transfer from the cluster of the state for region /com/titan/Foo.
Nothing is returned since Server 1 is the only active server.
f) JBC instructs its replication layer to begin accepting replicated messages related to
/com/titan/Foo.
2) Hibernate sees that the query cache is enabled, so it calls TreeCacheProviderHook
asking for a org.hibernate.cache.Cache instance for
"org.hibernate.cache.StandardQueryCache".
a) Same process as 1) above occurs, except:
i) JBCCaches recognizes that "org.hibernate.cache.StandardQueryCache" is a
special region that multiple deployments can share, so it doesn't register its
classloader.
ii) No registered classloader means data can't be safely replicated, so JBCCache sets
a flag telling itself to make any writes to the cache "local only", i.e.
non-replicated.
3) Hibernate sees that the query cache is enabled, so it calls TreeCacheProviderHook
asking for a org.hibernate.cache.Cache instance for
"org.hibernate.cache.UpdateTimestampsCache".
a) Same process as 1) above occurs, except:
i) JBCCaches recognizes that "org.hibernate.cache.UpdateTimestampsCache" is a
special region that multiple deployments can share, so it doesn't register its
classloader.
ii) Only Strings and longs are used in the
"org.hibernate.cache.UpdateTimestampsCache", and this data *must* be replicated,
so JBCCache does *not* set the flag telling itself to make any writes to the cache
"local only".
C) EJB deployment B.jar is deployed on Server 1. Jar contains entity com.titan.Account.
Same process as B) above occurs except:
1) When JBCCache instance for StandardQueryCache is created, it doesn't bother
activating the region, as it sees that it is already active.
2) Same for UpdateTimestampsCache.
D) Some instances of Foo and Account get cached. These would replicate (if there were
other servers in the cluster.)
E) A cacheable query is executed, with no special cache region specified. JBCCache for the
StandardQueryCache region puts it into JBC, but sets an option so it doesn't
replicate.
F) A cacheable query is executed, with special cache region "QueriesA"
specified.
1) Hibernate sees it needs to instantiate a Cache for region "QueriesA".
2) Same process as B1) above occurs.
3) Query is put into the cache, and would replicate if there were other cluster members.
II) Server 2 starts
A) Same as IA) above.
B/C) Same as IB/C) above, except:
B1) now when the region is activated, a state transfer does occur, bringing over the
cached queries from Server 1.
B2) Same as IB2) above, but again a state transfer will occur.
ISSUE This would be a problem if custom classes were stored from multiple deployments, as
the TCCL will only be able to deserialize classes for the current deployment (A.jar). I
need to think if there is any workaround for this. Note that this only causes a problem
if an instance of a custom class is directly stored as a query parameter or as a single
result. If the custom class is broken down by Hibernate into primitives, it's not a
problem.
B3) Same as IB3) above, but again a state transfer will occur. This won't be an issue
as no custom classes are stored.
III) EJB deployment A.jar is undeployed on Server 1. (Not sure of the exact order of this,
but shouldn't matter).
A) Hibernate calls destroy() on JBCCache for "QueriesA" region.
1) All data in the region is evicted from the local cache. This isn't replicated.
2) inactivateRegion() is called on JBC for "QueriesA". JBC starts ignoring
replication traffic for nodes under Fqn /QueriesA. All data under the region is then
evicted again. This ensure no classloader leakage from objects stored in the cache.
3) JBC unregisters the classloader from JBC for "QueriesA".
B) Same as A) for the "com.titan.Foo" region.
C) Hibernate calls destroy() on JBCCache for
"org.hibernate.cache.StandardQueryCache" region.
1) All data in the region is evicted from the local cache. This isn't replicated.
But, any cached queries for B.jar will be evicted as well. (Just means they need to be
executed against DB again if needed.)
2) inactivateRegion() is *not* called on JBC, since JBCCache has no way to know if other
deployments are still using it.
D) Same as C) above for "org.hibernate.cache.UpdateTimestampsCache" region.
View the original post :
http://www.jboss.com/index.html?module=bb&op=viewtopic&p=3990489#...
Reply to the post :
http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&a...