Package org.drools.compiler.integrationtests

Source Code of org.drools.compiler.integrationtests.PhreakConcurrencyTest$EPManipulator3

package org.drools.compiler.integrationtests;

import org.drools.compiler.CommonTestMethodBase;
import org.drools.compiler.StockTick;
import org.drools.core.common.InternalWorkingMemory;
import org.drools.core.common.NamedEntryPoint;
import org.drools.core.reteoo.AlphaNode;
import org.drools.core.reteoo.BetaMemory;
import org.drools.core.reteoo.BetaNode;
import org.drools.core.reteoo.ObjectSink;
import org.drools.core.reteoo.ObjectTypeNode;
import org.drools.core.reteoo.PathMemory;
import org.drools.core.reteoo.RuleTerminalNode;
import org.drools.core.reteoo.SegmentMemory;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.FactHandle;
import org.kie.api.runtime.rule.EntryPoint;
import org.kie.internal.KnowledgeBase;
import org.kie.internal.builder.conf.RuleEngineOption;
import org.kie.internal.runtime.StatefulKnowledgeSession;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

import static java.util.Arrays.asList;
import static org.drools.core.reteoo.ReteDumper.dumpRete;

@Ignore
public class PhreakConcurrencyTest extends CommonTestMethodBase {

    private Executor executor;

    private static RuleEngineOption wasRunningPhreak;

    @BeforeClass
    public static void setPhreak() {
        wasRunningPhreak = phreak;
        phreak = RuleEngineOption.PHREAK;
    }

    @AfterClass
    public static void unsetPhreak() {
        phreak = wasRunningPhreak;
    }

    @Before
    public void setUp() {
        executor = Executors.newCachedThreadPool(new ThreadFactory() {
            public Thread newThread(Runnable r) {
                Thread t = new Thread(r);
                t.setDaemon(true);
                return t;
            }
        });
    }

