Bug 1019473 - NPE when using Phreak related to activation matches
NPE when using Phreak related to activation matches
Status: CLOSED CURRENTRELEASE
Product: JBoss BRMS Platform 6
Classification: JBoss
Component: BRE (Show other bugs)
6.0.0
Unspecified Unspecified
high Severity high
: ER5
: 6.0.0
Assigned To: Edson Tirelli
Tomas David
:
Depends On:
Blocks:
  Show dependency treegraph
 
Reported: 2013-10-15 15:42 EDT by Richard Bourner
Modified: 2014-08-06 16:15 EDT (History)
3 users (show)

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2014-08-06 16:15:32 EDT
Type: Bug
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---


Attachments (Terms of Use)

  None (edit)
Description Richard Bourner 2013-10-15 15:42:28 EDT
Description of problem:
A problem occurs when switching from Rete to Phreak.
We get a NPE in the following code:
// @TODO (mdp) is this really necessary? won't the entire FH and RightTuple chaines just et GC'd?
unlinkCreatedHandles(leftTuple); 

On line 268 : leftTuple.getObject

It seems like the 'match' is null at t+1 but it was not at t. 

An extract of our rules is:
rule A
  when
     ...
  then
     context.delete("D1");
end

rule B
  when
    Object(...) from context.get("D1")
  then
    ...
end


Unfortunately, we haven't reproduced the bug yet in a unit test.


Version-Release number of selected component (if applicable):


How reproducible:


Steps to Reproduce:
1.
2.
3.

Actual results:


Expected results:


Additional info:
java.lang.NullPointerException
        at org.drools.core.phreak.PhreakFromNode.unlinkCreatedHandles(PhreakFromNode.java:268)
        at org.drools.core.phreak.PhreakFromNode.doLeftDeletes(PhreakFromNode.java:258)
        at org.drools.core.phreak.PhreakFromNode.doNode(PhreakFromNode.java:41)
        at org.drools.core.phreak.RuleNetworkEvaluator.innerEval(RuleNetworkEvaluator.java:348)
        at org.drools.core.phreak.RuleNetworkEvaluator.outerEval(RuleNetworkEvaluator.java:162)
        at org.drools.core.phreak.RuleNetworkEvaluator.evaluateNetwork(RuleNetworkEvaluator.java:117)
        at org.drools.core.phreak.RuleExecutor.reEvaluateNetwork(RuleExecutor.java:199)
        at org.drools.core.phreak.RuleExecutor.evaluateNetworkAndFire(RuleExecutor.java:66)
        at org.drools.core.common.DefaultAgenda.fireNextItem(DefaultAgenda.java:927)
        at org.drools.core.common.DefaultAgenda.fireAllRules(DefaultAgenda.java:1187)
        at org.drools.core.common.AbstractWorkingMemory.fireAllRules(AbstractWorkingMemory.java:957)
        at org.drools.core.common.AbstractWorkingMemory.fireAllRules(AbstractWorkingMemory.java:931)
        at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:233)
        at fr.edf.distribution.linky.lsp.DefaultTestWithSession.launchRules(DefaultTestWithSession.java:45)
        at fr.edf.distribution.linky.lsp.TestRulesOnDysf.testRG_MO_02(TestRulesOnDysf.java:53)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
        at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:77)
        at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:195)
        at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:63)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Comment 2 Mario Fusco 2013-10-17 04:36:38 EDT
I also tried to reproduce this problem but hadn't better luck. I am assuming the 'context' in your rules is a global variable, is that correct? With this assumption I tried to use a DRL like:

global java.util.Map context

rule A
  when
  then
     context.remove("key");
end

rule B
  when
    $s : String() from context.get("key")
  then
    System.out.println($s);
end

and do something like this on the session:

Map<String, String> context = new HashMap<String, String>();
context.put("key", "value");
session.setGlobal("context", context);
session.fireAllRules();

I also tried to populate the Map from inside another rule, to guard the executions of the rules with additional patterns or to change their order using salience, but nothing helped to reproduce the problem.

Without a proper reproducer it is impossible for me to fix this issue. Do you have further information that could help me to write that reproducer?
Comment 3 Richard Bourner 2013-10-17 15:26:16 EDT
Yes context is a global.
Unfortunately, we have put this problem on the side for now. I hope we can get back to it later and try to reproduce.  The problem is definitively there as it breaks with our "real" rules using PHREAK but not with RETE, but it seems more difficult to isolate it. We switched to RETE until we get more time to work on this.
As I saw the comment in the source code (typicaly the TODO), I was hoping that this was something unfinished and would be a problem that you might be aware of already.
More on this later.
Comment 4 Edson Tirelli 2013-10-18 18:31:49 EDT
I was able to reproduce the problem. It happens when the FROM node receives both a left insert and a left retract that get queued, and then they are evaluated at the same time.

Fix:
6.0.x: http://github.com/droolsjbpm/drools/commit/affb4e389
master: http://github.com/droolsjbpm/drools/commit/4e5187c63

Richard, this problem was not related to the mutable global you mentioned in the problem description but this is something that should not be done in rules. 

* Globals that are used as part of the "condition" of a rule must be immutable.

* Globals that are not used as part of the "conditions" of rules can be mutable.

* If one needs to use a condition on a mutable object, then the object must be a fact inserted into the session and every time the object is changed, the engine must be notified using update/modify. 

From the docs:

http://docs.jboss.org/drools/release/6.0.0.CR5/drools-expert-docs/html_single/index.html#d0e4569

"With global you define global variables. They are used to make application objects available to the rules. Typically, they are used to provide data or services that the rules use, especially application services used in rule consequences, and to return data from the rules, like logs or values added in rule consequences, or for the rules to interact with the application, doing callbacks. Globals are not inserted into the Working Memory, and therefore a global should never be used to establish conditions in rules except when it has a constant immutable value. The engine cannot be notified about value changes of globals and does not track their changes. Incorrect use of globals in constraints may yield surprising results - surprising in a bad way."
Comment 5 Tomas David 2013-12-11 05:32:43 EST
Verified on BRMS 6.0.0.ER5.

Note You need to log in before you can comment on or make changes to this bug.