You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@jena.apache.org by "ASF subversion and git services (JIRA)" <ji...@apache.org> on 2015/05/01 13:58:06 UTC

[jira] [Commented] (JENA-904) LPBRuleEngine leaks activeInterpreters

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

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

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

JENA-904: This closes #46


> 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)