Friday, June 17, 2011

Blog Moved to Tumblr!

This blog now lives on Tumblr. Thanks for visiting!

http://jeffnadler.tumblr.com/

Friday, March 11, 2011

Hibernate Collection Cache and Cascades

When using Hibernate collection caching, there are some problems that come up that require incredibly awkward code workarounds. I'm writing this post in the hopes that someone has come up with something more elegant.

When you delete an entity, you need to write the code to remove that entity from all c0llections in which it might be cached. Hibernate doesn't do this automagically. They say:

When I delete an object that belongs to a cached collection, the collection cache is not invalidated!

You must remove the deleted object from all collections it belongs to.

(source: http://community.jboss.org/wiki/HibernateFAQ-AdvancedProblems#When_I_delete_an_object_that_belongs_to_a_cached_collection_the_collection_cache_is_not_invalidated)


Now that's not ideal, because it makes my code very prone to error. Later, if I fail to maintain the collection properly and try to iterate it's members, I will get an EntityNotFoundException.


Fine, in my DAO I'll write teh code to look up the other entities that refer to this entity and remove this entity from their cached collections. Done, right?


Wrong. Now consider cascading deletes. Because Hibernate handles the cascade, entities are being deleted indirectly (not via any direct calls to my DAO). Those entities that are cascade-deleted may be members of many other collections caches, and they need to be removed.

Maybe we'll try @PreRemove, which runs for each entity that is cascade-deleted, and there we can look up the other entities that cache this entity and remove this entity from the collection. Right?

Wrong. This can cause ConcurrentModificationException in cases where the collection.remove(entity) that is done in @PreRemove conflicts with the cascade operation. The @PreRemove seems to run first, is successful, then deep in the bowels of Hibernate the CME is thrown when the cascade operation hits the same entity. Note that we have a hierarchical data model (entity has a collection of children of the same type, deletes cascade down the tree) and that this condition may be specific to that case.

Not much we can do here. We're thinking of writing our own cascade-delete logic to handle this case; this will allow us to maintain the collection caches as we go.

Argh. Any ideas?



Monday, November 15, 2010

Oracle vs Apache

So for a while now, Apache has been trying to get access to the Java TCK so that Harmony can be certified. Oracle's not an open source kind of company, so they're not playing ball.

Here's the Oracle official response to Apache, who have been playing hardball to try to get access to the TCK. It totally dodges the issue.

Not only that, but this chickenshit Oracle cog has disabled commenting for this post, because the overwhelming negative reaction would look awful:

http://blogs.oracle.com/henrik/2010/11/moving_java_forward_open_response_from_oracle_to_apache.html

Oracle sucks. Time to start moving my software away from Java?

Wednesday, September 15, 2010

Maintaining L2 Cached Collections After Cascade Remove

Hibernate's L2 collection caching provides a major performance boost to our application. It's requires an odd mindset from the developer user however - it does some things automatically, but the developer is left with a few critical responsibilities. If you just configure a collections cache but fail to maintain the collection cache properly in your code you can expect problems.

This is very error prone - the developer needs to understand a great deal about how Hibernate's collections caches work 'under the covers' to get everything working just perfectly.

The simple example is removing (deleting) an entity that is a member of a parent's collection. Lets assume I have entities Child and Parent. Parent has a cached collection called 'children'. If I simply do:

childDAO.delete(aChildEntity);

I'm now in bad shape. The parent cached collection still thinks it contains the child that has been removed. Simple enough; the developer is responsible for maintaining the collection (I know I know this code is for illustration only):

aChildEntity.getParent().getChildren().remove(aChildEntity); childDAO.delete(aChildEntity);

Problem solved right? Now lets make the scenario more complex. I have another entity that also cascades delete to children, so it's happening implicitly. Maybe I have 5 or 10 places where this happens. I'm quickly going to have to write a lot of fragile code to make sure this works right.

Instead, what I've done is to use a @PreRemove method on Child to evict the parent collection from the cache. This should be far less fragile. No matter what new and creative ways I come up with of deleting children, the cache should stay clean:

sessionFactory.getCache().evictCollection(com.mycompany.entity.Parent.class.getName() + ".children", deletedEntityId);

Thursday, August 12, 2010

Infinispan as Hibernate L2 Cache

We're now using Infinispan as a Hibernate L2 cache. There was only one obstacle: locking of our persistent entities.

Formerly we were using EHCache in a single-server configuration only. We switched to Atomikos + Infinispan and got the app working again. So far so good.

Then I ran some load tests. Uh - oh, exceptions all over the place, mostly Infinispan TimeoutExceptions. I'm using the same lock timeout as in the old EHCache version of the system.

In the end this boiled down to long running processing that was in fact causing lock timeouts. This didn't happen in EHCache possibly because it only supports CacheConcurrencyStrategy.READ_WRITE? I'm not sure; we never pinned down exactly why this arose only after switching to Infinispan.

The app is running very well after sorting through this issue. We've completed load testing and in a single server scenario we get just about exactly the same performance we saw with EHCache.

I wanted to use the Infinispan CacheManager for some app-specific (non-hibernate) caching as well, so I wrote a SpringInfinispanRegionFactory that let me spring-create the CacheManager and wire it to both Hibernate and to my other classes.

The only remaining problem is that we needed a JTA implementation. We went with Atomikos and we aren't happy with it. Bitronix looks good, but doesn't support Infinispan, not even using the last-resource gambit. Jotm is probably OK but the XAPool connection pool that it supports is widely agreed to be awful. Any brilliant suggestions?

Monday, March 22, 2010

Hibernate Lazy OneToOne Associations

Damn, this was harder than it needed to be. I have a bidirectional one-to-one association between two objects. I want the 'owner' object (the one without mappedBy=...) to be able to lazily load the 'owned' object.


@OneToOne(optional=false, fetch=FetchType.LAZY, cascade={CascadeType.PERSIST,CascadeType.REMOVE})
@LazyToOne(LazyToOneOption.PROXY)
@JoinColumn(name = "partyAttentionId")
ChildObject childObject;


This doesn't work. Supposedly from all the forum posts I read the 'key' would be to get that optional=false in there. No joy, I'm profiling in JProfiler and it's still eagerly loading this property.

Either LazyToOneOption.PROXY isn't intended to work for OneToOne associations (I couldn't find documentary evidence of this) or it's a bug.

