[
http://jira.jboss.com/jira/browse/JBRULES-541?page=comments#action_12346778 ]
Mark Proctor commented on JBRULES-541:
--------------------------------------
I wrote the following unit test, nothing is failing for me. We'll keep this open
anyway and probably syncrhonise the newWorkingMemory calls:
package org.drools.integrationtests;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.StringReader;
import org.drools.FactException;
import org.drools.FactHandle;
import org.drools.RuleBase;
import org.drools.RuleBaseConfiguration;
import org.drools.RuleBaseFactory;
import org.drools.WorkingMemory;
import org.drools.compiler.DroolsParserException;
import org.drools.compiler.PackageBuilder;
import org.drools.compiler.PackageBuilderConfiguration;
import org.drools.reteoo.ReteooFactHandleFactory;
import org.drools.reteoo.ReteooRuleBase;
import org.drools.reteoo.ReteooWorkingMemory;
import org.drools.rule.Rule;
import org.drools.spi.PropagationContext;
import junit.framework.Assert;
import junit.framework.TestCase;
public class AbstractRuleBaseTest extends TestCase {
public void test1() throws InterruptedException, Exception {
Engine engine = new Engine();
for (int i = 0; i < 10; i++ ) {
MultiThreadTester tester = new MultiThreadTester(engine);
new Thread( tester ).start();
}
Thread.sleep( 5000 );
}
public static class MultiThreadTester implements Runnable {
private Engine engine;
private static int counter = 0;
public MultiThreadTester(Engine engine) {
this.engine = engine;
}
public void run() {
System.out.println("Thread started");
for (int i=0; i<1000; i++) {
engine.getWorkingMemory();
/* try {
Thread.sleep(1);
} catch (InterruptedException e) {
break;
}*/
}
System.out.println("Thread finished");
}
}
public static class Engine {
private RuleBase ruleBase;
public Engine() {
ruleBase = RuleBaseFactory.newRuleBase();
PackageBuilderConfiguration conf = new PackageBuilderConfiguration();
conf.setCompiler(PackageBuilderConfiguration.JANINO);
PackageBuilder builder = new PackageBuilder(conf);
try {
String text = "" +
"package rules \n" +
"rule \"Some rule\" \n" +
" when \n" +
" A : String() \n" +
" then \n" +
" // Do something \n" +
"end \n";
builder.addPackageFromDrl(new StringReader( text));
} catch (DroolsParserException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
try {
ruleBase.addPackage(builder.getPackage());
} catch (Exception e) {
// Yeah, the api throws 'Exception'
throw new RuntimeException(e);
}
}
public WorkingMemory getWorkingMemory() {
return ruleBase.newWorkingMemory(true);
}
}
}
Avoid WeakHashmap for tracking working memories in a RuleBase.
--------------------------------------------------------------
Key: JBRULES-541
URL:
http://jira.jboss.com/jira/browse/JBRULES-541
Project: JBoss Rules
Issue Type: Feature Request
Security Level: Public(Everyone can see)
Components: Rule Assemply/SPI
Affects Versions: 3.0.4
Reporter: Michael Neale
Assigned To: Mark Proctor
Priority: Critical
Attachments: Engine.java, MultiThreadTest.java, rules.drl
This comes under the heading of "I knew it would happen one day and I warned people
about it but they didn't listen and Michael is always right in the long run, except
when he predicted that the graphical web browser would NOT take off back in 1993 and was
catastrophically wrong.
Someone was having issues with concurrency (5 concurrent threads, but heavy load) and
creating a newWorkingMemory - there are hangs/lock issues with the weak hashmap that
points from the Single rule base to the spawned working memories. This is not surprising,
blah blah blah....
Anyway, one possible solution is to have a call where users who *want* to update an
existing long lived working memory changes, pass in the WM to the rulebase, with say
"refresh rules" - ie the methods like removeRule() on a rule base, require a
working memory to be passed in.
We can still keep the old WeakHashMap, just make it non default behaviour (it cannot
scale the way it is now - with the default behaviour in my opinion).
STACK trace follows:
I'm using Java 1.5_09 on Linux. The app uses 5 simultaneous threads at
the moment. They never share WorkingMemory instances but do share the
same RuleBase.
A thread dump (see below) shows all threads being stuck in
java.util.WeakHashMap, which is called from
AbstractRuleBase.addWorkingMemory.
Has anyone seen this before? I attempted to synchronize the method
that's the entry point to newWorkingMemory(). That definitely made the
problem happen less often but didn't solve it completely. Anyone knows
any other workarounds?
Thanks,
Per
"CW4" prio=1 tid=0x1a4fd7a8 nid=0xc44 runnable [0x1a2fe000..0x1a2fefb0]
at
java.util.WeakHashMap.expungeStaleEntries(WeakHashMap.java:289)
at java.util.WeakHashMap.getTable(WeakHashMap.java:297)
at java.util.WeakHashMap.put(WeakHashMap.java:394)
at org.drools.common.AbstractRuleBase.addWorkingMemory(Unknown
Source)
at org.drools.reteoo.ReteooRuleBase.newWorkingMemory(Unknown
Source)
at org.drools.common.AbstractRuleBase.newWorkingMemory(Unknown
Source)
"CW3" prio=1 tid=0x1a4fd5f0 nid=0xc43 runnable [0x1a6fe000..0x1a6fee30]
at java.util.WeakHashMap.put(WeakHashMap.java:397)
at org.drools.common.AbstractRuleBase.addWorkingMemory(Unknown
Source)
at org.drools.reteoo.ReteooRuleBase.newWorkingMemory(Unknown
Source)
at org.drools.common.AbstractRuleBase.newWorkingMemory(Unknown
Source)
"CW2" prio=1 tid=0x1a4fd100 nid=0xc42 runnable [0x1a8e5000..0x1a8e5eb0]
at
java.util.WeakHashMap.expungeStaleEntries(WeakHashMap.java:289)
at java.util.WeakHashMap.getTable(WeakHashMap.java:297)
at java.util.WeakHashMap.put(WeakHashMap.java:394)
at org.drools.common.AbstractRuleBase.addWorkingMemory(Unknown
Source)
at org.drools.reteoo.ReteooRuleBase.newWorkingMemory(Unknown
Source)
at org.drools.common.AbstractRuleBase.newWorkingMemory(Unknown
Source)
"CW1" prio=1 tid=0x19afca78 nid=0xc41 runnable [0x1a966000..0x1a967130]
at
java.util.WeakHashMap.expungeStaleEntries(WeakHashMap.java:289)
at java.util.WeakHashMap.getTable(WeakHashMap.java:297)
at java.util.WeakHashMap.put(WeakHashMap.java:394)
at org.drools.common.AbstractRuleBase.addWorkingMemory(Unknown
Source)
at org.drools.reteoo.ReteooRuleBase.newWorkingMemory(Unknown
Source)
at org.drools.common.AbstractRuleBase.newWorkingMemory(Unknown
Source)
at
"CW0" prio=1 tid=0x19afc7d8 nid=0xc40 runnable [0x1aafe000..0x1aaff1b0]
at
java.util.WeakHashMap.expungeStaleEntries(WeakHashMap.java:289)
at java.util.WeakHashMap.getTable(WeakHashMap.java:297)
at java.util.WeakHashMap.put(WeakHashMap.java:394)
at org.drools.common.AbstractRuleBase.addWorkingMemory(Unknown
Source)
at org.drools.reteoo.ReteooRuleBase.newWorkingMemory(Unknown
Source)
at org.drools.common.AbstractRuleBase.newWorkingMemory(Unknown
Source)
at
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
http://jira.jboss.com/jira/secure/Administrators.jspa
-
For more information on JIRA, see:
http://www.atlassian.com/software/jira