Skip to content

Bootstrap refactoring#114

Merged
franz1981 merged 5 commits into
masterfrom
bootstrap-refactoring
May 28, 2026
Merged

Bootstrap refactoring#114
franz1981 merged 5 commits into
masterfrom
bootstrap-refactoring

Conversation

@franz1981
Copy link
Copy Markdown
Owner

@franz1981 franz1981 commented May 27, 2026

Move scheduling core to bootstrap module

Moves all Netty-independent scheduling classes (EventLoopScheduler, EventLoopSchedulerGroup, JFR events) from core to bootstrap under io.netty.loom.scheduler. Eliminates the SPI — NettyScheduler directly routes onStart/onContinue to carriers. Carrier pool is created eagerly at JVM startup.

Why: EventLoopSchedulerGroup.<clinit> is per-classloader. In app servers (JBoss, Liberty) or Spring Boot fat JARs with multiple classloaders, each gets its own carrier group. Additionally, instanceof SchedulingContext returns false across classloaders (different Class objects), causing VTs to silently fall back to ForkJoinPool — no error, just lost carrier affinity. Moving to bootstrap (system classloader) guarantees one carrier pool and one SchedulingContext class identity per JVM.

Trade-off: bootstrap now depends on jctools (MpscUnboundedArrayQueue). On master, jctools stays in core (app classloader) — no version conflict risk. With this change, jctools must be on the system classpath alongside bootstrap, which could conflict if the application uses a different jctools version. The proper fix is shading jctools into the bootstrap JAR, but maven-shade-plugin does not yet support Java 27 class files (ASM stops at major version 70). Once ASM catches up, jctools should be shaded to eliminate this risk.

JVM flag changed: -Djdk.virtualThreadScheduler.implClass=io.netty.loom.scheduler.NettyScheduler

@franz1981 franz1981 force-pushed the bootstrap-refactoring branch from c58d252 to 7ef1b57 Compare May 27, 2026 20:55
@dreamlike-ocean
Copy link
Copy Markdown
Contributor

jvm_args="$jvm_args -Djdk.virtualThreadScheduler.implClass=io.netty.loom.spi.NettyScheduler"

this script still uses the old io.netty.loom.spi.NettyScheduler class, so it should be updated to io.netty.loom.scheduler.NettyScheduler.

@franz1981
Copy link
Copy Markdown
Owner Author

So @dreamlike-ocean this change, despite good seems now blocked by maven-shade-plugin: I have updated the PR description to explain the risk of the current SPI based approach 😢

@dreamlike-ocean
Copy link
Copy Markdown
Contributor

So @dreamlike-ocean this change, despite good seems now blocked by maven-shade-plugin: I have updated the PR description to explain the risk of the current SPI based approach 😢

try this dreamlike-ocean@ae69a9b

the asm website shows

May 2026: ASM 9.10 (tag ASM_9_10)
new Opcodes.V27 constant for Java 27
bug fixes
318041: Compilation failure with JDK 5
318043: TraceSignatureVisitor bug
 

@franz1981
Copy link
Copy Markdown
Owner Author

@dreamlike-ocean thanks for checking!
I'm now removing the Spring MVC example; everyone can do their own following the README I think.
And I am going to shade JCTools to simplify everything.
Having a single real custom scheduler without duplicated carriers is THE thing to do I believe ^^

franz1981 added 3 commits May 28, 2026 15:03
Move all Netty-independent scheduling classes from core to bootstrap
under io.netty.loom.scheduler package. Eliminates the per-classloader
singleton problem in app servers (JBoss/Liberty) where multiple
classloaders would create duplicate carrier groups.

What moved to bootstrap:
- NettyScheduler (entry point, was in io.netty.loom.spi)
- EventLoopScheduler (carrier loop, run queue, work stealing)
- EventLoopSchedulerGroup (carrier pool)
- SchedulerJfrUtil + 4 JFR events
- jctools as a regular dependency (shade blocked by ASM/Java 27)

