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

ASF subversion and git services commented on JENA-904:
------------------------------------------------------

Commit 4edc6d38613970894165565000f9d1f1a50a6e4c in jena's branch 
refs/heads/master from [~andy.seaborne]
[ https://git-wip-us.apache.org/repos/asf?p=jena.git;h=4edc6d3 ]

JENA-904: Fix for LPBRuleEngine leaking activeInterpreters


> LPBRuleEngine leaks activeInterpreters
> --------------------------------------
>
>                 Key: JENA-904
>                 URL: https://issues.apache.org/jira/browse/JENA-904
>             Project: Apache Jena
>          Issue Type: Bug
>          Components: Ontology API
>            Reporter: Stian Soiland-Reyes (old)
>
> I found that activeInterpreters in LPBRuleEngine leaks also if you don't 
> iterate through to the end - calling .close() on the iterator is not enough. 
> Clean-up seems to only happen when it.hasNext() is called and it returns 
> false - so this could happen also in cases like where you return after 
> getting the first hit.
> {code}
>       @Test
>       public void testNotLeakingActiveInterpreters() throws Exception {
>               Graph data = Factory.createGraphMem();
>               data.add(new Triple(a, ty, C1));
>               data.add(new Triple(b, ty, C1));
>               List<Rule> rules = Rule
>                               .parseRules("[r1:  (?x p ?t) <- (?x rdf:type 
> C1), makeInstance(?x, p, C2, ?t)]"
>                                               + "[r2:  (?t rdf:type C2) <- 
> (?x rdf:type C1), makeInstance(?x, p, C2, ?t)]");
>               FBRuleInfGraph infgraph = (FBRuleInfGraph) 
> createReasoner(rules).bind(
>                               data);
>               LPBRuleEngine engine = getEngineForGraph(infgraph);
>               assertEquals(0, engine.activeInterpreters.size());
>               assertEquals(0, engine.tabledGoals.size());
>               // we ask for a non-hit -- it works, but only because we call 
> it.hasNext()
>               ExtendedIterator<Triple> it = infgraph.find(nohit, ty, C1);
>               assertFalse(it.hasNext());
>               it.close();
>               assertEquals(0, engine.activeInterpreters.size());
>               // and again.
>               // Ensure this is not cached by asking for a different triple 
> pattern
>               ExtendedIterator<Triple> it2 = infgraph.find(nohit, ty, C2);
>               // uuups, forgot to call it.hasNext(). But .close() should tidy
>               it2.close();
>               assertEquals(0, engine.activeInterpreters.size());
>               
>               // OK, let's ask for something that is in the graph
>               
>               ExtendedIterator<Triple> it3 = infgraph.find(a, ty, C1);
>               assertTrue(it3.hasNext());
>               assertEquals(a, it3.next().getMatchSubject());
>               
>               // .. and what if we forget to call next() to consume b?
>               // (e.g. return from a method with the first hit)
>               
>               // this should be enough
>               it3.close();
>               // without leaks of activeInterpreters
>               assertEquals(0, engine.activeInterpreters.size());
>       }
> {code}
> When investigating this, I got as far as seeing that the activeInterpreters 
> is normally closed from hasNext() when it reaches the end here:
> https://github.com/apache/jena/blob/master/jena-core/src/main/java/com/hp/hpl/jena/reasoner/rulesys/impl/Generator.java#L303
> which is a zombie check.. but this doesn't work when hasNext() hasn't reach 
> the end, even though it is also called from close() here:
> https://github.com/apache/jena/blob/master/jena-core/src/main/java/com/hp/hpl/jena/reasoner/rulesys/impl/LPTopGoalIterator.java#L199
> Moving the checkForCompletions further down and calling .close() on any 
> nextToRun or lookAhead was not sufficient - there is always a secondary 
> Generator in the list which is not removed - only the top-level one is 
> removed normally.
> I was unable to investigate any further as I could not understand the classes 
> that were creating the two Generators. 
> The inner LPInterpreter 147 is first created from generatorFor() call from 
> ConsumerChoicePointFrame constructor within LPInterpreter.setupTabledCall 
> which is coming from the ruleEngine.find.
> This outer LPInterpreter is then added as part of the find().
> In "normal operation" the inner one is removed through the zombie clearing, 
> while the outer one is removed through .close()
> If you don't iterate through to the end, the inner one is not removed.



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

Reply via email to