[Hibernate-JIRA] Created: (HHH-6848) The duration of hibernate merge rises quadratically with the amount of entities in a to be merged objectgraph
by Wim Ockerman (JIRA)
The duration of hibernate merge rises quadratically with the amount of entities in a to be merged objectgraph
-------------------------------------------------------------------------------------------------------------
Key: HHH-6848
URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-6848
Project: Hibernate Core
Issue Type: Improvement
Components: core
Affects Versions: 4.0.0.CR6, 3.6.8
Environment: Any Hibernate version, any database platform.
Reporter: Wim Ockerman
Attachments: HibernateMergeMeasurementBeforeAndAfterSolution.png, Sample_JProfiler_hotspot_research_in_a_merge_of_a_big_object_graph.png
Tests with merging large objectgraphs showed quadratic rise of duration of the merge related to the object-graph size.
>From a certain number of objects in the graph this becomes substantial.
This limits hibernate scalability for larger object-graph usages.
Analysis (based on 3.6.8 code branch):
The merge algorithm of hibernate is a recursive objectgraph walking algorithm. During it's execution it builds up algorithm state information e.g. of merged entities to original objects in the input graph. The information is stored in the EventCache object in the *entityToCopyMap* member. ( org.hibernate.event.def.EventCache)
At certain places in the merge algorithm the inverse relation as hold in the EventCache object is needed.
see e.g. def.AbstractSaveEventListener.performSaveOrReplicate -> calling persister.getPropertyValuesToInsert(.., *getMergeMap()*,..)
The getMergeMap() call calls through to the EventCache's invertMap method.
In the implementation of invertMap() a new map is created on the spot and all the elements in the entityToCopyMap where put in, now as copy to entity direction.
The call invertMap() happens more in a big detached graph wile merging, and also the size of the entityToCopyMap rises with the number of object already merged in the graph. Thus we have a quadratic relation between the total inverMap() execution time and the number of objects in a graph to be merged.
JProfiler screenshot sample attached showing a high call count and high duration time on the invertMap method in a merge vs time it took for a flush of the merged object graph. The latter was unexpected, as the flush time is a good higher bound reference for an object graph operation.
To solve this problem see proposed solution in pull request #208 of [hibernate-core] Performance Optimization of in memory merge algorithm.
With the solution, the merge duration behaves more linear with respect to the size of the to be merged objectgraph.
See attached plot of the original hibernate merge behaviour vs entities in a graph (redline) and the proposed solution's timeing.
--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira
12 years, 8 months
[Hibernate-JIRA] Created: (HHH-3718) call to id getter initializes proxy when using AccessType( "field" )
by Paul Lorenz (JIRA)
call to id getter initializes proxy when using AccessType( "field" )
--------------------------------------------------------------------
Key: HHH-3718
URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-3718
Project: Hibernate Core
Issue Type: Bug
Components: core
Affects Versions: 3.3.1
Environment: hibernate 3.3.1, hibernate annotations 3.4.0, running on windows, linux and solaris, using sybase 15
Reporter: Paul Lorenz
Calling getter for id when using AccessType( "field" ) causes proxy initialization.
In org.hibernate.proxy.proxy.pojo.BasicLazyInitializer there is the code
else if ( isUninitialized() && method.equals(getIdentifierMethod) ) {
return getIdentifier();
}
However, when using field access, the getIdentifierMethod will be null. I fixed this for us by changing DirectPropertyAccessor by adding a Method attribute to the DirectGetter inner class, and looking up the appropriate getter in the constructor. As far as I can tell, getMethod is only used in two places. In the above case, to the get the identity getter and in PojoComponentTupilizer.isMethodOf. This doesn't seem to break anything. I don't know if this is a clean solution, seems a little hacky to me, however, it would be great if the issue could be fixed somehow.
public static final class DirectGetter implements Getter {
private final transient Field field;
private final Class clazz;
private final String name;
private Method method;
DirectGetter(Field field, Class clazz, String name) {
this.field = field;
this.clazz = clazz;
this.name = name;
try
{
BeanInfo beanInfo = Introspector.getBeanInfo( clazz );
PropertyDescriptor[] pdArray = beanInfo.getPropertyDescriptors();
if ( pdArray != null )
{
for (PropertyDescriptor pd : pdArray )
{
if ( pd.getName().equals( name ) )
{
this.method = pd.getReadMethod();
}
}
}
}
catch ( Exception e )
{
// ignore
}
}
public Object get(Object target) throws HibernateException {
try {
return field.get(target);
}
catch (Exception e) {
throw new PropertyAccessException(e, "could not get a field value by reflection", false, clazz, name);
}
}
public Object getForInsert(Object target, Map mergeMap, SessionImplementor session) {
return get( target );
}
public Method getMethod() {
return method;
}
public String getMethodName() {
return method == null ? null : method.getName();
}
public Class getReturnType() {
return field.getType();
}
Object readResolve() {
return new DirectGetter( getField(clazz, name), clazz, name );
}
public String toString() {
return "DirectGetter(" + clazz.getName() + '.' + name + ')';
}
}
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators....
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
12 years, 8 months
[Hibernate-JIRA] Created: (HHH-7297) ScrollableResults#close throws an exception when called outside of a transaction
by Ittay Dror (JIRA)
ScrollableResults#close throws an exception when called outside of a transaction
--------------------------------------------------------------------------------
Key: HHH-7297
URL: https://hibernate.onjira.com/browse/HHH-7297
Project: Hibernate ORM
Issue Type: Bug
Components: core
Affects Versions: 3.6.9
Reporter: Ittay Dror
I have a repository class who is transactional but used by other classes that are not. One of its methods returns a ScrollableResults object. Using this object works fine (outside of a transaction), but calling close() throws an exception:
org.hibernate.SessionException: Session is closed!
at org.hibernate.impl.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:72) ~[hibernate-core-3.6.9.Final.jar:3.6.9.Final]
at org.hibernate.impl.SessionImpl.getBatcher(SessionImpl.java:305) ~[hibernate-core-3.6.9.Final.jar:3.6.9.Final]
at org.hibernate.impl.AbstractScrollableResults.close(AbstractScrollableResults.java:122) ~[hibernate-core-3.6.9.Final.jar:3.6.9.Final]
--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira
12 years, 8 months
[Hibernate-JIRA] Created: (HHH-7296) NPE in JtaTransaction#markRollbackOnly
by Steve Ebersole (JIRA)
NPE in JtaTransaction#markRollbackOnly
--------------------------------------
Key: HHH-7296
URL: https://hibernate.onjira.com/browse/HHH-7296
Project: Hibernate ORM
Issue Type: Bug
Components: core
Reporter: Steve Ebersole
Assignee: Steve Ebersole
Fix For: 4.1.3
Mainly this comes up in usage within Spring with Spring-managed transactions. The problem being that transactions are really "container managed", just in a Spring-specific way. Spring managed transactions to not expose access to TM, so Hibernate users in Spring are forced to use JtaTransactionFactory but the HIbernate transaction API is not used control the transactions, so if calls come into JtaTransaction#markRollbackOnly under these circumstances the userTransaction instance state is null (since #begin was never called).
--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira
12 years, 8 months
[Hibernate-JIRA] Created: (HHH-7252) EntityManager not retaining LockOptions context when mapping exceptions.
by Bryan Varner (JIRA)
EntityManager not retaining LockOptions context when mapping exceptions.
------------------------------------------------------------------------
Key: HHH-7252
URL: https://hibernate.onjira.com/browse/HHH-7252
Project: Hibernate ORM
Issue Type: Bug
Components: entity-manager
Affects Versions: 4.1.2
Environment: PostgreSQL 9.1
Reporter: Bryan Varner
Priority: Critical
AbstractEntityManagerImpl.java:791 (Implementation of EntityManager.find())
This line defines a local LockOptions and sets it to null.
A conditional execution for including lock options on line 795 evaluates the LockOptions but never sets it back to the local.
When an exception occurs (lock timeout, or otherwise) the lockOptions have not been set to anything but null, and incorrect exceptions are resolved and thrown.
Specifically, you get PessimisticLockException even when you should get LockTimeoutException.
This is marking transactions as rollback only, and causing subsequent code to fail gloriously.
Below is the offensive function, notice that lockOptions is never set to anything other than =null.
{code}
public <A> A find(Class<A> entityClass, Object primaryKey, LockModeType lockModeType, Map<String, Object> properties) {
CacheMode previousCacheMode = getSession().getCacheMode();
CacheMode cacheMode = determineAppropriateLocalCacheMode( properties );
LockOptions lockOptions = null;
try {
getSession().setCacheMode( cacheMode );
if ( lockModeType != null ) {
return ( A ) getSession().get(
entityClass, ( Serializable ) primaryKey,
getLockRequest( lockModeType, properties )
);
}
else {
return ( A ) getSession().get( entityClass, ( Serializable ) primaryKey );
}
}
catch ( ObjectDeletedException e ) {
//the spec is silent about people doing remove() find() on the same PC
return null;
}
catch ( ObjectNotFoundException e ) {
//should not happen on the entity itself with get
throw new IllegalArgumentException( e.getMessage(), e );
}
catch ( MappingException e ) {
throw new IllegalArgumentException( e.getMessage(), e );
}
catch ( TypeMismatchException e ) {
throw new IllegalArgumentException( e.getMessage(), e );
}
catch ( ClassCastException e ) {
throw new IllegalArgumentException( e.getMessage(), e );
}
catch ( HibernateException he ) {
throw convert( he, lockOptions );
}
finally {
getSession().setCacheMode( previousCacheMode );
}
}
{code}
--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira
12 years, 8 months