What changed:
- SPI eliminated: NettyScheduler directly routes onStart/onContinue
- Eager carrier pool creation in NettyScheduler constructor
- NettyScheduler reference passed explicitly (no partial publication)
- Tests moved to io.netty.loom.scheduler package for visibility
- SchedulerJfrUtil split: scheduler events in bootstrap, Netty I/O
  events (NettyJfrUtil) stay in core

JVM flag changed:
  -Djdk.virtualThreadScheduler.implClass=io.netty.loom.scheduler.NettyScheduler
NettyRunTasksEvent and the runNonBlockingTasks wrapper methods in both
event loop groups are dead code since the poller loop simplification.
Remove the event class, JFR util methods, JFC config entry, timeline
script reference, and benchmark README entry.
Raw Netty HTTP server with epoll pinned pollers demonstrating blocking
VT handlers, structured concurrency with carrier affinity, and carrier
info in responses. No Spring Boot, no external dependencies.

Endpoints:
  GET /         - blocking handler (50ms), returns VT + carrier info
  GET /parallel - StructuredTaskScope fork/join on same carrier
@franz1981 franz1981 force-pushed the bootstrap-refactoring branch from 7ef1b57 to 3679a1d Compare May 28, 2026 15:08
Replace direct field access on SchedulingContext with named methods:
  - home() instead of .eventLoopScheduler
  - type() instead of .type
  - mountedOn(carrier) instead of .runningScheduler = carrier
  - setVThreadId(id) instead of .vThreadId = id

Fields stay package-private (the class itself is package-private).
The accessors add readability, not encapsulation.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors the project so the Netty-independent scheduling core (custom NettyScheduler, EventLoopScheduler*, scheduler JFR events) lives in the bootstrap module under io.netty.loom.scheduler, eliminating the previous ServiceLoader SPI and updating docs/examples/benchmarks to the new scheduler flag and package layout.

Changes:

  • Move scheduler core + scheduler JFR events into netty-virtualthread-bootstrap and remove the SPI provider/discovery mechanism.
  • Update Netty integration layer to depend on io.netty.loom.scheduler.* directly and simplify availability checks.
  • Refresh docs, example-echo, and benchmark runner scripts/configs to the new scheduler class name and removed JFR events.

Reviewed changes

