Skip to content

Commit

Permalink
Merge pull request #64 from shreyeep/RHDM-2028-blue
Browse files Browse the repository at this point in the history
[7.67.x-blue][RHDM-2028] Deadlock between KieRepositoryImpl.kieModuleRepo and KieScannerHolder.kieScanner
  • Loading branch information
akumar074 authored Jul 17, 2024
2 parents ac25183 + 3bf58a2 commit 2441199
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,11 @@ private KieModule checkClasspathForKieModule(ReleaseId releaseId) {
}

private KieModule loadKieModuleFromMavenRepo(ReleaseId releaseId, PomModel pomModel) {
return KieScannerHolder.kieScanner.loadArtifact( releaseId, pomModel );
KieModule kieModule;
synchronized (kieModuleRepo) { // Make sure kieModuleRepo lock is acquired before kieScanner lock
kieModule = KieScannerHolder.kieScanner.loadArtifact(releaseId, pomModel);
}
return kieModule;
}

private static class DummyKieScanner
Expand Down
21 changes: 20 additions & 1 deletion kie-ci/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

<properties>
<java.module.name>org.kie.ci</java.module.name>
<excludedGroups>org.kie.test.testcategory.TurtleTestCategory</excludedGroups>
</properties>

<dependencies>
Expand Down Expand Up @@ -209,7 +210,12 @@
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-test-util</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down Expand Up @@ -260,4 +266,17 @@
</plugins>
</build>

<profiles>
<profile>
<id>runTurtleTests</id>
<activation>
<property>
<name>runTurtleTests</name>
</property>
</activation>
<properties>
<excludedGroups/>
</properties>
</profile>
</profiles>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* 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.kie.scanner.concurrent;

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.drools.compiler.kie.builder.impl.InternalKieModule;
import org.drools.core.util.FileManager;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.kie.api.KieServices;
import org.kie.api.builder.ReleaseId;
import org.kie.scanner.AbstractKieCiTest;
import org.kie.scanner.KieMavenRepository;
import org.kie.test.testcategory.TurtleTestCategory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.junit.Assert.assertTrue;
import static org.kie.scanner.KieMavenRepository.getKieMavenRepository;

@Category(TurtleTestCategory.class)
public class ConcurrentBuildTest extends AbstractKieCiTest {
private static final Logger LOG = LoggerFactory.getLogger(ConcurrentBuildTest.class);

private FileManager fileManager;

@Before
public void setUp() throws Exception {
this.fileManager = new FileManager();
this.fileManager.setUp();
ReleaseId releaseId = KieServices.Factory.get().newReleaseId("org.kie", "scanner-test", "1.0-SNAPSHOT");
}

@After
public void tearDown() throws Exception {
this.fileManager.tearDown();
}

// This is TurtleTest. You can run this test with -PrunTurtleTests
@Test(timeout=600000)
public void concurrentBuildWithDependency() throws Exception {
KieServices ks = KieServices.Factory.get();
KieMavenRepository repository = getKieMavenRepository();

final int testLoop = 10;
for (int m = 0; m < testLoop; m++) {
System.out.println("===== test loop " + m + " start");

// test-dep-a exists in KieRepositoryImpl$KieModuleRepo
// To resolve test-dep-a, KieRepositoryImpl$KieModuleRepo.load -> KieRepositoryScannerImpl.getArtifactVersion
// , so the lock order is kieModuleRepo -> kieScanner
System.out.println("===== dep A start");
ReleaseId releaseIdDepA = ks.newReleaseId("org.kie", "test-dep-a", "1.0-SNAPSHOT");
InternalKieModule kJarDepA = createKieJar(ks, releaseIdDepA, false, "ruleA");
repository.installArtifact(releaseIdDepA, kJarDepA, createKPom(fileManager, releaseIdDepA));

// test-dep-b does not exist in KieRepositoryImpl$KieModuleRepo. Instead, it is installed in local Maven repository
// To resolve test-dep-b, KieRepositoryImpl.loadKieModuleFromMavenRepo -> KieRepositoryImpl$KieModuleRepo.load
// , so the lock order is kieScanner -> kieModuleRepo
System.out.println("===== dep B start");
ReleaseId releaseIdDepB = ks.newReleaseId("org.kie", "test-dep-b", "1.0-SNAPSHOT");
InternalKieModule kJarDepB = createKieJarWithDependencies(ks, releaseIdDepB, false, "ruleB", releaseIdDepA); // test-dep-b depends on test-dep-a
repository.installArtifact(releaseIdDepB, kJarDepB, createKPom(fileManager, releaseIdDepB, releaseIdDepA));
KieServices.Factory.get().getRepository().removeKieModule(releaseIdDepB);

System.out.println("===== dep artifacts are ready. Start concurrent build");

final int maxThread = 20;
ExecutorService executor = Executors.newFixedThreadPool(maxThread);

for (int n = 0; n < maxThread; n++) {
final int i = n;
executor.execute(() -> {
ReleaseId releaseId = ks.newReleaseId("org.kie", "test-" + i, "1.0-SNAPSHOT");
try {
ReleaseId myDependencyId = i % 2 == 0 ? releaseIdDepA : releaseIdDepB;
InternalKieModule kJar = createKieJarWithDependencies(ks, releaseId, false, "rule" + i, myDependencyId);
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}

executor.shutdown();
executor.awaitTermination(300, TimeUnit.SECONDS);

// cleanup
KieServices.Factory.get().getRepository().removeKieModule(releaseIdDepA);
KieServices.Factory.get().getRepository().removeKieModule(releaseIdDepB);
}
assertTrue(true); // no deadlock
}
}

0 comments on commit 2441199

Please sign in to comment.