-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
uses a thread per dim store, this is not ideal but generally not a huge risk, maybe we could handle this on the shared IO pool but it's generally not a big deal or likely worth the effort
- Loading branch information
1 parent
610eac1
commit 4e672d5
Showing
2 changed files
with
187 additions
and
109 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||
From: Cryptite <[email protected]> | ||
Date: Tue, 27 Jun 2023 11:35:52 -0500 | ||
Subject: [PATCH] Write SavedData IO async | ||
|
||
|
||
diff --git a/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java b/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java | ||
index 513833c2ea23df5b079d157bc5cb89d5c9754c0b..ef957036de071908964a53c7a157b95e54dfefe3 100644 | ||
--- a/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java | ||
+++ b/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java | ||
@@ -97,6 +97,14 @@ public class ThreadedWorldUpgrader { | ||
} | ||
|
||
this.threadPool.execute(new ConvertTask(info, regionPos.x >> 5, regionPos.z >> 5)); | ||
+ // Paper start | ||
+ this.threadPool.execute(() -> { | ||
+ try { | ||
+ worldPersistentData.close(); | ||
+ } catch (IOException ignored) { | ||
+ } | ||
+ }); | ||
+ // Paper end | ||
} | ||
this.threadPool.shutdown(); | ||
|
||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java | ||
index 44ada45d9bf2d9b48e5de1c3cb1a855902f3884b..a4410cf67280f8a985e6019e6712c617b31fcd1b 100644 | ||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java | ||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java | ||
@@ -467,6 +467,12 @@ public class ServerChunkCache extends ChunkSource { | ||
|
||
public void close(boolean save) { // Paper - rewrite chunk system | ||
this.level.chunkTaskScheduler.chunkHolderManager.close(save, true); // Paper - rewrite chunk system | ||
+ // Paper start | ||
+ try { | ||
+ this.dataStorage.close(); | ||
+ } catch (IOException ignored) { | ||
+ } | ||
+ // Paper end | ||
} | ||
|
||
// CraftBukkit start - modelled on below | ||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java | ||
index 676087c3addd712939c865b39ddb5d9f0bc7ce25..7564b9226fa38a5d94eba3ca5e579e53892d0706 100644 | ||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java | ||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java | ||
@@ -1492,7 +1492,7 @@ public class ServerLevel extends Level implements WorldGenLevel { | ||
|
||
try (co.aikar.timings.Timing ignored = this.timings.worldSave.startTiming()) { | ||
if (doFull) { | ||
- this.saveLevelData(); | ||
+ this.saveLevelData(true); // Paper | ||
} | ||
|
||
this.timings.worldSaveChunks.startTiming(); // Paper | ||
@@ -1528,7 +1528,7 @@ public class ServerLevel extends Level implements WorldGenLevel { | ||
progressListener.progressStartNoAbort(Component.translatable("menu.savingLevel")); | ||
} | ||
|
||
- this.saveLevelData(); | ||
+ this.saveLevelData(!close); // Paper | ||
if (progressListener != null) { | ||
progressListener.progressStage(Component.translatable("menu.savingChunks")); | ||
} | ||
@@ -1551,12 +1551,12 @@ public class ServerLevel extends Level implements WorldGenLevel { | ||
// CraftBukkit end | ||
} | ||
|
||
- private void saveLevelData() { | ||
+ private void saveLevelData(boolean async) { // Paper | ||
if (this.dragonFight != null) { | ||
this.serverLevelData.setEndDragonFightData(this.dragonFight.saveData()); // CraftBukkit | ||
} | ||
|
||
- this.getChunkSource().getDataStorage().save(); | ||
+ this.getChunkSource().getDataStorage().save(async); // Paper | ||
} | ||
|
||
public <T extends Entity> List<? extends T> getEntities(EntityTypeTest<Entity, T> filter, Predicate<? super T> predicate) { | ||
diff --git a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java | ||
index f2a7cb6ebed7a4b4019a09af2a025f624f6fe9c9..cf07f435b5ec720807297e47d5f0d515b711fe41 100644 | ||
--- a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java | ||
+++ b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java | ||
@@ -224,7 +224,12 @@ public class WorldUpgrader { | ||
} | ||
} | ||
|
||
- this.overworldDataStorage.save(); | ||
+ // Paper start | ||
+ try { | ||
+ this.overworldDataStorage.close(); | ||
+ } catch (IOException ignored) { | ||
+ } | ||
+ // Paper end | ||
i = Util.getMillis() - i; | ||
WorldUpgrader.LOGGER.info("World optimizaton finished after {} ms", i); | ||
this.finished = true; | ||
diff --git a/src/main/java/net/minecraft/world/level/saveddata/SavedData.java b/src/main/java/net/minecraft/world/level/saveddata/SavedData.java | ||
index 697df9a9f050c0130246ce2b08a859965bddf184..b3e2954f28986e334089bfff39d92f857bc48a36 100644 | ||
--- a/src/main/java/net/minecraft/world/level/saveddata/SavedData.java | ||
+++ b/src/main/java/net/minecraft/world/level/saveddata/SavedData.java | ||
@@ -29,20 +29,35 @@ public abstract class SavedData { | ||
return this.dirty; | ||
} | ||
|
||
+ @io.papermc.paper.annotation.DoNotUse // Paper - This is dead | ||
public void save(File file) { | ||
+ save(file, null).join(); // Paper - joining is evil, but we assume the old blocking behavior here just for safety | ||
+ } | ||
+ | ||
+ public java.util.concurrent.CompletableFuture<Void> save(File file, @org.jetbrains.annotations.Nullable java.util.concurrent.ExecutorService ioExecutor) { | ||
+ // Paper end | ||
if (this.isDirty()) { | ||
CompoundTag compoundTag = new CompoundTag(); | ||
compoundTag.put("data", this.save(new CompoundTag())); | ||
NbtUtils.addCurrentDataVersion(compoundTag); | ||
|
||
+ // Paper start | ||
+ Runnable writeRunnable = () -> { | ||
try { | ||
NbtIo.writeCompressed(compoundTag, file.toPath()); | ||
} catch (IOException var4) { | ||
LOGGER.error("Could not save data {}", this, var4); | ||
} | ||
+ }; | ||
+ // Paper end | ||
|
||
this.setDirty(false); | ||
+ if (ioExecutor == null) { | ||
+ return java.util.concurrent.CompletableFuture.runAsync(writeRunnable); // Paper - No executor, just use common pool | ||
+ } | ||
+ return java.util.concurrent.CompletableFuture.runAsync(writeRunnable, ioExecutor); // Paper | ||
} | ||
+ return java.util.concurrent.CompletableFuture.completedFuture(null); // Paper | ||
} | ||
|
||
public static record Factory<T extends SavedData>(Supplier<T> constructor, Function<CompoundTag, T> deserializer, DataFixTypes type) { | ||
diff --git a/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java b/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java | ||
index d051e8c1db6b5c42b8df0be54d9d48ba0e7b0077..036063e2ba6eeecb2fabe11830370ab41f179f7c 100644 | ||
--- a/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java | ||
+++ b/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java | ||
@@ -20,15 +20,18 @@ import net.minecraft.util.datafix.DataFixTypes; | ||
import net.minecraft.world.level.saveddata.SavedData; | ||
import org.slf4j.Logger; | ||
|
||
-public class DimensionDataStorage { | ||
+public class DimensionDataStorage implements java.io.Closeable { //Paper | ||
private static final Logger LOGGER = LogUtils.getLogger(); | ||
public final Map<String, SavedData> cache = Maps.newHashMap(); | ||
private final DataFixer fixerUpper; | ||
private final File dataFolder; | ||
+ protected final java.util.concurrent.ExecutorService ioExecutor; // Paper | ||
|
||
public DimensionDataStorage(File directory, DataFixer dataFixer) { | ||
this.fixerUpper = dataFixer; | ||
this.dataFolder = directory; | ||
+ String worldFolder = dataFolder.getParent(); // Paper | ||
+ this.ioExecutor = java.util.concurrent.Executors.newSingleThreadExecutor(new com.google.common.util.concurrent.ThreadFactoryBuilder().setNameFormat("DimensionDataIO - " + worldFolder + " - %d").setDaemon(true).build()); // Paper | ||
} | ||
|
||
private File getDataFile(String id) { | ||
@@ -118,10 +121,23 @@ public class DimensionDataStorage { | ||
return bl; | ||
} | ||
|
||
- public void save() { | ||
+ // Paper start | ||
+ @Override | ||
+ public void close() throws IOException { | ||
+ save(false); | ||
+ this.ioExecutor.shutdown(); | ||
+ } | ||
+ // Paper end | ||
+ | ||
+ public void save(boolean async) { // Paper | ||
this.cache.forEach((id, state) -> { | ||
if (state != null) { | ||
- state.save(this.getDataFile(id)); | ||
+ // Paper start | ||
+ final java.util.concurrent.CompletableFuture<Void> save = state.save(this.getDataFile(id), ioExecutor);// Paper | ||
+ if (!async) { | ||
+ save.join(); | ||
+ } | ||
+ // Paper end | ||
} | ||
|
||
}); |