Copilot reviewed 35 out of 35 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
README.md Updates scheduler flag, module roles, and deployment/classloader guidance for bootstrap-first scheduler.
pom.xml Updates surefire JVM argLines to point at io.netty.loom.scheduler.NettyScheduler.
example-echo/src/main/java/io/netty/loom/example/EchoServer.java Reworks example into an epoll-based HTTP server demonstrating carrier affinity + structured concurrency.
example-echo/README.md Updates example documentation and run instructions for the new scheduler/epoll setup.
example-echo/pom.xml Switches example dependencies/plugins away from Spring Boot and adds epoll native transport dependency.
core/src/test/java/io/netty/loom/scheduler/VirtualIoNativePollerEventLoopGroupTest.java Adjusts test package and updates API usage to new scheduler helpers.
core/src/test/java/io/netty/loom/scheduler/NettySchedulerClassInitTest.java Adjusts test package for bootstrap scheduler init/availability.
core/src/test/java/io/netty/loom/ClassLoaderIsolationTest.java Removes SPI-era classloader isolation test (no longer applicable).
core/src/main/resources/META-INF/services/io.netty.loom.spi.NettySchedulerSpi Removes ServiceLoader registration (SPI removed).
core/src/main/java/io/netty/loom/VirtualIoNioPollerEventLoopGroup.java Switches to bootstrap scheduler APIs; removes SPI-based availability checks; updates JFR util usage.
core/src/main/java/io/netty/loom/VirtualIoNativePollerEventLoopGroup.java Switches to bootstrap scheduler APIs; removes SPI-based availability checks; updates JFR util usage.
core/src/main/java/io/netty/loom/VirtualIoEventLoopGroup.java Imports bootstrap EventLoopSchedulerGroup for default carrier selection.
core/src/main/java/io/netty/loom/NettySchedulerProviderImpl.java Removes SPI provider implementation (logic now in bootstrap scheduler).
core/src/main/java/io/netty/loom/NettyJfrUtil.java Replaces old Spring Boot entrypoint content with Netty JFR utility for run-I/O events.
core/src/main/java/io/netty/loom/jfr/NettyRunTasksEvent.java Removes the Netty “Run Tasks” JFR event class.
core/pom.xml Removes jctools-core dependency from core (moved to bootstrap).
bootstrap/src/main/java/io/netty/loom/spi/NettySchedulerSpi.java Removes SPI interface.
bootstrap/src/main/java/io/netty/loom/spi/NettyScheduler.java Removes SPI-based bootstrap shim scheduler.
bootstrap/src/main/java/io/netty/loom/scheduler/SchedulerJfrUtil.java Moves scheduler JFR util into bootstrap scheduler package and removes Netty task/run-I/O event helpers.
bootstrap/src/main/java/io/netty/loom/scheduler/NettyScheduler.java Adds new bootstrap scheduler implementation that eagerly creates the carrier pool and routes tasks directly.
bootstrap/src/main/java/io/netty/loom/scheduler/jfr/WorkStealEvent.java Moves scheduler JFR event package to io.netty.loom.scheduler.jfr.
bootstrap/src/main/java/io/netty/loom/scheduler/jfr/VirtualThreadTaskSubmitEvent.java Moves scheduler JFR event package to io.netty.loom.scheduler.jfr.
bootstrap/src/main/java/io/netty/loom/scheduler/jfr/VirtualThreadTaskRunsEvent.java Moves scheduler JFR event package to io.netty.loom.scheduler.jfr.
bootstrap/src/main/java/io/netty/loom/scheduler/jfr/VirtualThreadTaskRunEvent.java Moves scheduler JFR event package to io.netty.loom.scheduler.jfr.
bootstrap/src/main/java/io/netty/loom/scheduler/EventLoopSchedulerGroup.java Reworks singleton creation to come from NettyScheduler (bootstrap global), not SPI init.
bootstrap/src/main/java/io/netty/loom/scheduler/EventLoopScheduler.java Moves scheduler core into bootstrap package; adjusts internals for new scheduler wiring and API exposure.
bootstrap/pom.xml Adds jctools + shade configuration to embed/relocate it into the bootstrap artifact; adjusts surefire executions.
benchmarks/src/main/java/io/netty/loom/benchmark/SchedulerHandoffBenchmark.java Updates benchmark JVM args to new scheduler implClass.
benchmarks/src/main/java/io/netty/loom/benchmark/NettySchedulerBenchmark.java Updates benchmark JVM args to new scheduler implClass.
benchmark-runner/src/main/java/io/netty/loom/benchmark/runner/HandoffHttpServer.java Updates imports to bootstrap EventLoopSchedulerGroup.
benchmark-runner/scripts/run-benchmark.sh Removes NettyRunTasks event references and updates scheduler implClass flag.
benchmark-runner/scripts/jfr/netty-loom.jfc Removes NettyRunTasks event configuration.
benchmark-runner/scripts/jfr/JfrToTimeline.java Removes NettyRunTasks from parsed event list.
benchmark-runner/README.md Updates supported event list and scheduler implClass example.
BACKLOG.md Removes backlog document from repo.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +145 to +151
if (HttpUtil.isKeepAlive(request)) {
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
}
ctx.writeAndFlush(response);
if (!HttpUtil.isKeepAlive(request)) {
ctx.close();
}
Comment thread bootstrap/pom.xml
<shadedPattern>io.netty.loom.scheduler</shadedPattern>
</relocation>
</relocations>
<createDependencyReducedPom>false</createDependencyReducedPom>
Comment thread bootstrap/pom.xml
Comment on lines +35 to +78
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.2</version>
<dependencies>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>9.10.1</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-commons</artifactId>
<version>9.10.1</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-tree</artifactId>
<version>9.10.1</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<includes>
<include>org.jctools:jctools-core</include>
</includes>
</artifactSet>
<relocations>
<relocation>
<pattern>org.jctools</pattern>
<shadedPattern>io.netty.loom.scheduler</shadedPattern>
</relocation>
</relocations>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
</execution>
</executions>
</plugin>
@franz1981 franz1981 merged commit 5ff0281 into master May 28, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants