Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » EclipseLink » NullPointerException in QueryKeyExpression.getQueryKeyOrNull(occurs only in multithreaded environment)
NullPointerException in QueryKeyExpression.getQueryKeyOrNull [message #551953] Tue, 10 August 2010 09:31 Go to next message
Ana Oleski is currently offline Ana OleskiFriend
Messages: 22
Registered: July 2009
Junior Member
We have this NullPointerException that only happens when several threads execute some batchjob on an AIX with 16 processors.

java.lang.NullPointerException
        at
org.eclipse.persistence.internal.expressions.QueryKeyExpression.getQueryKeyOrNull(QueryKeyExpression.java:472)

Full stacktrace below. Happens when we execute a ReadAllQuery with a simple selection criteria, expressionbuilder.get(attributeName).equal(value)

I stress this, it only happens in production when lots of threads start doing the same thing for all objects of class A. For instance all accounts are updated with interest rates.

Our application uses eclipselink native API. The ServerSession is instantiated
based on an project.xml, for each transaction we acquire a ClientSession and subsequently a UnitOfWork, execute the readAllQuery on the uow, do stuff, commit the transaction. Everything works fine except for the batchjobs

I've looked at the code and I think it can only be a weird threadrace

public QueryKey getQueryKeyOrNull() {
if (!hasQueryKey) {
return null;
}

// Oct 19, 2000 JED
// Added try/catch. This was throwing a NPE in the following case
// expresssionBuilder.get("firstName").get("bob")
//moved by Gordon Yorke to cover validate and normalize
if (getContainingDescriptor() == null) {
throw QueryException.invalidQueryKeyInExpression(getName());
}
if (queryKey == null) {

// //NPE here
queryKey = getContainingDescriptor().getQueryKeyNamed(getName());

if (queryKey == null) {
hasQueryKey = false;
}
}
return queryKey;

}
getContainingDescriptor() calls getDescriptor() either on ObjectExpression, on ExpressionBuilder or on MapEntryExpression. ObjectExpression is the superclass and the method looks like this

public ClassDescriptor getDescriptor() {
        if (isAttribute()) {
            return null;
        }
        if (descriptor == null) {
            // Look first for query keys, then mappings. Ultimately we should have query keys
            // for everything and can dispense with the mapping part.
            ForeignReferenceQueryKey queryKey = (ForeignReferenceQueryKey)getQueryKeyOrNull();
            if (queryKey != null) {
                descriptor = getSession().getDescriptor(queryKey.getReferenceClass());
                return convertToCastDescriptor(descriptor, getSession());
            }
            if (getMapping() == null) {
                throw QueryException.invalidQueryKeyInExpression(this);
            }

            // We assume this is either a foreign reference or an aggregate mapping
            descriptor = getMapping().getReferenceDescriptor();
            if (getMapping().isVariableOneToOneMapping()) {
                throw QueryException.cannotQueryAcrossAVariableOneToOneMapping(getMapping(), descriptor);
            }
            convertToCastDescriptor(descriptor, getSession());
        }
        return descriptor;

    }


descriptor is a transient member variable of the ObjectExpression class.
I think it might help to make it at least volatile. Or maybe the whole method should be synchronized.


Anyway, I've already filed about 5 months ago a bug for this problem: https://bugs.eclipse.org/bugs/show_bug.cgi?id=305112.
I'm writing in the forum because I would really like an workaround until the bug is hopefully fixed. Some way to trigger this method after login but before the threads start doing their work.

I'd be grateful for any suggestions,

Ana

java.lang.NullPointerException
        at org.eclipse.persistence.internal.expressions.QueryKeyExpression.getQueryKeyOrNull(QueryKeyExpression.java:472)

        at org.eclipse.persistence.internal.expressions.QueryKeyExpression.isAttribute(QueryKeyExpression.java:538)
        at org.eclipse.persistence.internal.expressions.RelationExpression.isObjectComparison(RelationExpression.java:449)

        at org.eclipse.persistence.internal.expressions.RelationExpression.doValuesConform(RelationExpression.java:160)
        at org.eclipse.persistence.internal.expressions.RelationExpression.doesConform(RelationExpression.java:134)
        at org.eclipse.persistence.expressions.Expression.doesConform(Expression.java:1314)
        at org.eclipse.persistence.internal.identitymaps.IdentityMapManager.getAllFromIdentityMap(IdentityMapManager.java:483)

        at org.eclipse.persistence.internal.sessions.IdentityMapAccessor.getAllFromIdentityMap(IdentityMapAccessor.java:305)

        at org.eclipse.persistence.internal.sessions.UnitOfWorkIdentityMapAccessor.getAllFromIdentityMap(UnitOfWorkIdentityMapAccessor.java:91)

        at org.eclipse.persistence.internal.sessions.IdentityMapAccessor.getAllFromIdentityMap(IdentityMapAccessor.java:281)

        at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.scanForConformingInstances(UnitOfWorkImpl.java:4682)

        at org.eclipse.persistence.queries.ReadAllQuery.conformResult(ReadAllQuery.java:252)
        at org.eclipse.persistence.queries.ReadAllQuery.registerResultInUnitOfWork(ReadAllQuery.java:706)
        at org.eclipse.persistence.queries.ReadAllQuery.executeObjectLevelReadQuery(ReadAllQuery.java:420)
        at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1074)
        at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:736)
        at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1034)
        at org.eclipse.persistence.queries.ReadAllQuery.execute(ReadAllQuery.java:380)
        at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1112)
        at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2909)
        at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1291)
        at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1273)
        at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1233)
        at de.jdpe.bof.bes.query.pm.SimpleQueryManager.performComparisonQuery(SimpleQueryManager.java:336)

 selectionCriteria=
