[ 
https://issues.apache.org/jira/browse/JENA-1260?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15669912#comment-15669912
 ] 

Dave Reynolds commented on JENA-1260:
-------------------------------------

Those HashSets really shouldn't be static, that would mean having multiple 
TransitiveReasoners in use in the same JVM, even without concurrency, would 
fail. Not sure how that's lurked for so long!

Steve - thanks for the very clear report and analysis.


> NullPointerException when using an inferencing model under multithreaded load 
> with query and delete
> ---------------------------------------------------------------------------------------------------
>
>                 Key: JENA-1260
>                 URL: https://issues.apache.org/jira/browse/JENA-1260
>             Project: Apache Jena
>          Issue Type: Bug
>          Components: Jena
>    Affects Versions: Jena 3.0.0
>            Reporter: Stephen Owens
>            Assignee: Dave Reynolds
>         Attachments: TransitiveEngineFailureTest.java
>
>
> {noformat}
> java.lang.NullPointerException
>       at java.util.HashSet.contains(HashSet.java:203)
>       at 
> org.apache.jena.reasoner.transitiveReasoner.TransitiveEngine.triage(TransitiveEngine.java:194)
>       at 
> org.apache.jena.reasoner.transitiveReasoner.TransitiveEngine.add(TransitiveEngine.java:234)
>       at 
> org.apache.jena.reasoner.rulesys.FBRuleInfGraph.prepare(FBRuleInfGraph.java:431)
>       at 
> org.apache.jena.reasoner.BaseInfGraph.requirePrepared(BaseInfGraph.java:530)
>       at 
> org.apache.jena.reasoner.rulesys.FBRuleInfGraph.findWithContinuation(FBRuleInfGraph.java:557)
>       at 
> org.apache.jena.reasoner.rulesys.FBRuleInfGraph.graphBaseFind(FBRuleInfGraph.java:587)
>       at org.apache.jena.graph.impl.GraphBase.find(GraphBase.java:255)
>       at 
> org.apache.jena.sparql.engine.iterator.QueryIterTriplePattern$TripleMapper.<init>(QueryIterTriplePattern.java:75)
>       at 
> org.apache.jena.sparql.engine.iterator.QueryIterTriplePattern.nextStage(QueryIterTriplePattern.java:49)
>       at 
> org.apache.jena.sparql.engine.iterator.QueryIterRepeatApply.makeNextStage(QueryIterRepeatApply.java:108)
>       at 
> org.apache.jena.sparql.engine.iterator.QueryIterRepeatApply.hasNextBinding(QueryIterRepeatApply.java:65)
>       at 
> org.apache.jena.sparql.engine.iterator.QueryIteratorBase.hasNext(QueryIteratorBase.java:111)
>       at 
> org.apache.jena.sparql.engine.iterator.QueryIterBlockTriples.hasNextBinding(QueryIterBlockTriples.java:63)
>       at 
> org.apache.jena.sparql.engine.iterator.QueryIteratorBase.hasNext(QueryIteratorBase.java:111)
>       at 
> org.apache.jena.sparql.engine.iterator.QueryIteratorWrapper.hasNextBinding(QueryIteratorWrapper.java:39)
>       at 
> org.apache.jena.sparql.engine.iterator.QueryIteratorBase.hasNext(QueryIteratorBase.java:111)
>       at 
> org.apache.jena.sparql.engine.iterator.QueryIteratorWrapper.hasNextBinding(QueryIteratorWrapper.java:39)
>       at 
> org.apache.jena.sparql.engine.iterator.QueryIteratorBase.hasNext(QueryIteratorBase.java:111)
>       at org.apache.jena.atlas.iterator.Iter$4.hasNext(Iter.java:264)
>       at 
> org.apache.jena.ext.com.google.common.collect.Iterators$5.hasNext(Iterators.java:547)
>       at 
> org.apache.jena.test.TransitiveEngineFailureTest$FailureTask.execQuery(TransitiveEngineFailureTest.java:109)
>       at 
> org.apache.jena.test.TransitiveEngineFailureTest$FailureTask.call(TransitiveEngineFailureTest.java:75)
>       at 
> org.apache.jena.test.TransitiveEngineFailureTest$FailureTask.call(TransitiveEngineFailureTest.java:1)
>       at java.util.concurrent.FutureTask.run(FutureTask.java:266)
>       at 
> java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
>       at 
> java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
>       at java.lang.Thread.run(Thread.java:745)
> {noformat}
> This failure is due to the 
> {{org.apache.jena.reasoner.transitiveReasoner.TransitiveEngine}} class 
> declaring the {{subClassAliases}}
> member variable (of type HashSet<Node>) as static. The prepare method 
> re-creates this shared variable whenever {{isPrepared}}
> is false:
> {noformat}
>     private void prepare() {
>         if (isPrepared) return;
>         subClassAliases = new HashSet<>();
>         . . .
>         isPrepared = true;
>     }
> {noformat}
> In particular, the static {{subClassAliases}} variable will be re-created 
> whenever a {{TransitiveEngine}} object is created
> ({{isPrepared}} is false at creation time). Note that HashSet is neither 
> thread-safe nor being accessed in a thread-safe manner.
> The combination of attempting to remove triples from the model and attempting 
> to execute queries on the model leads
> to unsafe accesses to {{subClassAliases}}, which eventually leads to a null 
> pointer exception.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to