[JBoss JIRA] (DROOLS-1087) KieBase update wrong match for rules containing constraints over the accumulate
by Mario Fusco (JIRA)
[ https://issues.jboss.org/browse/DROOLS-1087?page=com.atlassian.jira.plugi... ]
Mario Fusco resolved DROOLS-1087.
---------------------------------
Resolution: Rejected
To recap, the problem you're reporting (at least for 6.4) is that the accumulate rule refires after incremental compilation even if you don't expect this. I demonstrated this behaviour in a simplified way with the following test case.
{code}
@Test
public void testAccumulate() throws Exception {
// DROOLS-1087
String drl1 =
"rule R1 when\n" +
" accumulate ( $s: String(); $n : count($s); $n > 0 )\n" +
"then\n" +
" System.out.println(\"HERE\");\n" +
"end\n";
String drl2 = drl1 + " "; // just a trivial update
KieServices ks = KieServices.Factory.get();
ReleaseId releaseId1 = ks.newReleaseId( "org.kie", "test-upgrade", "1.0.0" );
KieModule km = createAndDeployJar( ks, releaseId1, drl1 );
KieContainer kc = ks.newKieContainer( km.getReleaseId() );
KieSession ksession = kc.newKieSession();
ksession.insert( "Hello World" );
assertEquals( 1, ksession.fireAllRules() );
ReleaseId releaseId2 = ks.newReleaseId( "org.kie", "test-upgrade", "1.1.0" );
km = createAndDeployJar( ks, releaseId2, drl2 );
kc.updateToVersion( releaseId2 );
assertEquals( 0, ksession.fireAllRules() ); // this assertion fails
}
{code}
The problem here is that drools incremental compilation works at resources level. This means that when a resource is changed all artifacts created from that resource are removed from the KieBase and recreated. The accumulate rule then behaves like a brand new rule that has been just added to the KieBase and since the conditions to make it fire for the first time are met there's no reason why it shouldn't.
One final note on the no-loop attribute. The only purpose of this attribute is avoiding that the execution of a rule's consequence could re-activate the rule itself. Since the consequences of your rules just prints on the standard output there's no chance that this could happen, so using the no-loop in this context is totally irrelevant.
> KieBase update wrong match for rules containing constraints over the accumulate
> -------------------------------------------------------------------------------
>
> Key: DROOLS-1087
> URL: https://issues.jboss.org/browse/DROOLS-1087
> Project: Drools
> Issue Type: Bug
> Components: core engine
> Affects Versions: 6.2.0.Final, 6.3.0.Final, 6.4.0.Beta2
> Reporter: Matteo Mortari
> Assignee: Mario Fusco
> Attachments: 20160309.DROOLS-1087.zip
>
>
> Ciao, I will attach reproducer with same style as {{org.drools.compiler.integrationtests.IncrementalCompilationTest.testIncrementalCompilation}} / {{testIncrementalCompilationWithRedeclares}}
> h2. Executive summary
> When performing KieBase update, rules containing constraints over the accumulate Event, are firing with wrong matches and/or firing for already seen matches and violating the no-loop.
> h2. Detailed description of the reproducer.
> Assume a KB starting with only these two rules:
> {code}
> declare Measurement
> @role(event)
> end
> rule "color RED seen in the last 2 minutes"
> no-loop
> when
> accumulate ( $token: Measurement( id == "color", $colorVal : val, $colorVal == "red") over window:time(2m);
> $mySet : collectSet( $colorVal ),
> $val : count($token) ;
> $val >= 1
> )
> then
> System.out.println("I have seen color RED in the last 2m "+$mySet);
> end
> rule "color GREEN seen in the last 2 minutes"
> no-loop
> when
> accumulate ( $token: Measurement( id == "color", $colorVal : val, $colorVal == "green") over window:time(2m);
> $mySet : collectSet( $colorVal ),
> $val : count($token) ;
> $val >= 1
> )
> then
> System.out.println("I have seen color GREEN in the last 2m "+$mySet);
> end
> {code}
> and then on upgrade/update, the same rule as above un-touched, but additionally the following rule:
> {code}
> rule "id X seen in the last 2 minutes"
> no-loop
> when
> accumulate ( $token: Measurement( id == "x", $colorVal : val) over window:time(2m);
> $mySet : collectSet( $colorVal ),
> $val : count($token) ;
> $val >= 1
> )
> then
> System.out.println("I have seen Measurement for id=x in the last 2m "+$mySet);
> end
> {code}
> Where {{Measurement}} just a POJO as per Kie Artifact, basically containing fields: {{String id;String val;}}
> with the following of Measurement insertions, one at each minute:
> {code}
> -> Measurement [id=color, val=red]
> (KB update here)
> -> Measurement [id=x, val=x]
> -> Measurement [id=color, val=green]
> ...
> {code}
> the following problems are highlighted:
> h6. Drools version 6.2.0.Final with Reteoo
> The problem is highlighted after the 2nd Measurment event insertion below, the rules "color GREEN seen in the last 2 minutes" and "id X seen in the last 2 minutes" are firing with wrong matches, because:
> * the rule "color GREEN seen in the last 2 minutes" should fire only for {{Measurement\[id=color, val=green]}} Events, which has not occured, and is matching instead over {{Measurement\[id=color, val=red]}}
> * the rule "id X seen in the last 2 minutes" should fire only for {{Measurement\[id=x, _]}} Events, but is considering also the {{Measurement\[id=color, _]}} event which occured earlier.
> {code}
> 2016-03-09 09:33:20,952 INFO [org.drools.compiler.kie.builder.impl.KieRepositoryImpl] (main) KieModule was added: MemoryKieModule[releaseId=org.test:test:1.0.0]
> 2016-03-09 09:33:21,240 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) There should be rules:
> 2016-03-09 09:33:21,240 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) kp [Package name=com.acme.accumulateUpgradeTest] rule color RED seen in the last 2 minutes
> 2016-03-09 09:33:21,240 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) kp [Package name=com.acme.accumulateUpgradeTest] rule color GREEN seen in the last 2 minutes
> 2016-03-09 09:33:21,240 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) Creating kieSession
> 2016-03-09 09:33:21,319 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) Now running data
> 2016-03-09 09:33:21,321 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) advance clock @ 60000
> -> Measurement [id=color, val=red]
> I have seen color RED in the last 2m [red]
> 2016-03-09 09:33:21,539 INFO [org.drools.compiler.kie.builder.impl.KieRepositoryImpl] (main) KieModule was added: MemoryKieModule[releaseId=org.test:test:1.0.1]
> 2016-03-09 09:33:21,743 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) Update of KB performed.
> 2016-03-09 09:33:21,744 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) kp [Package name=com.acme.accumulateUpgradeTest] rule color RED seen in the last 2 minutes
> 2016-03-09 09:33:21,744 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) kp [Package name=com.acme.accumulateUpgradeTest] rule color GREEN seen in the last 2 minutes
> 2016-03-09 09:33:21,744 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) kp [Package name=com.acme.accumulateUpgradeTest] rule id X seen in the last 2 minutes
> 2016-03-09 09:33:21,744 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) advance clock @ 120000
> -> Measurement [id=x, val=x]
> I have seen Measurement for id=x in the last 2m [red, x]
> I have seen color GREEN in the last 2m [red]
> I have seen color RED in the last 2m [red]
> 2016-03-09 09:33:21,750 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) advance clock @ 180000
> <- Measurement [id=color, val=red]
> -> Measurement [id=color, val=green]
> I have seen color GREEN in the last 2m [green]
> I have seen Measurement for id=x in the last 2m [x]
> 2016-03-09 09:33:21,752 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) advance clock @ 240000
> <- Measurement [id=x, val=x]
> -> Measurement [id=color, val=blue]
> 2016-03-09 09:33:21,752 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) Final checks
> {code}
> h6. Drools version 6.2.0.Final with Phreak
> NPE
> {code}
> java.lang.NullPointerException
> at org.drools.core.reteoo.NodeTypeEnums.isBetaNode(NodeTypeEnums.java:87)
> at org.drools.core.phreak.RuleNetworkEvaluator.innerEval(RuleNetworkEvaluator.java:252)
> at org.drools.core.phreak.RuleNetworkEvaluator.outerEval(RuleNetworkEvaluator.java:161)
> at org.drools.core.phreak.RuleNetworkEvaluator.evaluateNetwork(RuleNetworkEvaluator.java:116)
> at org.drools.core.phreak.RuleExecutor.evaluateNetwork(RuleExecutor.java:92)
> at org.drools.core.common.DefaultAgenda.evaluateEagerList(DefaultAgenda.java:1044)
> at org.drools.core.common.DefaultAgenda.fireNextItem(DefaultAgenda.java:996)
> at org.drools.core.common.DefaultAgenda.fireAllRules(DefaultAgenda.java:1302)
> at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:1289)
> at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:1262)
> at com.acme.accumulateUpgradeTest.RuleTest.test(RuleTest.java:185)
> {code}
> h6. Drools version 6.3.0.Final with Reteoo
> Not in scope of this JIRA record. I think this release had a bug when running with the setup of this reproducer because if I try I get NPE at {{org.drools.core.RuleBaseConfiguration.configureReteComponentFactory()}}
> h6. Drools version 6.3.0.Final with Phreak
> Same NPE as "6.2.0.Final with Phreak"
> h6. Drools version 6.4.0.Beta2 with Reteoo
> Same problem as "6.2.0.Final with Reteoo"
> h6. Drools version 6.4.0.Beta2 with Phreak
> Better, but I'm not sure why rule "color RED seen in the last 2 minutes" is firing again after the rule-update, it is no-loop and the conditions of the rules are the same as before the rule-update, hence I'm not sure why it fired again.
> {code}
> 2016-03-09 09:45:25,301 INFO [org.drools.compiler.kie.builder.impl.KieRepositoryImpl] (main) KieModule was added: MemoryKieModule[releaseId=org.test:test:1.0.0]
> 2016-03-09 09:45:25,594 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) There should be rules:
> 2016-03-09 09:45:25,594 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) kp [Package name=com.acme.accumulateUpgradeTest] rule color RED seen in the last 2 minutes
> 2016-03-09 09:45:25,594 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) kp [Package name=com.acme.accumulateUpgradeTest] rule color GREEN seen in the last 2 minutes
> 2016-03-09 09:45:25,594 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) Creating kieSession
> 2016-03-09 09:45:25,696 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) Now running data
> 2016-03-09 09:45:25,698 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) advance clock @ 60000
> -> Measurement [id=color, val=red]
> I have seen color RED in the last 2m [red]
> 2016-03-09 09:45:25,854 INFO [org.drools.compiler.kie.builder.impl.KieRepositoryImpl] (main) KieModule was added: MemoryKieModule[releaseId=org.test:test:1.0.1]
> 2016-03-09 09:45:26,023 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) Update of KB performed.
> 2016-03-09 09:45:26,023 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) kp [Package name=com.acme.accumulateUpgradeTest] rule color RED seen in the last 2 minutes
> 2016-03-09 09:45:26,023 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) kp [Package name=com.acme.accumulateUpgradeTest] rule color GREEN seen in the last 2 minutes
> 2016-03-09 09:45:26,023 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) kp [Package name=com.acme.accumulateUpgradeTest] rule id X seen in the last 2 minutes
> 2016-03-09 09:45:26,023 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) advance clock @ 120000
> -> Measurement [id=x, val=x]
> I have seen color RED in the last 2m [red]
> I have seen Measurement for id=x in the last 2m [x]
> 2016-03-09 09:45:26,029 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) advance clock @ 180000
> -> Measurement [id=color, val=green]
> <- Measurement [id=color, val=red]
> I have seen color GREEN in the last 2m [green]
> 2016-03-09 09:45:26,033 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) advance clock @ 240000
> -> Measurement [id=color, val=blue]
> <- Measurement [id=x, val=x]
> 2016-03-09 09:45:26,033 INFO [com.acme.accumulateUpgradeTest.RuleTest] (main) Final checks
> {code}
> h2. Final note.
> Please notice in the reproducer I've used {{setSourcePath}} to ".txt" because I'm aliging with the Drool's JUnit tests: https://github.com/droolsjbpm/drools/blob/master/drools-compiler/src/test...
> However changing {{setSourcePath}} to ".drl" would NOT solve the problem, at least for the rule "id X seen in the last 2 minutes".
> Can you kindly advise, please?
> Thank you
> Ciao,
> MM
--
This message was sent by Atlassian JIRA
(v6.4.11#64026)
10 years, 1 month
[JBoss JIRA] (DROOLS-1059) Drools can't find rules under stress
by Massinissa BOUZIAD (JIRA)
[ https://issues.jboss.org/browse/DROOLS-1059?page=com.atlassian.jira.plugi... ]
Massinissa BOUZIAD commented on DROOLS-1059:
--------------------------------------------
Hi Mario, I created a new issue DROOLS-1115
> Drools can't find rules under stress
> ------------------------------------
>
> Key: DROOLS-1059
> URL: https://issues.jboss.org/browse/DROOLS-1059
> Project: Drools
> Issue Type: Bug
> Components: core engine
> Affects Versions: 6.3.0.Final
> Reporter: Massinissa BOUZIAD
> Assignee: Mario Fusco
> Priority: Blocker
> Fix For: 6.4.0.Final, 7.0.0.Final
>
> Attachments: DroolsBugReproducerTest.java, reproducerRule.drl
>
>
> In my knowledge base, I have many rules.
> All of them are working very well in production with drools 6.0.1-FINAL even in stress condition hight trafic (arount 40 hits seconds)
> This bug append when we made an upgrade with drools 6.3.0-FINAL which is compatible with jdk8 mandatory in my case.
> So now when I put my rules under stress test (benchmarking) I got this random error.
> Drools is unable to find a query (not always the same one).
> I got this error for 0,6% of my requests.
> *+Following the stack trace : +*
> Unable to find query 'checkAndBindBasket'
> at org.drools.core.phreak.SegmentUtilities.getQueryLiaNode(SegmentUtilities.java:518) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.phreak.SegmentUtilities.getQuerySegmentMemory(SegmentUtilities.java:208) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.reteoo.SegmentMemory$QueryMemoryPrototype.populateMemory(SegmentMemory.java:505) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.reteoo.SegmentMemory$Prototype.newSegmentMemory(SegmentMemory.java:400) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.impl.KnowledgeBaseImpl.createSegmentFromPrototype(KnowledgeBaseImpl.java:1424) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.phreak.SegmentUtilities.restoreSegmentFromPrototype(SegmentUtilities.java:186) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.phreak.SegmentUtilities.createSegmentMemory(SegmentUtilities.java:83) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.reteoo.LeftInputAdapterNode.assertObject(LeftInputAdapterNode.java:167) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.reteoo.SingleObjectSinkAdapter.propagateAssertObject(SingleObjectSinkAdapter.java:60) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.reteoo.AlphaNode.assertObject(AlphaNode.java:145) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.reteoo.CompositeObjectSinkAdapter.doPropagateAssertObject(CompositeObjectSinkAdapter.java:494) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.reteoo.CompositeObjectSinkAdapter.propagateAssertObject(CompositeObjectSinkAdapter.java:384) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.reteoo.AlphaNode.assertObject(AlphaNode.java:145) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.reteoo.SingleObjectSinkAdapter.propagateAssertObject(SingleObjectSinkAdapter.java:60) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.reteoo.AlphaNode.assertObject(AlphaNode.java:145) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.reteoo.CompositeObjectSinkAdapter.doPropagateAssertObject(CompositeObjectSinkAdapter.java:494) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.reteoo.CompositeObjectSinkAdapter.propagateAssertObject(CompositeObjectSinkAdapter.java:384) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.reteoo.AlphaNode.assertObject(AlphaNode.java:145) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.reteoo.CompositeObjectSinkAdapter.doPropagateAssertObject(CompositeObjectSinkAdapter.java:494) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.reteoo.CompositeObjectSinkAdapter.propagateAssertObject(CompositeObjectSinkAdapter.java:384) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.reteoo.AlphaNode.assertObject(AlphaNode.java:145) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.reteoo.CompositeObjectSinkAdapter.doPropagateAssertObject(CompositeObjectSinkAdapter.java:494) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.reteoo.CompositeObjectSinkAdapter.propagateAssertObject(CompositeObjectSinkAdapter.java:384) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.reteoo.AlphaNode.assertObject(AlphaNode.java:145) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.reteoo.CompositeObjectSinkAdapter.doPropagateAssertObject(CompositeObjectSinkAdapter.java:494) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.reteoo.CompositeObjectSinkAdapter.propagateAssertObject(CompositeObjectSinkAdapter.java:384) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.reteoo.ObjectTypeNode.propagateAssert(ObjectTypeNode.java:298) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.phreak.PropagationEntry$Insert.execute(PropagationEntry.java:93) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.phreak.SynchronizedPropagationList.flush(SynchronizedPropagationList.java:96) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.phreak.SynchronizedPropagationList.flush(SynchronizedPropagationList.java:69) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.impl.StatefulKnowledgeSessionImpl.flushPropagations(StatefulKnowledgeSessionImpl.java:1993) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.common.DefaultAgenda.fireAllRules(DefaultAgenda.java:1289) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.impl.StatefulKnowledgeSessionImpl.internalFireAllRules(StatefulKnowledgeSessionImpl.java:1294) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:1281) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
> at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:1260) ~[darty-pricing-ws-2.0.2.jar:2.0.2]
--
This message was sent by Atlassian JIRA
(v6.4.11#64026)
10 years, 1 month
[JBoss JIRA] (DROOLS-1115) IndexOutOfBoundException when using conditional break + query
by Massinissa BOUZIAD (JIRA)
[ https://issues.jboss.org/browse/DROOLS-1115?page=com.atlassian.jira.plugi... ]
Massinissa BOUZIAD commented on DROOLS-1115:
--------------------------------------------
Here my reproducer : https://github.com/Massinissab/DROOLS-1115.git
> IndexOutOfBoundException when using conditional break + query
> -------------------------------------------------------------
>
> Key: DROOLS-1115
> URL: https://issues.jboss.org/browse/DROOLS-1115
> Project: Drools
> Issue Type: Bug
> Components: core engine
> Affects Versions: 6.4.0.CR2
> Reporter: Massinissa BOUZIAD
> Assignee: Mario Fusco
> Priority: Blocker
>
> I got an java.lang.ArrayIndexOutOfBoundsException when I use conditionnal breaking and queries.
> I face this issue since 6.4.0.CR2 and not before this.
> Following the stack trace :
> java.lang.ArrayIndexOutOfBoundsException: 2
> at org.drools.core.reteoo.AbstractTerminalNode.getPathNodes(AbstractTerminalNode.java:304)
> at org.drools.core.reteoo.AbstractTerminalNode.getPathNodes(AbstractTerminalNode.java:311)
> at org.drools.core.phreak.PhreakQueryTerminalNode.checkAndTriggerQueryReevaluation(PhreakQueryTerminalNode.java:173)
> at org.drools.core.phreak.PhreakQueryTerminalNode.doLeftInserts(PhreakQueryTerminalNode.java:78)
> at org.drools.core.phreak.PhreakQueryTerminalNode.doNode(PhreakQueryTerminalNode.java:54)
> at org.drools.core.phreak.RuleNetworkEvaluator.innerEval(RuleNetworkEvaluator.java:282)
> at org.drools.core.phreak.RuleNetworkEvaluator.outerEval(RuleNetworkEvaluator.java:136)
> at org.drools.core.phreak.RuleNetworkEvaluator.evaluateNetwork(RuleNetworkEvaluator.java:94)
> at org.drools.core.phreak.RuleExecutor.reEvaluateNetwork(RuleExecutor.java:194)
> at org.drools.core.phreak.RuleExecutor.evaluateNetworkAndFire(RuleExecutor.java:73)
> at org.drools.core.common.DefaultAgenda.fireNextItem(DefaultAgenda.java:1003)
> at org.drools.core.common.DefaultAgenda.fireLoop(DefaultAgenda.java:1346)
> at org.drools.core.common.DefaultAgenda.fireAllRules(DefaultAgenda.java:1284)
> at org.drools.core.impl.StatefulKnowledgeSessionImpl.internalFireAllRules(StatefulKnowledgeSessionImpl.java:1303)
> at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:1293)
> at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:1274)
> at com.darty.drools.CodicCriteriaTest.price(CodicCriteriaTest.java:53)
--
This message was sent by Atlassian JIRA
(v6.4.11#64026)
10 years, 1 month
[JBoss JIRA] (DROOLS-1115) IndexOutOfBoundException when using conditional break + query
by Mario Fusco (JIRA)
[ https://issues.jboss.org/browse/DROOLS-1115?page=com.atlassian.jira.plugi... ]
Mario Fusco updated DROOLS-1115:
--------------------------------
Issue Type: Bug (was: Feature Request)
> IndexOutOfBoundException when using conditional break + query
> -------------------------------------------------------------
>
> Key: DROOLS-1115
> URL: https://issues.jboss.org/browse/DROOLS-1115
> Project: Drools
> Issue Type: Bug
> Components: core engine
> Affects Versions: 6.4.0.CR2
> Reporter: Massinissa BOUZIAD
> Assignee: Mario Fusco
> Priority: Blocker
>
> I got an java.lang.ArrayIndexOutOfBoundsException when I use conditionnal breaking and queries.
> I face this issue since 6.4.0.CR2 and not before this.
> Following the stack trace :
> java.lang.ArrayIndexOutOfBoundsException: 2
> at org.drools.core.reteoo.AbstractTerminalNode.getPathNodes(AbstractTerminalNode.java:304)
> at org.drools.core.reteoo.AbstractTerminalNode.getPathNodes(AbstractTerminalNode.java:311)
> at org.drools.core.phreak.PhreakQueryTerminalNode.checkAndTriggerQueryReevaluation(PhreakQueryTerminalNode.java:173)
> at org.drools.core.phreak.PhreakQueryTerminalNode.doLeftInserts(PhreakQueryTerminalNode.java:78)
> at org.drools.core.phreak.PhreakQueryTerminalNode.doNode(PhreakQueryTerminalNode.java:54)
> at org.drools.core.phreak.RuleNetworkEvaluator.innerEval(RuleNetworkEvaluator.java:282)
> at org.drools.core.phreak.RuleNetworkEvaluator.outerEval(RuleNetworkEvaluator.java:136)
> at org.drools.core.phreak.RuleNetworkEvaluator.evaluateNetwork(RuleNetworkEvaluator.java:94)
> at org.drools.core.phreak.RuleExecutor.reEvaluateNetwork(RuleExecutor.java:194)
> at org.drools.core.phreak.RuleExecutor.evaluateNetworkAndFire(RuleExecutor.java:73)
> at org.drools.core.common.DefaultAgenda.fireNextItem(DefaultAgenda.java:1003)
> at org.drools.core.common.DefaultAgenda.fireLoop(DefaultAgenda.java:1346)
> at org.drools.core.common.DefaultAgenda.fireAllRules(DefaultAgenda.java:1284)
> at org.drools.core.impl.StatefulKnowledgeSessionImpl.internalFireAllRules(StatefulKnowledgeSessionImpl.java:1303)
> at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:1293)
> at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:1274)
> at com.darty.drools.CodicCriteriaTest.price(CodicCriteriaTest.java:53)
--
This message was sent by Atlassian JIRA
(v6.4.11#64026)
10 years, 1 month
[JBoss JIRA] (DROOLS-1115) IndexOutOfBoundException when using conditional break + query
by Mario Fusco (JIRA)
[ https://issues.jboss.org/browse/DROOLS-1115?page=com.atlassian.jira.plugi... ]
Mario Fusco commented on DROOLS-1115:
-------------------------------------
Can you please send a reproducer for this issue?
> IndexOutOfBoundException when using conditional break + query
> -------------------------------------------------------------
>
> Key: DROOLS-1115
> URL: https://issues.jboss.org/browse/DROOLS-1115
> Project: Drools
> Issue Type: Bug
> Components: core engine
> Affects Versions: 6.4.0.CR2
> Reporter: Massinissa BOUZIAD
> Assignee: Mario Fusco
> Priority: Blocker
>
> I got an java.lang.ArrayIndexOutOfBoundsException when I use conditionnal breaking and queries.
> I face this issue since 6.4.0.CR2 and not before this.
> Following the stack trace :
> java.lang.ArrayIndexOutOfBoundsException: 2
> at org.drools.core.reteoo.AbstractTerminalNode.getPathNodes(AbstractTerminalNode.java:304)
> at org.drools.core.reteoo.AbstractTerminalNode.getPathNodes(AbstractTerminalNode.java:311)
> at org.drools.core.phreak.PhreakQueryTerminalNode.checkAndTriggerQueryReevaluation(PhreakQueryTerminalNode.java:173)
> at org.drools.core.phreak.PhreakQueryTerminalNode.doLeftInserts(PhreakQueryTerminalNode.java:78)
> at org.drools.core.phreak.PhreakQueryTerminalNode.doNode(PhreakQueryTerminalNode.java:54)
> at org.drools.core.phreak.RuleNetworkEvaluator.innerEval(RuleNetworkEvaluator.java:282)
> at org.drools.core.phreak.RuleNetworkEvaluator.outerEval(RuleNetworkEvaluator.java:136)
> at org.drools.core.phreak.RuleNetworkEvaluator.evaluateNetwork(RuleNetworkEvaluator.java:94)
> at org.drools.core.phreak.RuleExecutor.reEvaluateNetwork(RuleExecutor.java:194)
> at org.drools.core.phreak.RuleExecutor.evaluateNetworkAndFire(RuleExecutor.java:73)
> at org.drools.core.common.DefaultAgenda.fireNextItem(DefaultAgenda.java:1003)
> at org.drools.core.common.DefaultAgenda.fireLoop(DefaultAgenda.java:1346)
> at org.drools.core.common.DefaultAgenda.fireAllRules(DefaultAgenda.java:1284)
> at org.drools.core.impl.StatefulKnowledgeSessionImpl.internalFireAllRules(StatefulKnowledgeSessionImpl.java:1303)
> at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:1293)
> at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:1274)
> at com.darty.drools.CodicCriteriaTest.price(CodicCriteriaTest.java:53)
--
This message was sent by Atlassian JIRA
(v6.4.11#64026)
10 years, 1 month
[JBoss JIRA] (DROOLS-1115) IndexOutOfBoundException when using conditional break + query
by Massinissa BOUZIAD (JIRA)
Massinissa BOUZIAD created DROOLS-1115:
------------------------------------------
Summary: IndexOutOfBoundException when using conditional break + query
Key: DROOLS-1115
URL: https://issues.jboss.org/browse/DROOLS-1115
Project: Drools
Issue Type: Feature Request
Components: core engine
Affects Versions: 6.4.0.CR2
Reporter: Massinissa BOUZIAD
Assignee: Mario Fusco
Priority: Blocker
I got an java.lang.ArrayIndexOutOfBoundsException when I use conditionnal breaking and queries.
I face this issue since 6.4.0.CR2 and not before this.
Following the stack trace :
java.lang.ArrayIndexOutOfBoundsException: 2
at org.drools.core.reteoo.AbstractTerminalNode.getPathNodes(AbstractTerminalNode.java:304)
at org.drools.core.reteoo.AbstractTerminalNode.getPathNodes(AbstractTerminalNode.java:311)
at org.drools.core.phreak.PhreakQueryTerminalNode.checkAndTriggerQueryReevaluation(PhreakQueryTerminalNode.java:173)
at org.drools.core.phreak.PhreakQueryTerminalNode.doLeftInserts(PhreakQueryTerminalNode.java:78)
at org.drools.core.phreak.PhreakQueryTerminalNode.doNode(PhreakQueryTerminalNode.java:54)
at org.drools.core.phreak.RuleNetworkEvaluator.innerEval(RuleNetworkEvaluator.java:282)
at org.drools.core.phreak.RuleNetworkEvaluator.outerEval(RuleNetworkEvaluator.java:136)
at org.drools.core.phreak.RuleNetworkEvaluator.evaluateNetwork(RuleNetworkEvaluator.java:94)
at org.drools.core.phreak.RuleExecutor.reEvaluateNetwork(RuleExecutor.java:194)
at org.drools.core.phreak.RuleExecutor.evaluateNetworkAndFire(RuleExecutor.java:73)
at org.drools.core.common.DefaultAgenda.fireNextItem(DefaultAgenda.java:1003)
at org.drools.core.common.DefaultAgenda.fireLoop(DefaultAgenda.java:1346)
at org.drools.core.common.DefaultAgenda.fireAllRules(DefaultAgenda.java:1284)
at org.drools.core.impl.StatefulKnowledgeSessionImpl.internalFireAllRules(StatefulKnowledgeSessionImpl.java:1303)
at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:1293)
at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:1274)
at com.darty.drools.CodicCriteriaTest.price(CodicCriteriaTest.java:53)
--
This message was sent by Atlassian JIRA
(v6.4.11#64026)
10 years, 1 month
[JBoss JIRA] (WFCORE-1468) Servers are suspended two times using timeout parameter in domain mode
by Brian Stansberry (JIRA)
Brian Stansberry created WFCORE-1468:
----------------------------------------
Summary: Servers are suspended two times using timeout parameter in domain mode
Key: WFCORE-1468
URL: https://issues.jboss.org/browse/WFCORE-1468
Project: WildFly Core
Issue Type: Bug
Components: Domain Management
Reporter: Yeray Santana Borges
Assignee: Yeray Santana Borges
In a domain mode :suspend-servers command with a timeout parameter different than 0 executes two suspend operations for each server in the domain. It first executes a suspend with 0ms and later a suspend with the timeout specified.
How to reproduce it:
{code}
[domain@localhost:9990 /] :suspend-servers(timeout=10)
{code}
Server log traces show:
{code}
[Server:server-one] 20:14:40,126 INFO [org.jboss.as.server] (ServerService Thread Pool -- 8) WFLYSRV0211: Suspending server with 0ms timeout.
[Server:server-one] 20:14:40,135 INFO [org.jboss.as.server] (ServerService Thread Pool -- 8) WFLYSRV0211: Suspending server with 10000000ms timeout.
{code}
Expected traces are:
{code}
[Server:server-one] 20:14:40,135 INFO [org.jboss.as.server] (ServerService Thread Pool -- 8) WFLYSRV0211: Suspending server with 10000000ms timeout.
{code}
--
This message was sent by Atlassian JIRA
(v6.4.11#64026)
10 years, 1 month
[JBoss JIRA] (WFLY-2504) add lazy xpc inheritance to handle legacy case, remote client with UserTransaction fails on 2nd SFSB invocation when using extended persistence context
by Scott Marlow (JIRA)
[ https://issues.jboss.org/browse/WFLY-2504?page=com.atlassian.jira.plugin.... ]
Scott Marlow resolved WFLY-2504.
--------------------------------
Resolution: Rejected
Reopen this issue if/when we decide to fix it. Currently, I have no plans to fix due to low interest in the issue. Please vote for the issue if you want it fixed in the future.
> add lazy xpc inheritance to handle legacy case, remote client with UserTransaction fails on 2nd SFSB invocation when using extended persistence context
> -------------------------------------------------------------------------------------------------------------------------------------------------------
>
> Key: WFLY-2504
> URL: https://issues.jboss.org/browse/WFLY-2504
> Project: WildFly
> Issue Type: Enhancement
> Components: JPA / Hibernate
> Reporter: Scott Marlow
> Assignee: Scott Marlow
>
> AS5 allowed a remote client to instantiate a set of stateful session beans (e.g. SFSB1 + SFSB2) and then call the remote stateful session beans (SFSB1+SFSB2) in a started user transaction (UT1). Each of the stateful beans reference the same extended persistence context by name. In AS5, both stateful beans will share the same extended persistence unit context but on AS7/WF8, each bean has its own extended persistence unit context. Having both XPCS involved in the same user transaction, causes an (EJBException: JBAS011437: Found extended persistence context in SFSB invocation call stack but that cannot be used because the transaction already has a transactional context associated with it...) error to be thrown.
> On AS7/WF8, Allow the separate (remote) stateful beans to share the same persistence context.
> One approach might be to defer creation of the extended persistence context until the first invocation (need to verify that this is the right approach).
> Currently, we support shallow + deep extended persistence context inheritance. This will be a "lazy" variation of the deep XPC inheritance.
> Some of the AS5 code is pasted below for easy reference.
> {code}
> public class ExtendedPersistenceContextPropagationInterceptor implements Interceptor
> {
> private static final Logger log = Logger.getLogger(ExtendedPersistenceContextPropagationInterceptor.class);
> public String getName()
> {
> return this.getClass().getName();
> }
> public Object invoke(Invocation invocation) throws Throwable
> {
> log.debug("++++ LongLivedSessionPropagationInterceptor");
> StatefulContainerInvocation ejb = (StatefulContainerInvocation) invocation;
> StatefulBeanContext ctx = (StatefulBeanContext) ejb.getBeanContext();
> Map<String, EntityManager> extendedPCs = ctx.getExtendedPersistenceContexts();
> if (extendedPCs == null || extendedPCs.size() == 0)
> {
> return invocation.invokeNext();
> }
> TransactionManager tm = TxUtil.getTransactionManager();
> if (tm.getTransaction() != null)
> {
> for (String kernelname : extendedPCs.keySet())
> {
> EntityManager manager = extendedPCs.get(kernelname);
> ManagedEntityManagerFactory factory = ManagedEntityManagerFactoryHelper.getManagedEntityManagerFactory(kernelname);
> factory.registerExtendedWithTransaction(manager);
> }
> }
> return invocation.invokeNext();
> }
> }
> {code}
> {code}
> public class EJB3XPCResolver implements XPCResolver
> {
> private static final Logger log = Logger.getLogger(EJB3XPCResolver.class);
> /**
> * Query the current stateful bean contexts for the specified XPC.
> */
> public EntityManager getExtendedPersistenceContext(String kernelName)
> {
> StatefulBeanContext beanContext = StatefulBeanContext.currentBean.get();
> if (beanContext != null)
> {
> EntityManager em = null;
> em = beanContext.getExtendedPersistenceContext(kernelName);
> if (em != null) {
> log.info("current SFSB has XPC with scoped pu name=" + kernelName + " on SFSB bean=" + beanContext.getContainer().getIdentifier() + beanContext.getId());
> return em;
> }
> /**
> * Look for XPC in current bean set.
> */
> log.info("looking for existing XPC with scoped pu name=" + kernelName);
> List <StatefulBeanContext> beanContexts = StatefulBeanContext.currentBean.getList();
> for( StatefulBeanContext bc : beanContexts)
> {
> em = bc.getExtendedPersistenceContext(kernelName);
> if (em != null) {
> log.info("found existing XPC with scoped pu name=" + kernelName + " on SFSB bean=" + bc.getContainer().getIdentifier() + bc.getId());
> // Propagate created XPC as required (7.6.2.1 Inheritance of Extended Persistence Context
> beanContext.addExtendedPersistenceContext(kernelName, em);
> return em;
> }
> log.info("XPC not found yet, scoped pu name=" + kernelName + " not in SFSB bean=" + bc.getContainer().getIdentifier() + bc.getId());
> }
> }
> log.info("XPC not found scoped, search done, pu name=" + kernelName);
> return null;
> }
> @Override
> public EntityManager createExtendedPersistenceContext(String kernelName)
> {
> StatefulBeanContext beanContext = StatefulBeanContext.currentBean.get();
> if (beanContext != null)
> {
> EntityManager em = null;
> ManagedEntityManagerFactory factory=
> ((PersistenceUnitDeployment) PersistenceUnitRegistry.getPersistenceUnit(kernelName)).getManagedFactory();
> if (factory != null)
> {
> em = factory.createEntityManager();
> if (em != null)
> {
> beanContext.addExtendedPersistenceContext(factory.getKernelName(), em);
> log.info("created new XPC with scoped pu name=" + kernelName + " on SFSB bean=" + beanContext.getContainer().getIdentifier() + beanContext.getId());
> /**
> * TODO: Propagate created XPC as required (7.6.2.1 Inheritance of Extended Persistence Context
> *
> */
> // List <StatefulBeanContext> beanContexts = StatefulBeanContext.currentBean.getList();
> // for( StatefulBeanContext bc : beanContexts)
> // {
> // bc.addExtendedPersistenceContext(kernelName, em);
> // }
> }
> }
> return em;
> }
> return null;
> }
> }
> {code}
> {code}
> public class ManagedEntityManagerFactoryHelper
> {
> public static ManagedEntityManagerFactory getManagedEntityManagerFactory(String kernelName)
> {
> PersistenceUnitDeployment pu = (PersistenceUnitDeployment) PersistenceUnitRegistry.getPersistenceUnit(kernelName);
> if(pu != null)
> return pu.getManagedFactory();
> return null;
> }
> }
> {code}
--
This message was sent by Atlassian JIRA
(v6.4.11#64026)
10 years, 1 month
[JBoss JIRA] (WFLY-2504) add lazy xpc inheritance to handle legacy case, remote client with UserTransaction fails on 2nd SFSB invocation when using extended persistence context
by Scott Marlow (JIRA)
[ https://issues.jboss.org/browse/WFLY-2504?page=com.atlassian.jira.plugin.... ]
Scott Marlow commented on WFLY-2504:
------------------------------------
Just to be clear, WFLY-2504 is a request to implement a non-standard (extension) that is not required by the JPA specification.
In the description, we mention that we already support both shallow + deep extended persistence context inheritance. The default is "shallow", which matches the behaviour described by the JPA specification lead (in a conversation on the JPA 2.1 spec expert group mailing list).
I believe that the WFLY-2504 extension would be a "lazy" variation of the deep XPC inheritance (as mentioned in the description).
> add lazy xpc inheritance to handle legacy case, remote client with UserTransaction fails on 2nd SFSB invocation when using extended persistence context
> -------------------------------------------------------------------------------------------------------------------------------------------------------
>
> Key: WFLY-2504
> URL: https://issues.jboss.org/browse/WFLY-2504
> Project: WildFly
> Issue Type: Enhancement
> Components: JPA / Hibernate
> Reporter: Scott Marlow
> Assignee: Scott Marlow
>
> AS5 allowed a remote client to instantiate a set of stateful session beans (e.g. SFSB1 + SFSB2) and then call the remote stateful session beans (SFSB1+SFSB2) in a started user transaction (UT1). Each of the stateful beans reference the same extended persistence context by name. In AS5, both stateful beans will share the same extended persistence unit context but on AS7/WF8, each bean has its own extended persistence unit context. Having both XPCS involved in the same user transaction, causes an (EJBException: JBAS011437: Found extended persistence context in SFSB invocation call stack but that cannot be used because the transaction already has a transactional context associated with it...) error to be thrown.
> On AS7/WF8, Allow the separate (remote) stateful beans to share the same persistence context.
> One approach might be to defer creation of the extended persistence context until the first invocation (need to verify that this is the right approach).
> Currently, we support shallow + deep extended persistence context inheritance. This will be a "lazy" variation of the deep XPC inheritance.
> Some of the AS5 code is pasted below for easy reference.
> {code}
> public class ExtendedPersistenceContextPropagationInterceptor implements Interceptor
> {
> private static final Logger log = Logger.getLogger(ExtendedPersistenceContextPropagationInterceptor.class);
> public String getName()
> {
> return this.getClass().getName();
> }
> public Object invoke(Invocation invocation) throws Throwable
> {
> log.debug("++++ LongLivedSessionPropagationInterceptor");
> StatefulContainerInvocation ejb = (StatefulContainerInvocation) invocation;
> StatefulBeanContext ctx = (StatefulBeanContext) ejb.getBeanContext();
> Map<String, EntityManager> extendedPCs = ctx.getExtendedPersistenceContexts();
> if (extendedPCs == null || extendedPCs.size() == 0)
> {
> return invocation.invokeNext();
> }
> TransactionManager tm = TxUtil.getTransactionManager();
> if (tm.getTransaction() != null)
> {
> for (String kernelname : extendedPCs.keySet())
> {
> EntityManager manager = extendedPCs.get(kernelname);
> ManagedEntityManagerFactory factory = ManagedEntityManagerFactoryHelper.getManagedEntityManagerFactory(kernelname);
> factory.registerExtendedWithTransaction(manager);
> }
> }
> return invocation.invokeNext();
> }
> }
> {code}
> {code}
> public class EJB3XPCResolver implements XPCResolver
> {
> private static final Logger log = Logger.getLogger(EJB3XPCResolver.class);
> /**
> * Query the current stateful bean contexts for the specified XPC.
> */
> public EntityManager getExtendedPersistenceContext(String kernelName)
> {
> StatefulBeanContext beanContext = StatefulBeanContext.currentBean.get();
> if (beanContext != null)
> {
> EntityManager em = null;
> em = beanContext.getExtendedPersistenceContext(kernelName);
> if (em != null) {
> log.info("current SFSB has XPC with scoped pu name=" + kernelName + " on SFSB bean=" + beanContext.getContainer().getIdentifier() + beanContext.getId());
> return em;
> }
> /**
> * Look for XPC in current bean set.
> */
> log.info("looking for existing XPC with scoped pu name=" + kernelName);
> List <StatefulBeanContext> beanContexts = StatefulBeanContext.currentBean.getList();
> for( StatefulBeanContext bc : beanContexts)
> {
> em = bc.getExtendedPersistenceContext(kernelName);
> if (em != null) {
> log.info("found existing XPC with scoped pu name=" + kernelName + " on SFSB bean=" + bc.getContainer().getIdentifier() + bc.getId());
> // Propagate created XPC as required (7.6.2.1 Inheritance of Extended Persistence Context
> beanContext.addExtendedPersistenceContext(kernelName, em);
> return em;
> }
> log.info("XPC not found yet, scoped pu name=" + kernelName + " not in SFSB bean=" + bc.getContainer().getIdentifier() + bc.getId());
> }
> }
> log.info("XPC not found scoped, search done, pu name=" + kernelName);
> return null;
> }
> @Override
> public EntityManager createExtendedPersistenceContext(String kernelName)
> {
> StatefulBeanContext beanContext = StatefulBeanContext.currentBean.get();
> if (beanContext != null)
> {
> EntityManager em = null;
> ManagedEntityManagerFactory factory=
> ((PersistenceUnitDeployment) PersistenceUnitRegistry.getPersistenceUnit(kernelName)).getManagedFactory();
> if (factory != null)
> {
> em = factory.createEntityManager();
> if (em != null)
> {
> beanContext.addExtendedPersistenceContext(factory.getKernelName(), em);
> log.info("created new XPC with scoped pu name=" + kernelName + " on SFSB bean=" + beanContext.getContainer().getIdentifier() + beanContext.getId());
> /**
> * TODO: Propagate created XPC as required (7.6.2.1 Inheritance of Extended Persistence Context
> *
> */
> // List <StatefulBeanContext> beanContexts = StatefulBeanContext.currentBean.getList();
> // for( StatefulBeanContext bc : beanContexts)
> // {
> // bc.addExtendedPersistenceContext(kernelName, em);
> // }
> }
> }
> return em;
> }
> return null;
> }
> }
> {code}
> {code}
> public class ManagedEntityManagerFactoryHelper
> {
> public static ManagedEntityManagerFactory getManagedEntityManagerFactory(String kernelName)
> {
> PersistenceUnitDeployment pu = (PersistenceUnitDeployment) PersistenceUnitRegistry.getPersistenceUnit(kernelName);
> if(pu != null)
> return pu.getManagedFactory();
> return null;
> }
> }
> {code}
--
This message was sent by Atlassian JIRA
(v6.4.11#64026)
10 years, 1 month