Relation operator [ = ]
   Query Key kontonummer
      Base de.bkm.bes.kontosystem.konto.hauptbuch.BoHauptbuchkonto
   Constant 101000

[Updated on: Tue, 10 August 2010 09:34]

Report message to a moderator

Re: NullPointerException in QueryKeyExpression.getQueryKeyOrNull [message #552554 is a reply to message #551953] Thu, 12 August 2010 15:45 Go to previous messageGo to next message
James Sutherland is currently offline James SutherlandFriend
Messages: 1939
Registered: July 2009
Location: Ottawa, Canada
Senior Member

Very odd. The stack does not make much logical sense.

Could you please include the code you use to create and execute this query.
Are you reusing or caching expressions, expression builders or queries?

I noticed the error is occurring in conforming, does it still occur with conforming off?


James : Wiki : Book : Blog : Twitter
Re: NullPointerException in QueryKeyExpression.getQueryKeyOrNull [message #555287 is a reply to message #552554] Thu, 26 August 2010 08:36 Go to previous messageGo to next message
Ana Oleski is currently offline Ana OleskiFriend
Messages: 22
Registered: July 2009
Junior Member
Hi,

I've removed our own classes from the stacktrace to keep it short. The full stacktrace is here

https://bugs.eclipse.org/bugs/attachment.cgi?id=176212

The code is a little complicated so I've attached the whole class

https://bugs.eclipse.org/bugs/attachment.cgi?id=177500

to bug 305112

Basically the class receives our own queryRequest as parameter, which contains the entity classname, operation type, attribute and value and constructs a new brand new ReadAllQuery with new ExpressionBuilder each time.

But I see your point, why is the expression in case used by several threads...
I rembember something about an expression query cache in eclipselink? Is it still there? Could it have something to do with it?

Ana

P.S. Thank you for the quick answer! I forgot to switch 'notify me' on but still expected to receive a mail. Which of course never came.
Re: NullPointerException in QueryKeyExpression.getQueryKeyOrNull [message #555420 is a reply to message #551953] Thu, 26 August 2010 14:30 Go to previous messageGo to next message
James Sutherland is currently offline James SutherlandFriend
Messages: 1939
Registered: July 2009
Location: Ottawa, Canada
Senior Member

The is an Expression cache, it can be disabled on your descriptor sing,

descriptor.getQueryManager().setExpressionQueryCacheMaxSize( 0);

Please try this to see if this is the issue.

Also can you please try turning conforming off, does this resolve the issue?

If the query is always the same, you should convert it to a named query, this will be more efficient, and probably also resolve the issue. Can you please try this.


James : Wiki : Book : Blog : Twitter
Re: NullPointerException in QueryKeyExpression.getQueryKeyOrNull [message #555938 is a reply to message #555420] Mon, 30 August 2010 10:12 Go to previous messageGo to next message
Ana Oleski is currently offline Ana OleskiFriend
Messages: 22
Registered: July 2009
Junior Member
Turning conforming off is not an option. But we've disabled the query cache and we didn't get any exceptions last weekend so this might be the workaround we've been looking for.

I've been wondering about named queries. If there is a bug when using the query cache, because two threads are working with the same query object, what's to stop the bug manifesting itself when using the same named query?

Or are the named queries built in advance?
Re: NullPointerException in QueryKeyExpression.getQueryKeyOrNull [message #556078 is a reply to message #551953] Mon, 30 August 2010 17:50 Go to previous message
James Sutherland is currently offline James SutherlandFriend
Messages: 1939
Registered: July 2009
Location: Ottawa, Canada
Senior Member

If,

>> descriptor.getQueryManager().setExpressionQueryCacheMaxSize( 0);

fixes the issue, then it is a bug in the expression cache. Please indicate this in the bug and vote for the issue.

Named queries are processed differently, so the issue may not occur.




James : Wiki : Book : Blog : Twitter
Previous Topic:Lazy is not lazy
Next Topic:ObjectChangeSet always null
Goto Forum:
  


Current Time: Fri Dec 19 14:31:20 GMT 2014

Powered by FUDForum. Page generated in 0.09771 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software