    @Test
    public void testMultipleConcurrentEPs() {
        final boolean PARALLEL = true;
        final int EP_NR = 10;

        StringBuilder sb = new StringBuilder();

        sb.append("import org.drools.compiler.StockTick;\n");
        for (int i = 0; i < EP_NR; i++) {
            sb.append("global java.util.List results").append(i).append(";\n");
        }
        sb.append("declare StockTick\n" +
                  "    @role( event )\n" +
                  "end\n");
        for (int i = 0; i < EP_NR; i++) {
            sb.append("rule \"R" + i +"\"\n" +
                      "when\n" +
                      "    $name : String( this.startsWith(\"A\") )\n" +
                      "    $st : StockTick( company == $name, price > 10 ) from entry-point EP" + i +"\n" +
                      "then\n" +
                      "    results" + i +".add( $st );\n" +
                      "end\n");
        }

        KnowledgeBase kbase = loadKnowledgeBaseFromString(sb.toString());
        KieSession ksession = kbase.newStatefulKnowledgeSession();

        boolean success = true;
        if (PARALLEL) {

            CompletionService<Boolean> ecs = new ExecutorCompletionService<Boolean>(executor);
            for (int i = 0; i < EP_NR; i++) {
                ecs.submit(new EPManipulator(ksession, i));
            }

            for (int i = 0; i < EP_NR; i++) {
                try {
                    success = ecs.take().get() && success;
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }

        } else {

            for (int i = 0; i < EP_NR; i++) {
                try {
                    success = new EPManipulator(ksession, i).call() && success;
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }

        }

        assertTrue(success);

        assertEquals(EP_NR, ksession.fireAllRules());

        for (int i = 0; i < EP_NR; i++) {
            assertEquals(1, ((List) ksession.getGlobal("results" + i)).size());
        }

        ksession.dispose();
    }

    public static class EPManipulator implements Callable<Boolean> {

        private final KieSession ksession;
        private final int index;

        public EPManipulator(KieSession ksession, int index) {
            this.ksession = ksession;
            this.index = index;
        }

        public Boolean call() throws Exception {
            List results = new ArrayList();
            ksession.setGlobal("results" + index, results);

            ksession.insert("ACME" + index);

            EntryPoint ep = ksession.getEntryPoint("EP" + index);

            for (int i = 0; i < 12; i++) {
                ep.insert(new StockTick(1, "ACME" + index, i - 50));
                ep.insert(new StockTick(2, "DROO" + index, i));
                ep.insert(new StockTick(3, "ACME" + index, i));
            }

            return true;
        }
    }

    @Test(timeout = 10000)
    public void testMultipleConcurrentEPs2() {
        String str = "global java.util.List results\n" +
                     "\n" +
                     "rule \"R0\" when\n" +
                     "    $s : String( ) from entry-point EP0\n" +
                     "    $i : Integer( toString().equals($s) ) from entry-point EP1\n" +
                     "    $l : Long( intValue() == $i ) from entry-point EP2\n" +
                     "then\n" +
                     "    results.add( $s );\n" +
                     "end\n" +
                     "\n" +
                     "rule \"R1\" when\n" +
                     "    $s : String( ) from entry-point EP1\n" +
                     "    $i : Integer( toString().equals($s) ) from entry-point EP2\n" +
                     "    $l : Long( intValue() == $i ) from entry-point EP0\n" +
                     "then\n" +
                     "    results.add( $s );\n" +
                     "end\n" +
                     "\n" +
                     "rule \"R2\" when\n" +
                     "    $s : String( ) from entry-point EP2\n" +
                     "    $i : Integer( toString().equals($s) ) from entry-point EP0\n" +
                     "    $l : Long( intValue() == $i ) from entry-point EP1\n" +
                     "then\n" +
                     "    results.add( $s );\n" +
                     "end\n";

        KnowledgeBase kbase = loadKnowledgeBaseFromString(str);
        KieSession ksession = kbase.newStatefulKnowledgeSession();

        List<String> results = new ArrayList<String>();
        ksession.setGlobal("results", results);

        boolean success = true;
        CompletionService<Boolean> ecs = new ExecutorCompletionService<Boolean>(executor);
        for (int i = 0; i < 3; i++) {
            ecs.submit(new EPManipulator2(ksession, i));
        }

        for (int i = 0; i < 3; i++) {
            try {
                success = ecs.take().get() && success;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        assertTrue(success);

        ksession.fireAllRules();
        System.out.println(results);
        assertEquals(3, results.size());
        for (String s : results) {
            assertEquals("2", s);
        }
    }

    public static class EPManipulator2 implements Callable<Boolean> {

        private final KieSession ksession;
        private final int index;

        public EPManipulator2(KieSession ksession, int index) {
            this.ksession = ksession;
            this.index = index;
        }

        public Boolean call() throws Exception {
            EntryPoint ep = ksession.getEntryPoint("EP" + index);

            FactHandle[] fhs = new FactHandle[15];

            for (int j = 0; j < 3; j++) {
                for (int i = 0; i < 5; i++) {
                    fhs[i * 3] = ep.insert("" + i);
                    fhs[i * 3 + 1] = ep.insert(new Long(i));
                    fhs[i * 3 + 2] = ep.insert(new Integer(i));
                }

                for (int i = 0; i < 5; i++) {
                    if (i == index+j) continue;
                    ep.delete(fhs[i * 3]);
                    ep.delete(fhs[i * 3 + 1]);
                    ep.delete(fhs[i * 3 + 2]);
                }
            }

            return true;
        }
    }

    private KieSession getKieSessionWith3Segments() {
        String str = "global java.util.List results\n" +
                     "rule R1 when\n" +
                     "   String( this == \"1\") from entry-point EP1\n" +
                     "   String( this == \"2\") from entry-point EP2\n" +
                     "   String( this == \"3\") from entry-point EP3\n" +
                     "   String( this == \"4\") from entry-point EP4\n" +
                     "   String( this == \"5\") from entry-point EP5\n" +
                     "   String( this == \"6\") from entry-point EP6\n" +
                     "   String( this == \"7\") from entry-point EP7\n" +
                     "   String( this == \"8\") from entry-point EP8\n" +
                     "   String( this == \"9\") from entry-point EP9\n" +
                     "then\n" +
                     "   results.add(\"R1\");\n" +
                     "end\n" +
                     "\n" +
                     "rule R2 when\n" +
                     "   String( this == \"1\") from entry-point EP1\n" +
                     "   String( this == \"2\") from entry-point EP2\n" +
                     "   String( this == \"3\") from entry-point EP3\n" +
                     "   eval(true)\n" +
                     "   String( this == \"4\") from entry-point EP4\n" +
                     "   String( this == \"5\") from entry-point EP5\n" +
                     "   String( this == \"6\") from entry-point EP6\n" +
                     "   String( this == \"7\") from entry-point EP7\n" +
                     "   String( this == \"8\") from entry-point EP8\n" +
                     "   String( this == \"9\") from entry-point EP9\n" +
                     "then\n" +
                     "   results.add(\"R2\");\n" +
                     "end\n" +
                     "\n" +
                     "rule R3 when\n" +
                     "   String( this == \"1\") from entry-point EP1\n" +
                     "   String( this == \"2\") from entry-point EP2\n" +
                     "   String( this == \"3\") from entry-point EP3\n" +
                     "   eval(true)\n" +
                     "   String( this == \"4\") from entry-point EP4\n" +
                     "   String( this == \"5\") from entry-point EP5\n" +
                     "   String( this == \"6\") from entry-point EP6\n" +
                     "   eval(true)\n" +
                     "   String( this == \"7\") from entry-point EP7\n" +
                     "   String( this == \"8\") from entry-point EP8\n" +
                     "   String( this == \"9\") from entry-point EP9\n" +
                     "then\n" +
                     "   results.add(\"R3\");\n" +
                     "end\n";

        KnowledgeBase kbase = loadKnowledgeBaseFromString(str);
        return kbase.newStatefulKnowledgeSession();
    }

    @Test
    public void testMultipleConcurrentEPs3() {
        final KieSession ksession = getKieSessionWith3Segments();

        List<String> results = new ArrayList<String>();
        ksession.setGlobal("results", results);

        EPManipulator3[] epManipulators = new EPManipulator3[9];
        for (int i = 0; i < 9; i++) {
            epManipulators[i] = new EPManipulator3(ksession, i+1);
        }

        for (int deleteIndex = 0; deleteIndex < 11; deleteIndex++) {
            boolean success = true;
            CompletionService<Boolean> ecs = new ExecutorCompletionService<Boolean>(executor);
            for (int i = 0; i < 9; i++) {
                ecs.submit(epManipulators[i].setDeleteIndex(deleteIndex % 10));
            }

            for (int i = 1; i < 10; i++) {
                try {
                    success = ecs.take().get() && success;
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }

            assertTrue(success);

            new Thread () {
                public void run () {
                    ksession.fireUntilHalt();
                }
            }.start ();

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            ksession.halt();

            if (deleteIndex % 10 == 0) {
                assertEquals(3, results.size());
                assertTrue(results.containsAll(asList("R1", "R2", "R3")));
            } else {
                if (!results.isEmpty()) {
                    fail("Results should be empty with deleteIndex = " + deleteIndex + "; got " + results.size() + " items");
                }
            }

            results.clear();
        }
    }

    public static class EPManipulator3 implements Callable<Boolean> {

        private static final Random RANDOM = new Random(0);

        private final KieSession ksession;
        private final int index;

        private int deleteIndex;

        private FactHandle fh = null;

        public EPManipulator3(KieSession ksession, int index) {
            this.ksession = ksession;
            this.index = index;
        }

        public Boolean call() throws Exception {
            EntryPoint ep = ksession.getEntryPoint("EP" + index);

            InternalWorkingMemory wm = ((NamedEntryPoint)ep).getInternalWorkingMemory();
            ObjectTypeNode otn = ((NamedEntryPoint)ep).getEntryPointNode().getObjectTypeNodes().values().iterator().next();
            AlphaNode alpha = (AlphaNode)otn.getSinkPropagator().getSinks()[0];
            BetaNode beta = (BetaNode)alpha.getSinkPropagator().getSinks()[0];
            BetaMemory memory = (BetaMemory) wm.getNodeMemory(beta);
            memory.getSegmentMemory();

            for (int i = 0; i < 100; i++) {
                Thread.sleep(RANDOM.nextInt(100));
                if (fh == null) {
                    fh = ep.insert("" + index);
                } else {
                    if ( RANDOM.nextInt(100) < 70 ) {
                        ep.delete(fh);
                        fh = null;
                    } else {
                        ep.update(fh, "" + index);
                    }
                }
            }

            if (index == deleteIndex) {
                if (fh != null) {
                    ep.delete(fh);
                    fh = null;
                }
            } else if (fh == null) {
                fh = ep.insert("" + index);
            }

            return true;
        }

        public EPManipulator3 setDeleteIndex(int deleteIndex) {
            this.deleteIndex = deleteIndex;
            return this;
        }
    }

    @Test
    public void testMultipleConcurrentEPs4() {
        final KieSession ksession = getKieSessionWith3Segments();

        List<String> results = new ArrayList<String>();
        ksession.setGlobal("results", results);

        EPManipulator4[] epManipulators = new EPManipulator4[9];
        CyclicBarrier barrier = new CyclicBarrier(9, new SegmentChecker(epManipulators));
        for (int i = 0; i < 9; i++) {
            epManipulators[i] = new EPManipulator4(ksession, i+1, barrier);
        }

        new Thread () {
            public void run () {
                ksession.fireUntilHalt();
            }
        }.start();

        for (int deleteIndex = 0; deleteIndex < 11; deleteIndex++) {
            boolean success = true;
            CompletionService<Boolean> ecs = new ExecutorCompletionService<Boolean>(executor);
            for (int i = 0; i < 9; i++) {
                ecs.submit(epManipulators[i].setDeleteIndex(deleteIndex % 10));
            }

            for (int i = 0; i < 9; i++) {
                try {
                    success = ecs.take().get() && success;
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }

            assertTrue(success);
        }

        ksession.halt();
    }

    public static class EPManipulator4 implements Callable<Boolean> {

        private static final Random RANDOM = new Random();

        private final KieSession ksession;
        private final int index;
        private final CyclicBarrier barrier;

        private int deleteIndex;

        private FactHandle fh = null;

        private final EntryPoint ep;

        public EPManipulator4(KieSession ksession, int index, CyclicBarrier barrier) {
            this.ksession = ksession;
            this.index = index;
            this.barrier = barrier;
            this.ep = ksession.getEntryPoint("EP" + index);
        }

        public Boolean call() throws Exception {
            for (int i = 0; i < 100; i++) {
                Thread.sleep(RANDOM.nextInt(100));
                if (fh == null) {
                    fh = ep.insert("" + index);
                } else {
                    if ( RANDOM.nextInt(100) < 70 ) {
                        ep.delete(fh);
                        fh = null;
                    } else {
                        ep.update(fh, "" + index);
                    }
                }

                if (i % 10 == 9) {
                    if (!barrier.isBroken()) {
                        barrier.await();
                    } else {
                        fail("This is not a bug in phreak synchronization, but a for some reason the barrier is broken, run the test again");
                        return false;
                    }
                }
            }

            if (index == deleteIndex) {
                if (fh != null) {
                    ep.delete(fh);
                    fh = null;
                }
            } else if (fh == null) {
                fh = ep.insert("" + index);
            }

            return true;
        }

        public EPManipulator4 setDeleteIndex(int deleteIndex) {
            this.deleteIndex = deleteIndex;
            return this;
        }

        public boolean isInserted() {
            return fh != null;
        }

        public CyclicBarrier getBarrier() {
            return barrier;
        }

        public EntryPoint getEntryPoiny() {
            return ep;
        }
    }

    public static class SegmentChecker implements Runnable {

        private final EPManipulator4[] epManipulators;

        private PathMemory[] pathMemories;

        public SegmentChecker(EPManipulator4[] epManipulators) {
            this.epManipulators = epManipulators;
        }

        @Override
        public void run() {
            System.out.println("Sync point");
            if (pathMemories == null) {
                initPathMemories();
            }

            String s = "";
            for (int i = 0; i < epManipulators.length; i++) {
                if (epManipulators[i].isInserted()) {
                    s = "1" + s;
                } else {
                    s = "0" + s;
                }
            }
            System.out.println("Inserted facts mask = " + s);

            // P0 = s0 + s1
            SegmentMemory s0 = pathMemories[0].getSegmentMemories()[0];
            SegmentMemory s1 = pathMemories[0].getSegmentMemories()[1];

            // P1 = s0 + s2 + s3
            SegmentMemory s2 = pathMemories[1].getSegmentMemories()[1];
            SegmentMemory s3 = pathMemories[1].getSegmentMemories()[2];

            // P2 = s0 + s2 + s4
            SegmentMemory s4 = pathMemories[2].getSegmentMemories()[2];

            long s0Mask = 1; // InitialFact is always present
            long s1Mask = 0;
            long s2Mask = 0;
            long s3Mask = 0;
            long s4Mask = 0;

            if (epManipulators[0].isInserted()) {
                s0Mask |= 2;
            }
            if (epManipulators[1].isInserted()) {
                s0Mask |= 4;
            }
            if (epManipulators[2].isInserted()) {
                s0Mask |= 8;
            }
            if (epManipulators[3].isInserted()) {
                s1Mask |= 1;
                s2Mask |= 2;
            }
            if (epManipulators[4].isInserted()) {
                s1Mask |= 2;
                s2Mask |= 4;
            }
            if (epManipulators[5].isInserted()) {
                s1Mask |= 4;
                s2Mask |= 8;
            }
            if (epManipulators[6].isInserted()) {
                s1Mask |= 8;
                s3Mask |= 1;
                s4Mask |= 2;
            }
            if (epManipulators[7].isInserted()) {
                s1Mask |= 16;
                s3Mask |= 2;
                s4Mask |= 4;
            }
            if (epManipulators[8].isInserted()) {
                s1Mask |= 32;
                s3Mask |= 4;
                s4Mask |= 8;
            }

            assertEquals(s0Mask, s0.getLinkedNodeMask());
            assertEquals(s1Mask, s1.getLinkedNodeMask());
            assertEquals(s2Mask, s2.getLinkedNodeMask());
            assertEquals(s3Mask, s3.getLinkedNodeMask());
            assertEquals(s4Mask, s4.getLinkedNodeMask());

            long p0Mask = 0;
            long p1Mask = 0;
            long p2Mask = 0;

            if ((s0Mask & 15) == 15) {
                assertTrue(s0.isSegmentLinked());
                p0Mask |= 1;
                p1Mask |= 1;
                p2Mask |= 1;
            } else {
                assertFalse(s0.isSegmentLinked());
            }

            if ((s1Mask & 63) == 63) {
                assertTrue(s1.isSegmentLinked());
                p0Mask |= 2;
            } else {
                assertFalse(s1.isSegmentLinked());
            }

            if ((s2Mask & 14) == 14) {
                assertTrue(s2.isSegmentLinked());
                p1Mask |= 2;
                p2Mask |= 2;
            } else {
                assertFalse(s2.isSegmentLinked());
            }

            if ((s3Mask & 7) == 7) {
                assertTrue(s3.isSegmentLinked());
                p1Mask |= 4;
            } else {
                assertFalse(s3.isSegmentLinked());
            }

            if ((s4Mask & 14) == 14) {
                assertTrue(s4.isSegmentLinked());
                p2Mask |= 4;
            } else {
                assertFalse(s4.isSegmentLinked());
            }

            assertEquals(p0Mask == 3, pathMemories[0].isRuleLinked());
            assertEquals(p1Mask == 7, pathMemories[1].isRuleLinked());
            assertEquals(p2Mask == 7, pathMemories[2].isRuleLinked());
        }

        private void initPathMemories() {
            pathMemories = new PathMemory[3];
            NamedEntryPoint ep = (NamedEntryPoint)epManipulators[8].getEntryPoiny();
            InternalWorkingMemory wm = ((NamedEntryPoint)ep).getInternalWorkingMemory();
            ObjectTypeNode otn = ((NamedEntryPoint)ep).getEntryPointNode().getObjectTypeNodes().values().iterator().next();
            AlphaNode alpha = (AlphaNode)otn.getSinkPropagator().getSinks()[0];
            ObjectSink[] sinks = alpha.getSinkPropagator().getSinks();
            for (int i = 0; i < sinks.length; i++) {
                BetaNode beta = (BetaNode)sinks[i];
                RuleTerminalNode rtn = (RuleTerminalNode)beta.getSinkPropagator().getSinks()[0];
                pathMemories[i] ( PathMemory ) wm.getNodeMemory(rtn);
            }
        }
    }


    @Test
    public void testFactLeak() throws InterruptedException {
        for ( int i = 0; i < 100; i++ ) {
            // repeat this 100 times, to try and better detect thread issues
            doFactLeak();
            System.gc();
            Thread.sleep(200);
        }
    }

    public void doFactLeak() throws InterruptedException {
        //DROOLS-131
        String drl = "package org.drools.test; \n" +
                     "global " + ConcurrentLinkedQueue.class.getCanonicalName() + " list; \n" +
                     //"global " + AtomicInteger.class.getCanonicalName() + "counter; \n" +
                     "" +
                     "rule Intx when\n" +
                     " $x : Integer() from entry-point \"x\" \n" +
                     "then\n" +
                     " list.add( $x );" +
                     "end";
        int N = 1100;

        KnowledgeBase kb = loadKnowledgeBaseFromString( drl );
        final StatefulKnowledgeSession ks = kb.newStatefulKnowledgeSession();
        ConcurrentLinkedQueue list = new ConcurrentLinkedQueue<Integer>();
        AtomicInteger counter = new AtomicInteger(0);
        ks.setGlobal( "list", list );
        //ks.setGlobal( "counter", counter );

        new Thread () {
            public void run () {
                ks.fireUntilHalt();
            }
        }.start ();

        for ( int j = 0; j < N; j++ ) {
            ks.getEntryPoint( "x" ).insert( new Integer( j ) );
        }

        int count = 0;
        while ( list.size() != N && count++ != 1000) {
            Thread.sleep( 200 );
        }

        ks.halt();
        if ( list.size() != N ) {
            for ( int j = 0; j < N; j++ ) {
                if ( !list.contains( new Integer( j ) ) ) {
                    System.out.println( "missed: " + j );
                }
            }
        }

        assertEquals( N, list.size() );
    }
}
TOP

Related Classes of org.drools.compiler.integrationtests.PhreakConcurrencyTest$EPManipulator3

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.