Skip to content

Commit

Permalink
Add ability to use Virtual Thread for Linear region flusher
Browse files Browse the repository at this point in the history
  • Loading branch information
Dreeam-qwq committed Apr 1, 2024
1 parent d59542c commit c7b3e4e
Show file tree
Hide file tree
Showing 12 changed files with 134 additions and 18 deletions.
48 changes: 33 additions & 15 deletions patches/server/0054-LinearPurpur-Add-Linear-region-format.patch
Original file line number Diff line number Diff line change
Expand Up @@ -704,10 +704,10 @@ index f6338904ca0961cfd67326908e9cf72e37c6e86e..21c15670c0c9b988472ac8e875a1c033
public boolean alwaysTameInCreative = false;
diff --git a/src/main/java/org/purpurmc/purpur/region/AbstractRegionFile.java b/src/main/java/org/purpurmc/purpur/region/AbstractRegionFile.java
new file mode 100644
index 0000000000000000000000000000000000000000..e6ab1ca9a699c3f57855f2acc8d08b8a005bce2f
index 0000000000000000000000000000000000000000..4f903d384959e4353ac1b310b9a70beeb2ce7f6a
--- /dev/null
+++ b/src/main/java/org/purpurmc/purpur/region/AbstractRegionFile.java
@@ -0,0 +1,31 @@
@@ -0,0 +1,43 @@
+package org.purpurmc.purpur.region;
+
+import net.minecraft.nbt.CompoundTag;
Expand All @@ -722,21 +722,33 @@ index 0000000000000000000000000000000000000000..e6ab1ca9a699c3f57855f2acc8d08b8a
+
+public interface AbstractRegionFile {
+ void flush() throws IOException;
+
+ void clear(ChunkPos pos) throws IOException;
+
+ void close() throws IOException;
+
+ void setStatus(int x, int z, ChunkStatus status);
+
+ void setOversized(int x, int z, boolean b) throws IOException;
+
+ boolean hasChunk(ChunkPos pos);
+
+ boolean doesChunkExist(ChunkPos pos) throws Exception;
+
+ boolean isOversized(int x, int z);
+
+ boolean recalculateHeader() throws IOException;
+
+ DataOutputStream getChunkDataOutputStream(ChunkPos pos) throws IOException;
+
+ DataInputStream getChunkDataInputStream(ChunkPos pos) throws IOException;
+
+ CompoundTag getOversizedData(int x, int z) throws IOException;
+
+ ChunkStatus getStatusIfCached(int x, int z);
+
+ ReentrantLock getFileLock();
+
+ Path getRegionFile();
+}
diff --git a/src/main/java/org/purpurmc/purpur/region/AbstractRegionFileFactory.java b/src/main/java/org/purpurmc/purpur/region/AbstractRegionFileFactory.java
Expand Down Expand Up @@ -776,10 +788,10 @@ index 0000000000000000000000000000000000000000..c88ff6fda185a8489cbefa51a7b09ccb
+}
diff --git a/src/main/java/org/purpurmc/purpur/region/LinearRegionFile.java b/src/main/java/org/purpurmc/purpur/region/LinearRegionFile.java
new file mode 100644
index 0000000000000000000000000000000000000000..731a90436cae2e615c228c07f042fa112b95a8d2
index 0000000000000000000000000000000000000000..041f97f32beabc52400f57d056de3d4d313d3e74
--- /dev/null
+++ b/src/main/java/org/purpurmc/purpur/region/LinearRegionFile.java
@@ -0,0 +1,316 @@
@@ -0,0 +1,317 @@
+package org.purpurmc.purpur.region;
+
+import com.github.luben.zstd.ZstdInputStream;
Expand Down Expand Up @@ -1044,7 +1056,7 @@ index 0000000000000000000000000000000000000000..731a90436cae2e615c228c07f042fa11
+
+ @Nullable
+ public synchronized DataInputStream getChunkDataInputStream(ChunkPos pos) {
+ if(this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] != 0) {
+ if (this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] != 0) {
+ byte[] content = new byte[bufferUncompressedSize[getChunkIndex(pos.x, pos.z)]];
+ this.decompressor.decompress(this.buffer[getChunkIndex(pos.x, pos.z)], 0, content, 0, bufferUncompressedSize[getChunkIndex(pos.x, pos.z)]);
+ return new DataInputStream(new ByteArrayInputStream(content));
Expand Down Expand Up @@ -1086,7 +1098,8 @@ index 0000000000000000000000000000000000000000..731a90436cae2e615c228c07f042fa11
+ return false;
+ }
+
+ public void setOversized(int x, int z, boolean something) {}
+ public void setOversized(int x, int z, boolean something) {
+ }
+
+ public CompoundTag getOversizedData(int x, int z) throws IOException {
+ throw new IOException("getOversizedData is a stub " + this.path);
Expand All @@ -1098,30 +1111,35 @@ index 0000000000000000000000000000000000000000..731a90436cae2e615c228c07f042fa11
+}
diff --git a/src/main/java/org/purpurmc/purpur/region/LinearRegionFileFlusher.java b/src/main/java/org/purpurmc/purpur/region/LinearRegionFileFlusher.java
new file mode 100644
index 0000000000000000000000000000000000000000..60f8ed586676609b9be7626eebf865aaaee92ac2
index 0000000000000000000000000000000000000000..0d3d9193e8d8f72141dc155840c5eed1a744761c
--- /dev/null
+++ b/src/main/java/org/purpurmc/purpur/region/LinearRegionFileFlusher.java
@@ -0,0 +1,45 @@
@@ -0,0 +1,50 @@
+package org.purpurmc.purpur.region;
+
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+
+import java.util.Queue;
+import java.util.concurrent.*;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.purpurmc.purpur.PurpurConfig;
+import org.bukkit.Bukkit;
+
+public class LinearRegionFileFlusher {
+ private final Logger LOGGER = LogManager.getLogger(getClass().getName());
+ private final Queue<LinearRegionFile> savingQueue = new LinkedBlockingQueue<>();
+ private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(
+ new ThreadFactoryBuilder()
+ .setNameFormat("linear-flush-scheduler")
+ .build()
+ new ThreadFactoryBuilder()
+ .setNameFormat("linear-flush-scheduler")
+ .build()
+ );
+ private final ExecutorService executor = Executors.newFixedThreadPool(
+ PurpurConfig.linearFlushThreads,
+ new ThreadFactoryBuilder()
+ .setNameFormat("linear-flusher-%d")
+ .build()
+ PurpurConfig.linearFlushThreads,
+ new ThreadFactoryBuilder()
+ .setNameFormat("linear-flusher-%d")
+ .build()
+ );
+
+ public LinearRegionFileFlusher() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: nostalfinals <[email protected]>
Date: Tue, 12 Mar 2024 00:36:29 +0800
Subject: [PATCH] Ability to use Virtual Thread for async scheduler
Subject: [PATCH] Virtual Thread for async scheduler


diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
Expand All @@ -17,13 +17,15 @@ index ee166ad76bd2c143e04e4bf6bd9991bc90ab99a5..13f3f8628143ffc22a2d2c2129ea4836
tryPreloadClass("org.slf4j.helpers.FormattingTuple");
tryPreloadClass("org.slf4j.helpers.BasicMarker");
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java
index 9c1aff17aabd062640e3f451a2ef8c50a7c62f10..3f119f51e1af89f63be00f5a54a9814358f04be6 100644
index 9c1aff17aabd062640e3f451a2ef8c50a7c62f10..ba7784780a578350992be3e2cfcb9791aa805838 100644
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java
@@ -25,30 +25,50 @@ package org.bukkit.craftbukkit.scheduler;
@@ -25,30 +25,55 @@ package org.bukkit.craftbukkit.scheduler;

import com.destroystokyo.paper.ServerSchedulerReportingWrapper;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.galemc.gale.virtualthread.VirtualThreadService;
import org.bukkit.plugin.Plugin;

Expand All @@ -43,6 +45,7 @@ index 9c1aff17aabd062640e3f451a2ef8c50a7c62f10..3f119f51e1af89f63be00f5a54a98143
- private final ThreadPoolExecutor executor = new ThreadPoolExecutor(
- 4, Integer.MAX_VALUE,30L, TimeUnit.SECONDS, new SynchronousQueue<>(),
- new ThreadFactoryBuilder().setNameFormat("Craft Scheduler Thread - %1$d").setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(net.minecraft.server.MinecraftServer.LOGGER)).build()); // Paper
+ private final Logger LOGGER = LogManager.getLogger(getClass().getName()); // Leaf - Class logger
+ private Executor executor; // Leaf - use super class
private final Executor management = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder()
.setNameFormat("Craft Async Scheduler Management Thread").setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(net.minecraft.server.MinecraftServer.LOGGER)).build()); // Paper
Expand All @@ -57,10 +60,12 @@ index 9c1aff17aabd062640e3f451a2ef8c50a7c62f10..3f119f51e1af89f63be00f5a54a98143
+ if (VirtualThreadService.getJavaMajorVersion() >= VirtualThreadService.minimumJavaMajorVersionWithoutFeaturePreview && org.dreeam.leaf.config.modules.opt.VT4BukkitScheduler.enabled) {
+ try {
+ Method newThreadPerTaskExecutor = Executors.class.getMethod("newThreadPerTaskExecutor", ThreadFactory.class);
+
+ executor = (Executor) newThreadPerTaskExecutor.invoke(null, VirtualThreadService.get().createFactory());
+ //executor = Executors.newThreadPerTaskExecutor(Thread.ofVirtual().name("Craft Scheduler Thread - ", 0).factory()); // Leaf - When Minecraft using Java21
+ return;
+ } catch (Exception ignored) {
+ LOGGER.error("Failed to create Virtual Thread executor! Fallback to default executor.");
+ }
+ }
+
Expand Down
93 changes: 93 additions & 0 deletions patches/server/0076-Virtual-Thread-for-linear-flusher.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Radiation_pi <[email protected]>
Date: Mon, 25 Mar 2024 23:00:19 +0800
Subject: [PATCH] Virtual Thread for linear flusher


diff --git a/src/main/java/org/dreeam/leaf/config/modules/opt/VT4LinearFlusher.java b/src/main/java/org/dreeam/leaf/config/modules/opt/VT4LinearFlusher.java
new file mode 100644
index 0000000000000000000000000000000000000000..d4576c9930d12548d4302207f61a0eb8b1fa7b7a
--- /dev/null
+++ b/src/main/java/org/dreeam/leaf/config/modules/opt/VT4LinearFlusher.java
@@ -0,0 +1,29 @@
+package org.dreeam.leaf.config.modules.opt;
+
+import com.electronwill.nightconfig.core.file.CommentedFileConfig;
+import org.dreeam.leaf.config.ConfigInfo;
+import org.dreeam.leaf.config.EnumConfigCategory;
+import org.dreeam.leaf.config.IConfigModule;
+
+public class VT4LinearFlusher implements IConfigModule {
+
+ @Override
+ public EnumConfigCategory getCategory() {
+ return EnumConfigCategory.PERFORMANCE;
+ }
+
+ @Override
+ public String getBaseName() {
+ return "use_virtual_thread_for_linear_flusher";
+ }
+
+ @ConfigInfo(baseName = "enabled")
+ public static boolean enabled = false;
+
+ @Override
+ public void onLoaded(CommentedFileConfig config) {
+ config.setComment("performance.use_virtual_thread_for_linear_flusher", """
+ Use the new Virtual Thread introduced in JDK 21 for Linear Region Flusher.
+ """);
+ }
+}
diff --git a/src/main/java/org/purpurmc/purpur/region/LinearRegionFileFlusher.java b/src/main/java/org/purpurmc/purpur/region/LinearRegionFileFlusher.java
index 0d3d9193e8d8f72141dc155840c5eed1a744761c..339157b5e5a81e3c1c5b54fbd9e3c53ea3f51716 100644
--- a/src/main/java/org/purpurmc/purpur/region/LinearRegionFileFlusher.java
+++ b/src/main/java/org/purpurmc/purpur/region/LinearRegionFileFlusher.java
@@ -4,9 +4,12 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder;

import java.util.Queue;
import java.util.concurrent.*;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.galemc.gale.virtualthread.VirtualThreadService;
import org.purpurmc.purpur.PurpurConfig;
import org.bukkit.Bukkit;

@@ -18,12 +21,28 @@ public class LinearRegionFileFlusher {
.setNameFormat("linear-flush-scheduler")
.build()
);
- private final ExecutorService executor = Executors.newFixedThreadPool(
- PurpurConfig.linearFlushThreads,
- new ThreadFactoryBuilder()
- .setNameFormat("linear-flusher-%d")
- .build()
- );
+
+ private ExecutorService executor;
+
+ {
+ try {
+ if (VirtualThreadService.getJavaMajorVersion() >= VirtualThreadService.minimumJavaMajorVersionWithoutFeaturePreview && org.dreeam.leaf.config.modules.opt.VT4LinearFlusher.enabled) {
+ Method newThreadPerTaskExecutor = Executors.class.getMethod("newThreadPerTaskExecutor", ThreadFactory.class);
+
+ executor = (ExecutorService) newThreadPerTaskExecutor.invoke(null, VirtualThreadService.get().createFactory());
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException |
+ UnsupportedOperationException e) {
+ LOGGER.error("Failed to create Virtual Thread executor! Fallback to default executor.");
+ executor = Executors.newFixedThreadPool(
+ PurpurConfig.linearFlushThreads,
+ new ThreadFactoryBuilder()
+ .setNameFormat("linear-flusher-%d")
+ .build());
+ }
+ }

public LinearRegionFileFlusher() {
Bukkit.getLogger().info("Using " + PurpurConfig.linearFlushThreads + " threads for linear region flushing.");

0 comments on commit c7b3e4e

Please sign in to comment.