[hibernate-dev] Bytecode enhancement

Steve Ebersole steve at hibernate.org
Tue Oct 9 11:30:38 EDT 2012


On Tue 09 Oct 2012 09:57:12 AM CDT, Emmanuel Bernard wrote:
> On Thu 2012-10-04 10:00, Steve Ebersole wrote:
>> See https://hibernate.onjira.com/browse/HHH-7667
>>
>> I want to investigate expanding Hibernate's support for bytecode
>> enhancement.  I can see 3 main fronts to this:
>>
>> 1) offloading map lookups from the PersistenceContext .  Currently we
>> keep state associated with each entity in a map (a special type of map
>> called IdentityMap) on the PersistenceContext, keyed by the entity.
>> Profiling consistently shows these maps as a hot-spot.  The main thing
>> we keep in the PersistenceContext in regards to the entity is called an
>> EntityEntry, which is kept in an IdentityMap<Object,EntityEntry> (again,
>> the entity is the key).  So the thought here is to invert this from
>> `map.get( entity )` to something like `( (Enhanced) entity
>> ).getEntityEntry()`
>
> I was discussing this with Sanne. One "workaround" to the heavy
> IdentityMap price is to keep a contextual cache. I am pretty sure these
> IndeitityMap lookups are done over and over for a given operation.
>
> We might be able to:
>
> - pass along the EntityEntry instead of relying on the lookup several
>    times
> - use a cache of lookups for either the most recent or for the
>    contextual operation.
>
> The cache would be array based and thus not involve hashcode or lookup.
>
> for ( int index = 0 ; index < cache.length ; index++ ) {
>    if ( searchedO == cache[index] ) {
>      entityEntry = entityEntryCache[index];
>    }
> }
> if ( entityEntry == null ) {
>    identityMap.get(searchedO);
>    //add to cache
> }
>
> Alternatively, I don't remember what is costly, the actual lookup or the
> computation of the identity hashcode.
> If that's the former, we can take the bet and use the entity hashcode
> instead but still use == instead of equals. The risk is more collisions
> or in case of a rogue implementation of hashCode not finding the entity.
>
> These options seems more lightweight than relying on bytecode
> enhancement to keep a placeholder.

Well technically the hotspot is the calculation of the hashcode.  
However, the same is true no matter how we calculate the hashcode.  
Both Object#hashCode and System#identityHashCode have the same 
characteristic (in fact Object#hashCode simply calls 
System#identityHashCode, as best we can tell since they are both 
defined as native calls).  However, the fact that this call stack shows 
up as a hotspot at all is more due to the poor choice of Map impl here 
and then the fact that we do lots of lookups.  What happens is that we 
wrap the keys (the entity instances) in a wrapper object that applies 
the "hashCode as System#identityHashCode" and "equality as ==" 
semantics.  They problem with the number of calls then is the number of 
times we do lookups and the fact that we need to wrap the incoming keys 
and call identityHashCode to be able to do a map lookup.

I do not see how the answer can be "contextual" caches, beyond the set 
of contextual caches we leverage already (see "merge map", etc).



>> 2) More performant dirty-checking.  This already exists, to an extent,
>> in the current Hibernate bytecode.  The idea being that we could use
>> "interception" within the enhanced entity to know when it becomes dirty.
>>    Well, almost.  What is missing is "deep checking of mutable state
>> fields".  For example, an entity attribute of type Date that is
>> "changed" via entity.getSomeDate().setTime( ... ).  The entity needs to
>> be found dirty here, because its "someDate" attribute value has changed,
>> but interception will not catch this.  And I think this should be
>> configurable (whether the user wants us to perform "deep mutable state
>> checking").  We have all the pieces in place to handle this already
>> through Type.isMutable() as Hibernate already does a great job of
>> finding dirty fields in the most flexible manner.  We just need to
>> determine how to best wire that up into enhancement.
>
> Either check the deep state via the type system or consider an element
> as dirty when it is read.

Well yes, thats what I just said ;)  But that's not what I was asking.  
In my opinion it cannot be "dirty on read"; that is just asking for 
spurious writes.  We need to leverage Type here.  What I am asking is 
how to best achieve that.

Does it make sense to push the types to the enhanced entity and have it 
be responsible for doing that calculation?  Personally I don't think 
that is feasible.

I think the best option is that the enhanced entity tracks state it 
*knows* has changed.  From there we again have this option that says 
whether the user wants us to do "deep mutable state checking".  So with 
"deep mutable state checking" == true where we have state that (a) is 
of a mutable type and (b) the ehanced entity says is not dirty, we 
would do further Type.isDirty checks.


>> 3) Alternative means for lazy loading of entity state, meaning an
>> alternative to using proxies for the same purpose.  This is different,
>> too, from the current enhancement capability of lazy loading of property
>> state.  Lazy property loading is meant to delay loading of certain
>> field(s) until they are accessed.
>>
>
> You lost me on that one, I'm not sure what you mean here.

Well, currently we use proxies for lazy entity loading.  Even if 
entities are enhanced we still generate proxy classes and do lazy 
loading via that means.  Seems kind of redundant, no?

--
steve at hibernate.org
http://hibernate.org


More information about the hibernate-dev mailing list