Skip to content

Commit

Permalink
Warmup Phase
Browse files Browse the repository at this point in the history
refine warmup

flexible warmup

Update core/deployment/src/main/java/io/quarkus/deployment/CracConfig.java

Co-authored-by: Clement Escoffier <[email protected]>

Update core/deployment/src/main/java/io/quarkus/deployment/CracConfig.java

Co-authored-by: Clement Escoffier <[email protected]>

Update core/deployment/src/main/java/io/quarkus/deployment/CracConfig.java

Co-authored-by: Clement Escoffier <[email protected]>

Update core/deployment/src/main/java/io/quarkus/deployment/CracConfig.java

Co-authored-by: Clement Escoffier <[email protected]>

Update core/deployment/src/main/java/io/quarkus/deployment/CracConfig.java

Co-authored-by: Clement Escoffier <[email protected]>

Generate the application class list when Crac is enabled (#137)

fixes

Revert ExtensionLoader.java

revert ExecutionTime

Revert MainBytecodeRecorderBuildItem

Revert LoggingResourceProcessor

Revert BootstrapConfig

rollback more files

Fix LambdaProcessor

revert more

remove WARMUP_INIT

fullWarmup = true
  • Loading branch information
patriot1burke committed Nov 17, 2022
1 parent dcb2dbe commit b16b992
Show file tree
Hide file tree
Showing 14 changed files with 112 additions and 85 deletions.
8 changes: 8 additions & 0 deletions core/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,14 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>10</source>
<target>10</target>
</configuration>
</plugin>
</plugins>
</build>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,39 @@
public class CracConfig {

/**
* Enable/Disable CRAC registration
* Enable/Disable CRAC integration
* <p>
* Default value is dependent on extensions deployed
* (i.e. with Lambda this will be set to true by default)
* (i.e. when using AWS Lambda extensions, this will be set to true by default)
*/
@ConfigItem
Optional<Boolean> enable;

/**
* Will do a classpath search for all META-INF/crac-preload-classes files
* Will do a classpath search for all META-INF/quarkus-preload-classes.txt files
* These files contain fully qualified classnames that should be loaded
* in the CRAC init phase
*
* in the CRAC`beforeCheckpoint()` phase
*/
@ConfigItem(defaultValue = "true")
boolean preloadClasses;

/**
* Perform Application.start() within CRAC INIT phase (beforeCheckpoint())
* if preloading classes, specify whether or not
* to do static initialization when preloading these classes.
*/
@ConfigItem(defaultValue = "false")
@ConfigItem(defaultValue = "true")
boolean initializeClasses;

/**
* Perform Application.start() within CRAC `beforeCheckpoint()` phase.
*/
@ConfigItem(defaultValue = "true")
boolean fullWarmup;

/**
* When CRAC is enabled, it generates the application class list so it can be preloaded.
*/
@ConfigItem(defaultValue = "true")
boolean generateApplicationClassList;

}
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
package io.quarkus.deployment;

import java.util.List;
import java.util.Optional;
import java.util.Set;

import org.jboss.jandex.ClassInfo;
import org.jboss.logging.Logger;

import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.ExecutionTime;
import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.builditem.ApplicationArchivesBuildItem;
import io.quarkus.deployment.builditem.CracDefaultValueBuildItem;
import io.quarkus.deployment.builditem.CracEnabledBuildItem;
import io.quarkus.deployment.builditem.GeneratedClassBuildItem;
import io.quarkus.deployment.builditem.PreloadClassBuildItem;
import io.quarkus.deployment.builditem.PreloadClassesEnabledBuildItem;
import io.quarkus.deployment.builditem.TransformedClassesBuildItem;
import io.quarkus.deployment.pkg.steps.NativeBuild;
import io.quarkus.runtime.CracRecorder;

Expand All @@ -26,7 +33,7 @@ public void processCrac(BuildProducer<PreloadClassesEnabledBuildItem> preload,
CracConfig config,
Optional<CracDefaultValueBuildItem> defaultVal) {
if (config.enable.isPresent()) {
if (config.enable.get().booleanValue() == false) {
if (!config.enable.get().booleanValue()) {
return;
}

Expand All @@ -35,8 +42,37 @@ public void processCrac(BuildProducer<PreloadClassesEnabledBuildItem> preload,
}
cracEnabled.produce(CracEnabledBuildItem.INSTANCE);
if (config.preloadClasses)
preload.produce(new PreloadClassesEnabledBuildItem());
preload.produce(new PreloadClassesEnabledBuildItem(config.initializeClasses));
crac.register(config.fullWarmup);
}

@BuildStep(onlyIf = IsNormal.class, onlyIfNot = NativeBuild.class)
public void generateClassListFromApplication(
CracConfig cc,
BuildProducer<PreloadClassBuildItem> producer,
TransformedClassesBuildItem transformedClasses,
ApplicationArchivesBuildItem applicationArchivesBuildItem,
List<GeneratedClassBuildItem> generatedClasses) {
if (cc.generateApplicationClassList) {
for (Set<TransformedClassesBuildItem.TransformedClass> transformedSet : transformedClasses
.getTransformedClassesByJar().values()) {
for (TransformedClassesBuildItem.TransformedClass transformed : transformedSet) {
String className = transformed.getClassName();
producer.produce(new PreloadClassBuildItem(className));
}
}

for (GeneratedClassBuildItem i : generatedClasses) {
if (i.isApplicationClass()) {
String cn = i.getName().replace("/", ".");
producer.produce(new PreloadClassBuildItem(cn));
}
}

for (ClassInfo clz : applicationArchivesBuildItem.getRootArchive().getIndex().getKnownClasses()) {
producer.produce(new PreloadClassBuildItem(clz.toString()));
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
/**
* Class to be preloaded in static initialization phase of Quarkus
*/
public class PreloadClassBuildItem extends MultiBuildItem {
public final class PreloadClassBuildItem extends MultiBuildItem {
private final String className;

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
package io.quarkus.deployment.builditem;

import io.quarkus.builder.item.MultiBuildItem;
import io.quarkus.builder.item.SimpleBuildItem;

/**
* Extension build steps can produce this if preloading classes is enabled
*/
public final class PreloadClassesEnabledBuildItem extends MultiBuildItem {
public final class PreloadClassesEnabledBuildItem extends SimpleBuildItem {
private final boolean initialize;

public PreloadClassesEnabledBuildItem(boolean initialize) {
this.initialize = initialize;
}

public boolean doInitialize() {
return initialize;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import io.quarkus.deployment.annotations.BuildStep;
Expand All @@ -17,10 +18,10 @@
public class PreloadClassesBuildStep {
@BuildStep
@Record(ExecutionTime.STATIC_INIT)
public void preInit(List<PreloadClassesEnabledBuildItem> preload, PreloadClassesRecorder recorder) {
if (preload == null || preload.isEmpty())
public void preInit(Optional<PreloadClassesEnabledBuildItem> preload, PreloadClassesRecorder recorder) {
if (!preload.isPresent())
return;
recorder.invokePreloadClasses();
recorder.invokePreloadClasses(preload.get().doInitialize());
}

@BuildStep
Expand Down
5 changes: 0 additions & 5 deletions core/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,6 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-fs-util</artifactId>
</dependency>
<dependency>
<groupId>io.github.crac</groupId>
<artifactId>org-crac</artifactId>
</dependency>

<!--
This is required to ensure that the extension processor is built.
If we move the extension processor to a separate project, this can be removed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public abstract class Application implements Closeable {
private final Condition stateCond = stateLock.newCondition();

private int state = ST_INITIAL;
private static volatile Application currentApplication;
protected static volatile Application currentApplication;

/**
* Embedded applications don't set up or modify logging, and don't provide start/
Expand Down
35 changes: 0 additions & 35 deletions core/runtime/src/main/java/io/quarkus/runtime/CracRecorder.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package io.quarkus.runtime;

import org.crac.Context;
import org.crac.Resource;
import org.jboss.logging.Logger;

import io.quarkus.runtime.annotations.Recorder;

/**
Expand All @@ -12,42 +8,11 @@
@Recorder
public class CracRecorder {

protected static class CracResource implements Resource {
protected final boolean fullWarmup;

public CracResource(boolean fullWarmup) {
this.fullWarmup = fullWarmup;
}

@Override
public void beforeCheckpoint(Context<? extends Resource> context) throws Exception {
if (fullWarmup) {
Quarkus.manualStart();
}
}

@Override
public void afterRestore(Context<? extends Resource> context) throws Exception {
if (!fullWarmup) {
Quarkus.manualStart();
Logger.getLogger(Quarkus.class).info("Started Quarkus via CRAC afterRestore()");
} else {
Logger.getLogger(Quarkus.class).info("Started Quarkus via CRAC beforeCheckpoint()");
}
}
}

public static boolean enabled = false;
public static boolean fullWarmup = false;

public void register(boolean fw) {
enabled = true;
fullWarmup = fw;
// I originally wanted to do registration here, but for some reason
// the registration didn't result in the CRAC callbacks being executed.
// I had to move the registration into Quarkus.manualInitialize()
// Core.getGlobalContext()
// .register(new CracResource(CracRecorder.fullWarmup));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@
public class PreloadClassesRecorder {
public static final String QUARKUS_GENERATED_PRELOAD_CLASSES_FILE = "quarkus-generated-preload-classes.txt";

public static void preloadClass(String classname) {
public static void preloadClass(String classname, boolean initialize) {
try {
Class.forName(classname, true, PreloadClassesRecorder.class.getClassLoader());
Class.forName(classname, initialize, PreloadClassesRecorder.class.getClassLoader());
} catch (Throwable ignored) {

}
}

public static void preloadClasses() {
public static void preloadClasses(boolean initialize) {
try {
Enumeration<URL> files = PreloadClassesRecorder.class.getClassLoader()
.getResources("META-INF/quarkus-preload-classes.txt");
Expand All @@ -31,17 +31,17 @@ public static void preloadClasses() {
URLConnection conn = url.openConnection();
conn.setUseCaches(false);
InputStream is = conn.getInputStream();
preloadClassesFromStream(is);
preloadClassesFromStream(is, initialize);
}
} catch (IOException ignored) {
}
InputStream is = PreloadClassesRecorder.class
.getResourceAsStream("/META-INF/" + QUARKUS_GENERATED_PRELOAD_CLASSES_FILE);
if (is != null)
preloadClassesFromStream(is);
preloadClassesFromStream(is, initialize);
}

public static void preloadClassesFromStream(InputStream is) {
public static void preloadClassesFromStream(InputStream is, boolean initialize) {
try (is;
InputStreamReader isr = new InputStreamReader(is);
BufferedReader reader = new BufferedReader(isr)) {
Expand All @@ -53,15 +53,15 @@ public static void preloadClassesFromStream(InputStream is) {
}
final String className = line.stripTrailing();
if (!className.isBlank()) {
preloadClass(className);
preloadClass(className, initialize);
}
}
} catch (Exception ignored) {

}
}

public void invokePreloadClasses() {
preloadClasses();
public void invokePreloadClasses(boolean initialize) {
preloadClasses(initialize);
}
}
23 changes: 10 additions & 13 deletions core/runtime/src/main/java/io/quarkus/runtime/Quarkus.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
import java.util.Locale;
import java.util.function.BiConsumer;

import org.crac.Core;
import org.jboss.logging.Logger;

import io.quarkus.launcher.QuarkusLauncher;
import io.quarkus.runtime.logging.JBossVersion;
import io.quarkus.runtime.shutdown.ShutdownRecorder;

/**
* The entry point for applications that use a main method. Quarkus will shut down when the main method returns.
Expand Down Expand Up @@ -198,9 +198,9 @@ public static void blockingExit() {
private static final int MANUAL_BEGIN = 0;
private static final int MANUAL_BEGIN_INITIALIZATION = 1;
private static final int MANUAL_INITIALIZED = 2;
private static final int MANUAL_STARTING = 3;
private static final int MANUAL_STARTED = 4;
private static final int MANUAL_FAILURE = 5;
private static final int MANUAL_STARTING = 5;
private static final int MANUAL_STARTED = 6;
private static final int MANUAL_FAILURE = 7;
private static volatile int manualState = MANUAL_BEGIN;
private static final Object manualLock = new Object();

Expand Down Expand Up @@ -232,13 +232,9 @@ public static void manualInitialize() {
Class<?> appClass = Class.forName("io.quarkus.runner.ApplicationImpl");
manualApp = (Application) appClass.getDeclaredConstructor().newInstance();
manualState = MANUAL_INITIALIZED;
if (CracRecorder.enabled) {
// NOTE: I tried to do this within a recorder method, but the resource was never registered
// with Crac. Ideally this would be registered within CracRecorder.register()
Core.getGlobalContext()
.register(new CracRecorder.CracResource(CracRecorder.fullWarmup));
if (CracRecorder.enabled && CracRecorder.fullWarmup) {
manualStart();
}
manualState = MANUAL_INITIALIZED;
} catch (Exception e) {
manualState = MANUAL_FAILURE;
throw new RuntimeException("Quarkus manual initialization failed", e);
Expand Down Expand Up @@ -267,18 +263,19 @@ public static void manualStart() {
if (tmpState >= MANUAL_STARTING)
return;
if (tmpState != MANUAL_INITIALIZED)
throw new IllegalStateException("Quarkus manual start cannot proceed as manual initialization did not run");
throw new IllegalStateException("Quarkus manual start cannot proceed as warmup did not run");
manualState = MANUAL_STARTING;
}
try {
String[] args = {};
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
manualApp.stop();
ShutdownRecorder.runShutdown();
manualApp.doStop();
}
});
manualApp.start(args);
manualApp.doStart(args);
} catch (RuntimeException e) {
manualState = MANUAL_FAILURE;
throw e;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -302,10 +302,10 @@ void startPoolLoopDevOrTest(AmazonLambdaRecorder recorder,
}

@BuildStep
@Record(value = ExecutionTime.RUNTIME_INIT)
@Record(value = ExecutionTime.STATIC_INIT)
void recordExpectedExceptions(LambdaBuildTimeConfig config,
BuildProducer<ReflectiveClassBuildItem> registerForReflection,
AmazonLambdaRecorder recorder) {
AmazonLambdaStaticRecorder recorder) {
Set<Class<?>> classes = config.expectedExceptions.map(Set::copyOf).orElseGet(Set::of);
classes.stream().map(clazz -> new ReflectiveClassBuildItem(false, false, false, clazz))
.forEach(registerForReflection::produce);
Expand Down
Loading

0 comments on commit b16b992

Please sign in to comment.