The only alternative is to use LazyToOneOption.NO_PROXY and run bytecode enhancement during the build as described here: http://tricksdev.blogspot.com/2009/03/hibernate-bytecode-instrumentation.html

Thursday, February 25, 2010

Infinispan Went GA

Infinispan just went GA. Hibernate 3.5 is at a CR. It's getting to be time to try clustering our app using Infinispan and their cache provider for Hibernate.

We have a few machines in the QA lab just waiting for this. I hope our gb switch is fast enough to run an Infinispan cluster. Our app hauls a lot of content, and I noticed that they used Inifiband interconnects (way faster than any ethernet, widely used in high-performance computing) in their benchmarks.

If anyone has already tried Infinispan with Hibernate let me know how it went for you.

Upgrading To Spring and SpringSecurity 3.0

Tonight I upgraded our enterprise Java app to both Spring 3.0 and Spring Security 3.0.


Spring 3.0


Upgrading to Spring 3.0 was easy. It works with spring-*-2.5 XML schemas, so I didn't have to change any of my beans files. The only hitch is that we use Jersey and the jersey-spring module.

We build with maven, and this module's pom has versioned dependencies on Spring 2.5.x, so a bunch of <exclusions> were needed.

Spring Security 3.0

Spring Security was much harder to upgrade from 2.0.4 to 3.0.2. The module structures have changed, so it was a bit of trial and error to find the minimal set of spring-security modules that met our app requirements.

The trouble wasn't over once I had a clean build. Lots of the classes have changed packages, so a number of the beans in our spring security XML file needed to be fixed.

Our old Spring Security config had some quirks. It used the security namespace configuration to create the primary beans (it created them all with an underscore ID, like _formLoginFilter) then created two different filter chains using normal bean definitions.

This doesn't work in SS3. No choice but to manually set up all the bean definitions for all the components of SS. This might be good (lots of flexibility, I learned a ton about SS) but it took hours to get it just right.

The app is running smoothly now, using all the latest Spring goodness. Hope this helps someone!

Wednesday, September 23, 2009

Why is Lucene MoreLikeThis Final?

Lucene has a class MoreLikeThis which can used to build a search query finding documents similar to a passed example document.

This is very useful; in my RSS reader I allows users to find articles similar to an article they find interesting.

I'd like to do something a bit advanced: given an instance of class A, find similar instances of class B. The two classes are stored in separate Lucene indices; the vast majority of the time they are to be queried separately.

For some reason they have chosen to implement MoreLikeThis as final. I can't see any reason for this. I'd like to be able to extend it to add a new public Query like... method but no dice. The primary methods I need (createQuery()) to call are private so there doesn't seem to be a way around it:

I'll need to make my own version of the whole class. Ick. Looking at it positively, this will encourage me to learn the internals of the class instead of using it as a black box.

Saturday, September 19, 2009

Upgrading to EhCache 1.6.2 with Hibernate to enable JMX Monitoring

I couldn't (easily) find this answer, so here goes: Yes, it is completely OK to use 1.6.2 with Hibernate (3.3.2 in my case).

For whatever reason, the maven package hibernate-ehcache uses an old version of ehcache, version 1.2.3. This version doesn't support JMX (which is why I wanted to upgrade) but supposedly there are significant performance improvements in newer ehcache versions as well.

My app is maven/spring/hibernate, so first in your spring config make sure to use the Singleton version of the ehcache provider, otherwise you won't be able to turn on JMX:

<entry key="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.SingletonEhCacheProvider" />


Then in maven, exclude the old version and bring in the new one:

        <dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>3.3.2.GA</version>
<exclusions>
<exclusion>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>1.6.2</version>
</dependency>


Finally you will need to register JMX mbeans for your cache when your app starts:

        CacheManager manager = CacheManager.getInstance();
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
ManagementService.registerMBeans(manager, mBeanServer, false, false, false, true);


Now you can see how many items are in each cache region using JConsole. Enjoy!