Hi,
I think we have identified two issues with how the Hibernate handles 2nd level cache updates in conjunction with EhCache in CacheConcurrencyStrategy.READ_WRITE mode. Are these issues known?
1. In case of versioned entities: A version update will be written to the 2nd level cache but not the database, this can lead to an spurious transaction conflict.
The problem seems to originate in DefaultFlushEntityEventListener which performs the following: * DefaultFlushEntityEventListener:154 - Checks if an update is necessary by checking the current state with the loaded state. * DefaultFlushEntityEventListener:287 - In case that the entity has been found to be dirty, entity callbacks are invoked and the list of dirty entity properties is recreated. * DefaultFlushEntityEventListener:304 - In case that the entity callbacks modified the entity such that the current state does not differ from the loaded state the list of dirty properties is initialize to be empty. * EntityUpdateAction:113 - The persister performs a check of its own and in case that there are no dirty properties nothing will be written to the database. * EntityUpdateAction:260 - After the transaction commits things are written to the 2nd level cache.
Not sure if the above explanation is clear (it took me quite a bit of time to understand what was going). Interesting consequence of the above is that in case that a versioned entity has dirty properties and dirty collections the entity version will not be increased (I think this is a guaranteed).
2. 2nd level collection locks are not properly released in case of an optimistic conflict. This leads to the 2nd level collection entries being not refreshed with data from database. The locks will indicate a collision with another transaction (except that there is no other transaction). Only once the locks expire will the entries be filled with real data.
The problem seems to originate in ActionQueue which performs the following steps: * ActionQueue:199 - Run collection update prepare actions. This causes that the actual contents of the 2nd level cache are replaced with a lock. * ActionQueue:185 - Run entity update actions. In case that an optimistic conflict is detected (such as caused by the first issue) the collection locks are not released as the necessary code CollectionAction:180 is not executed.
A not expired AbstractReadWriteEhCacheAccessStrategy.Lock is not writtable in case multiplicity > 0.
regards, juraj
|