From 6d453fc3342960fb3ddeabff96c02293a4eaf307 Mon Sep 17 00:00:00 2001 From: holzig Date: Thu, 6 Jul 2023 11:49:55 +0000 Subject: [PATCH] [DROOLS-7496] fixing concurrency problems in TruthMaintenanceSystemImpl (#5374) --- ...TruthMaintenanceSystemConcurrencyTest.java | 67 +++++++++++++++++++ .../regression/test_concurrency.drl | 33 +++++++++ .../tms/TruthMaintenanceSystemImpl.java | 9 +-- 3 files changed, 103 insertions(+), 6 deletions(-) create mode 100644 drools-test-coverage/test-suite/src/test/java/org/drools/testcoverage/regression/TruthMaintenanceSystemConcurrencyTest.java create mode 100644 drools-test-coverage/test-suite/src/test/resources/org/drools/testcoverage/regression/test_concurrency.drl diff --git a/drools-test-coverage/test-suite/src/test/java/org/drools/testcoverage/regression/TruthMaintenanceSystemConcurrencyTest.java b/drools-test-coverage/test-suite/src/test/java/org/drools/testcoverage/regression/TruthMaintenanceSystemConcurrencyTest.java new file mode 100644 index 00000000000..8a324ada5ec --- /dev/null +++ b/drools-test-coverage/test-suite/src/test/java/org/drools/testcoverage/regression/TruthMaintenanceSystemConcurrencyTest.java @@ -0,0 +1,67 @@ +package org.drools.testcoverage.regression; + +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import org.drools.kiesession.rulebase.InternalKnowledgeBase; +import org.drools.kiesession.rulebase.KnowledgeBaseFactory; +import org.drools.kiesession.session.StatefulKnowledgeSessionImpl; +import org.drools.mvel.compiler.Cheese; +import org.junit.Test; +import org.kie.api.definition.KiePackage; +import org.kie.api.io.ResourceType; +import org.kie.api.runtime.ClassObjectFilter; +import org.kie.internal.builder.KnowledgeBuilder; +import org.kie.internal.builder.KnowledgeBuilderFactory; +import org.kie.internal.io.ResourceFactory; + +import static org.assertj.core.api.Assertions.assertThat; + + +public class TruthMaintenanceSystemConcurrencyTest { + + @Test + public void testUsingMultipleSessionsConcurrently() throws InterruptedException { + final KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); + kbuilder.add( + ResourceFactory.newClassPathResource( + "test_concurrency.drl", + getClass() + ), + ResourceType.DRL + ); + Collection kpkgs = kbuilder.getKnowledgePackages(); + + InternalKnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(); + kbase.addPackages(kpkgs); + + final ExecutorService executorService = Executors.newFixedThreadPool(20); + + final Collection errors = + Collections.synchronizedCollection(new LinkedList<>()); + for (int i = 0; i < 2000; i++) { + executorService.submit(() -> { + try { + StatefulKnowledgeSessionImpl ksession = (StatefulKnowledgeSessionImpl) kbase.newKieSession(); + + ksession.fireAllRules(); + assertThat(ksession.getObjects(new ClassObjectFilter(Cheese.class))) + .hasSize(2); + } catch (Throwable e) { + errors.add(e); + } + }); + } + executorService.shutdown(); + assertThat(executorService.awaitTermination(2, TimeUnit.SECONDS)) + .isTrue(); + + assertThat(errors) + .isEmpty(); + } + +} \ No newline at end of file diff --git a/drools-test-coverage/test-suite/src/test/resources/org/drools/testcoverage/regression/test_concurrency.drl b/drools-test-coverage/test-suite/src/test/resources/org/drools/testcoverage/regression/test_concurrency.drl new file mode 100644 index 00000000000..22d2c6183de --- /dev/null +++ b/drools-test-coverage/test-suite/src/test/resources/org/drools/testcoverage/regression/test_concurrency.drl @@ -0,0 +1,33 @@ +/* + * Copyright 2015 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +package org.drools.testcoverage.regression; + +import org.drools.mvel.compiler.Cheese; + +rule "default" + then + insert("cheeseType"); + insert(new Cheese("cheeseType")); +end + + +rule "insert new Cheese" + when + $type : String(this == "cheeseType") + Cheese( type == $type ) + then + insertLogical( new Cheese("success") ); +end diff --git a/drools-tms/src/main/java/org/drools/tms/TruthMaintenanceSystemImpl.java b/drools-tms/src/main/java/org/drools/tms/TruthMaintenanceSystemImpl.java index 3d838794c51..25fa6c5b742 100644 --- a/drools-tms/src/main/java/org/drools/tms/TruthMaintenanceSystemImpl.java +++ b/drools-tms/src/main/java/org/drools/tms/TruthMaintenanceSystemImpl.java @@ -68,17 +68,14 @@ public TruthMaintenanceSystemImpl(InternalWorkingMemoryEntryPoint ep) { } private static class EqualityKeyPlaceholder { - private static final EqualityKeyPlaceholder INSTANCE = new EqualityKeyPlaceholder(); + private final Object object; - private Object object; - - public EqualityKeyPlaceholder withObject(Object object) { + private EqualityKeyPlaceholder(final Object object) { this.object = object; - return this; } private static Object transformEqualityKey(Object o) { - return o instanceof EqualityKey ? o : EqualityKeyPlaceholder.INSTANCE.withObject(o); + return o instanceof EqualityKey ? o : new EqualityKeyPlaceholder(o); } @Override