Skip to content

Commit 93e17ca

Browse files
committed
Hibernate ORM - Generate proxies in parallel
1 parent 0816552 commit 93e17ca

File tree

1 file changed

+40
-20
lines changed

1 file changed

+40
-20
lines changed

extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@
2929
import java.util.Properties;
3030
import java.util.Set;
3131
import java.util.TreeSet;
32+
import java.util.concurrent.CompletableFuture;
33+
import java.util.concurrent.ConcurrentLinkedDeque;
34+
import java.util.concurrent.ExecutionException;
35+
import java.util.concurrent.ExecutorService;
36+
import java.util.concurrent.Future;
3237
import java.util.function.BiConsumer;
3338
import java.util.stream.Collectors;
3439

@@ -465,7 +470,8 @@ public BytecodeRecorderConstantDefinitionBuildItem pregenProxies(
465470
List<PersistenceUnitDescriptorBuildItem> persistenceUnitDescriptorBuildItems,
466471
List<AdditionalJpaModelBuildItem> additionalJpaModelBuildItems,
467472
BuildProducer<GeneratedClassBuildItem> generatedClassBuildItemBuildProducer,
468-
LiveReloadBuildItem liveReloadBuildItem) {
473+
LiveReloadBuildItem liveReloadBuildItem,
474+
ExecutorService buildExecutor) throws ExecutionException, InterruptedException {
469475
Set<String> managedClassAndPackageNames = new HashSet<>(jpaModel.getEntityClassNames());
470476
for (PersistenceUnitDescriptorBuildItem pud : persistenceUnitDescriptorBuildItems) {
471477
// Note: getManagedClassNames() can also return *package* names
@@ -479,9 +485,9 @@ public BytecodeRecorderConstantDefinitionBuildItem pregenProxies(
479485
managedClassAndPackageNames.add(additionalJpaModelBuildItem.getClassName());
480486
}
481487

482-
PreGeneratedProxies proxyDefinitions = generatedProxies(managedClassAndPackageNames,
488+
PreGeneratedProxies proxyDefinitions = generateProxies(managedClassAndPackageNames,
483489
indexBuildItem.getIndex(), transformedClassesBuildItem,
484-
generatedClassBuildItemBuildProducer, liveReloadBuildItem);
490+
generatedClassBuildItemBuildProducer, liveReloadBuildItem, buildExecutor);
485491

486492
// Make proxies available through a constant;
487493
// this is a hack to avoid introducing circular dependencies between build steps.
@@ -1372,53 +1378,65 @@ private static MultiTenancyStrategy getMultiTenancyStrategy(Optional<String> mul
13721378
return multiTenancyStrategy;
13731379
}
13741380

1375-
private PreGeneratedProxies generatedProxies(Set<String> managedClassAndPackageNames, IndexView combinedIndex,
1381+
private PreGeneratedProxies generateProxies(Set<String> managedClassAndPackageNames, IndexView combinedIndex,
13761382
TransformedClassesBuildItem transformedClassesBuildItem,
13771383
BuildProducer<GeneratedClassBuildItem> generatedClassBuildItemBuildProducer,
1378-
LiveReloadBuildItem liveReloadBuildItem) {
1384+
LiveReloadBuildItem liveReloadBuildItem,
1385+
ExecutorService buildExecutor) throws ExecutionException, InterruptedException {
13791386
ProxyCache proxyCache = liveReloadBuildItem.getContextObject(ProxyCache.class);
13801387
if (proxyCache == null) {
13811388
proxyCache = new ProxyCache();
13821389
liveReloadBuildItem.setContextObject(ProxyCache.class, proxyCache);
13831390
}
1384-
Set<String> changedClasses = Collections.emptySet();
1391+
Set<String> changedClasses = Set.of();
13851392
if (liveReloadBuildItem.getChangeInformation() != null) {
13861393
changedClasses = liveReloadBuildItem.getChangeInformation().getChangedClasses();
13871394
} else {
13881395
//we don't have class change info, invalidate the cache
13891396
proxyCache.cache.clear();
13901397
}
13911398
//create a map of entity to proxy type
1392-
PreGeneratedProxies preGeneratedProxies = new PreGeneratedProxies();
13931399
TypePool transformedClassesTypePool = createTransformedClassesTypePool(transformedClassesBuildItem,
13941400
managedClassAndPackageNames);
1401+
1402+
PreGeneratedProxies preGeneratedProxies = new PreGeneratedProxies();
1403+
13951404
try (ProxyBuildingHelper proxyHelper = new ProxyBuildingHelper(transformedClassesTypePool)) {
1405+
final ConcurrentLinkedDeque<Future<CachedProxy>> generatedProxyQueue = new ConcurrentLinkedDeque<>();
1406+
Set<String> proxyInterfaceNames = Set.of(ClassNames.HIBERNATE_PROXY.toString());
1407+
13961408
for (String managedClassOrPackageName : managedClassAndPackageNames) {
1397-
CachedProxy result;
13981409
if (proxyCache.cache.containsKey(managedClassOrPackageName)
13991410
&& !isModified(managedClassOrPackageName, changedClasses, combinedIndex)) {
1400-
result = proxyCache.cache.get(managedClassOrPackageName);
1411+
CachedProxy proxy = proxyCache.cache.get(managedClassOrPackageName);
1412+
generatedProxyQueue.add(CompletableFuture.completedFuture(proxy));
14011413
} else {
1402-
Set<String> proxyInterfaceNames = new TreeSet<>();
1403-
proxyInterfaceNames.add(ClassNames.HIBERNATE_PROXY.toString()); //always added
14041414
if (!proxyHelper.isProxiable(combinedIndex.getClassByName(managedClassOrPackageName))) {
14051415
// we need to make sure the actual class is proxiable
14061416
continue;
14071417
}
1408-
final String mappedClass = managedClassOrPackageName;
1409-
DynamicType.Unloaded<?> unloaded = proxyHelper.buildUnloadedProxy(mappedClass, proxyInterfaceNames);
1410-
result = new CachedProxy(unloaded, proxyInterfaceNames);
1411-
proxyCache.cache.put(managedClassOrPackageName, result);
1418+
// we now are sure we have a proper class and not a package
1419+
String managedClass = managedClassOrPackageName;
1420+
generatedProxyQueue.add(buildExecutor.submit(() -> {
1421+
DynamicType.Unloaded<?> unloaded = proxyHelper.buildUnloadedProxy(managedClass,
1422+
proxyInterfaceNames);
1423+
return new CachedProxy(managedClass, unloaded, proxyInterfaceNames);
1424+
}));
14121425
}
1413-
for (Entry<TypeDescription, byte[]> i : result.proxyDef.getAllTypes().entrySet()) {
1426+
}
1427+
1428+
for (Future<CachedProxy> proxyFuture : generatedProxyQueue) {
1429+
CachedProxy proxy = proxyFuture.get();
1430+
proxyCache.cache.putIfAbsent(proxy.managedClassName, proxy);
1431+
for (Entry<TypeDescription, byte[]> i : proxy.proxyDef.getAllTypes().entrySet()) {
14141432
generatedClassBuildItemBuildProducer
14151433
.produce(new GeneratedClassBuildItem(true, i.getKey().getName(), i.getValue()));
14161434
}
1417-
preGeneratedProxies.getProxies().put(managedClassOrPackageName,
1418-
new PreGeneratedProxies.ProxyClassDetailsHolder(result.proxyDef.getTypeDescription().getName(),
1419-
result.interfaces));
1435+
preGeneratedProxies.getProxies().put(proxy.managedClassName, new PreGeneratedProxies.ProxyClassDetailsHolder(
1436+
proxy.proxyDef.getTypeDescription().getName(), proxy.interfaces));
14201437
}
14211438
}
1439+
14221440
return preGeneratedProxies;
14231441
}
14241442

@@ -1476,10 +1494,12 @@ private static final class ProxyCache {
14761494
}
14771495

14781496
static final class CachedProxy {
1497+
final String managedClassName;
14791498
final DynamicType.Unloaded<?> proxyDef;
14801499
final Set<String> interfaces;
14811500

1482-
CachedProxy(DynamicType.Unloaded<?> proxyDef, Set<String> interfaces) {
1501+
CachedProxy(String managedClassName, DynamicType.Unloaded<?> proxyDef, Set<String> interfaces) {
1502+
this.managedClassName = managedClassName;
14831503
this.proxyDef = proxyDef;
14841504
this.interfaces = interfaces;
14851505
}

0 commit comments

Comments
 (0)