[jboss-jira] [JBoss JIRA] (DROOLS-309) Multiple threads working with traits against same knowledge base hangs
Davide Sottara (JIRA)
jira-events at lists.jboss.org
Tue Oct 22 21:53:01 EDT 2013
[ https://issues.jboss.org/browse/DROOLS-309?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12824134#comment-12824134 ]
Davide Sottara commented on DROOLS-309:
---------------------------------------
The "TripleStore" is actually a mock implementation rather than a real interface to a global storage subsystem, which we haven't had time to implement yet.
Among other things, it is not thread-safe (Drools 5 in general is not, so one has to pay attention when using multiple threads).
The best workaround is to use a local store for each traited object, which you can configure as you create the KnowledgeBase:
TraitFactory.setMode( TraitFactory.VirtualPropertyMode.MAP, kbase );
I did fix another bug related to races in the definition of proxy classes, however, which will be in 5.6 and 6.x.
By the way, the trait subsystem in 5.6 is largely redesigned and improved. I will probably blog about it in a few days.
Best,
Davide
> Multiple threads working with traits against same knowledge base hangs
> ----------------------------------------------------------------------
>
> Key: DROOLS-309
> URL: https://issues.jboss.org/browse/DROOLS-309
> Project: Drools
> Issue Type: Quality Risk
> Security Level: Public(Everyone can see)
> Affects Versions: 5.5.0.Final
> Reporter: James Myers
> Assignee: Davide Sottara
>
> In our web system, we are creating new StatefulKnowledgeSession per user session and executing a set of rules containing trait donning. This starts to hang (seemingly indefinitely) with following type of stack trace (usually initiated from insert/update):
> {quote}
> java.lang.Thread.State: RUNNABLE
> at org.drools.core.util.TripleStore.getAll(TripleStore.java:188)
> at org.drools.factmodel.traits.TripleBasedStruct.getTriplesForSubject(TripleBasedStruct.java:165)
> at org.drools.factmodel.traits.ThingorgdroolsfactmodeltraitsTraitSession$ItemWrapperProxyWrapper.hashCode(Unknown Source)
> at org.drools.factmodel.traits.TraitProxy.hashCode(TraitProxy.java:110)
> at org.drools.factmodel.traits.ThingorgdroolsfactmodeltraitsTraitSession$ItemWrapperProxy.hashCode(Unknown Source)
> at org.drools.common.DefaultFactHandle.<init>(DefaultFactHandle.java:110)
> at org.drools.common.DefaultFactHandle.<init>(DefaultFactHandle.java:98)
> at org.drools.common.TraitFactHandle.<init>(TraitFactHandle.java:26)
> at org.drools.reteoo.ReteooFactHandleFactory.newFactHandle(ReteooFactHandleFactory.java:80)
> at org.drools.common.AbstractFactHandleFactory.newFactHandle(AbstractFactHandleFactory.java:68)
> at org.drools.common.AbstractFactHandleFactory.newFactHandle(AbstractFactHandleFactory.java:53)
> at org.drools.common.NamedEntryPoint.createHandle(NamedEntryPoint.java:765)
> at org.drools.common.NamedEntryPoint.insert(NamedEntryPoint.java:301)
> at org.drools.common.AbstractWorkingMemory.insert(AbstractWorkingMemory.java:903)
> {quote}
> Here is a unit test for org.drools.factmodel.traits.TraitTest. It's not perfect because it will spawn thread that might never die and may need thread/iteration count increased to fail consistently, but capturing a stack trace a few seconds in should show all threads in "getAll()":
> {code}
> @Traitable
> public static class Item {
> private String id;
> public String getId() {
> return id;
> }
> public void setId(String id) {
> this.id = id;
> }
> }
> public static class TraitRulesThread implements Runnable {
> int threadIndex;
> int numRepetitions;
> StatefulKnowledgeSession ksession;
> public TraitRulesThread(int threadIndex, int numRepetitions, final StatefulKnowledgeSession ksession) {
> this.threadIndex = threadIndex;
> this.numRepetitions = numRepetitions;
> this.ksession = ksession;
> }
> public void run() {
> for (int repetitionIndex = 0; repetitionIndex < numRepetitions; repetitionIndex++) {
> final Item i = new Item();
> i.setId(String.format("testId_%d%d", threadIndex, repetitionIndex));
> ksession.insert(i);
> ksession.fireAllRules();
> }
> }
> }
> @Test
> public void testMultithreadingTraits() throws InterruptedException {
> final String s1 = "package test;\n" +
> "import org.drools.factmodel.traits.TraitTest.Item;\n" +
> "declare Item end\n" +
> "declare trait ItemStyle\n" +
> " id: String\n" +
> " adjustable: boolean\n" +
> "end\n" +
> "rule \"Don ItemStyle\"\n" +
> " no-loop true\n" +
> " when\n" +
> " $p : Item ()\n" +
> " not ItemStyle ( id == $p.id )\n" +
> " then\n" +
> " don($p, ItemStyle.class);\n" +
> "end\n" +
> "rule \"Item Style - Adjustable\"" +
> " no-loop true" +
> " when" +
> " $style : ItemStyle ( !adjustable )" +
> " Item (" +
> " id == $style.id " +
> " )" +
> " then" +
> " modify($style) {" +
> " setAdjustable(true)" +
> " };" +
> "end";
> final KnowledgeBase kbase = getKnowledgeBaseFromString(s1);
> // might need to tweak these numbers. often works with 7-10,100,60, but often fails 15-20,100,60
> int MAX_THREADS = 20;
> int MAX_REPETITIONS = 100;
> int MAX_WAIT_SECONDS = 60;
> final ExecutorService executorService = Executors.newFixedThreadPool(MAX_THREADS);
> for (int threadIndex = 0; threadIndex < MAX_THREADS; threadIndex++) {
> executorService.execute(new TraitRulesThread(threadIndex, MAX_REPETITIONS, kbase.newStatefulKnowledgeSession()));
> }
> executorService.shutdown();
> executorService.awaitTermination(MAX_WAIT_SECONDS, TimeUnit.SECONDS);
> final List<Runnable> queuedTasks = executorService.shutdownNow();
> assertEquals(0, queuedTasks.size());
> assertEquals(true, executorService.isTerminated());
> }
> {code}
--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira
More information about the jboss-jira
mailing list