Files
MiraiMC/patches/server/0024-Sugarcane-New-NBT-cache.patch
2021-09-19 15:59:30 +02:00

142 lines
7.0 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Etil <81570777+etil2jz@users.noreply.github.com>
Date: Sun, 19 Sep 2021 14:56:18 +0200
Subject: [PATCH] (Sugarcane) New NBT cache
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index d30d7a025cb88da120b3c6b7cb57a4f4d0afe043..883de715e3a5a1c9335854b7d0d0cfd998f7866f 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1097,7 +1097,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<Runnab
}
// Spigot start
MCUtil.asyncExecutor.shutdown(); // Paper
+ this.playerDataStorage.executorService.shutdown(); // Sugarcane
try { MCUtil.asyncExecutor.awaitTermination(30, java.util.concurrent.TimeUnit.SECONDS); // Paper
+ this.playerDataStorage.executorService.awaitTermination(30, java.util.concurrent.TimeUnit.SECONDS); // Sugarcane - New async nbt cache
} catch (java.lang.InterruptedException ignored) {} // Paper
if (org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) {
MinecraftServer.LOGGER.info("Saving usercache.json");
diff --git a/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java b/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java
index 8ce6d386a67687207966a9c577cff9046f45193e..ce80d1d424c195144215cf7bcd7792a889c9d5f8 100644
--- a/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java
+++ b/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java
@@ -24,6 +24,10 @@ public class PlayerDataStorage {
private static final Logger LOGGER = LogManager.getLogger();
private final File playerDir;
protected final DataFixer fixerUpper;
+ // Sugarcane start - NBT Cache system
+ private final xyz.arthurb.mirai.server.util.NBTCache dataCache = new xyz.arthurb.mirai.server.util.NBTCache();
+ public final java.util.concurrent.ExecutorService executorService = java.util.concurrent.Executors.newSingleThreadExecutor(new com.google.common.util.concurrent.ThreadFactoryBuilder().setDaemon(true).setPriority(Thread.NORM_PRIORITY - 1).build());
+ // Sugarcane end
public PlayerDataStorage(LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer) {
this.fixerUpper = dataFixer;
@@ -37,11 +41,24 @@ public class PlayerDataStorage {
CompoundTag nbttagcompound = player.saveWithoutId(new CompoundTag());
File file = File.createTempFile(player.getStringUUID() + "-", ".dat", this.playerDir);
- NbtIo.writeCompressed(nbttagcompound, file);
- File file1 = new File(this.playerDir, player.getStringUUID() + ".dat");
- File file2 = new File(this.playerDir, player.getStringUUID() + ".dat_old");
-
- Util.safeReplaceFile(file1, file, file2);
+ // NbtIo.writeCompressed(nbttagcompound, file); // Sugarcane
+ // Sugarcane start - NBT Cache system
+ Runnable task = () -> {
+ try {
+ NbtIo.writeCompressed(nbttagcompound, file);
+ File file1 = new File(this.playerDir, player.getStringUUID() + ".dat");
+ File file2 = new File(this.playerDir, player.getStringUUID() + ".dat_old");
+
+ Util.safeReplaceFile(file1, file, file2);
+ } catch (Exception exception) {
+ PlayerDataStorage.LOGGER.error("Failed to save player data for {}", player.getScoreboardName(), exception); // Paper
+ }
+ };
+ synchronized (this.dataCache){
+ this.dataCache.put(file, nbttagcompound);
+ }
+ this.executorService.execute(task);
+ // Sugarcane end
} catch (Exception exception) {
PlayerDataStorage.LOGGER.warn("Failed to save player data for {}", player.getScoreboardName(), exception); // Paper
}
@@ -57,9 +74,18 @@ public class PlayerDataStorage {
// Spigot Start
boolean usingWrongFile = false;
boolean normalFile = file.exists() && file.isFile(); // Akarin - ensures normal file
- if ( org.bukkit.Bukkit.getOnlineMode() && !normalFile ) // Paper - Check online mode first // Akarin - ensures normal file
+ // if ( org.bukkit.Bukkit.getOnlineMode() && !file.exists() ) // Paper - Check online mode first
+ // Sugarcane start - NBT Cache system
+ CompoundTag playerData;
+ synchronized (this.dataCache){
+ playerData = this.dataCache.get(file);
+ }
+ if (playerData == null && org.bukkit.Bukkit.getOnlineMode() && !normalFile ) // Paper - Check online mode first // Akarin - ensures normal file // Sugarcane
{
file = new File( this.playerDir, java.util.UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + player.getScoreboardName() ).getBytes( "UTF-8" ) ).toString() + ".dat");
+ synchronized (this.dataCache){
+ playerData = this.dataCache.get(file);
+ }
if ( file.exists() )
{
usingWrongFile = true;
@@ -68,9 +94,15 @@ public class PlayerDataStorage {
}
// Spigot End
- if (normalFile) { // Akarin - avoid double I/O operation
+ //if (normalFile) { // Akarin - avoid double I/O operation
+ if (playerData != null) {
+ nbttagcompound = playerData;
+ } else if (normalFile) { // Akarin - avoid double I/O operation
+
+ // if (file.exists() && file.isFile()) {
nbttagcompound = NbtIo.readCompressed(file);
}
+ // Sugarcane end
// Spigot Start
if ( usingWrongFile )
{
diff --git a/src/main/java/xyz/arthurb/mirai/server/util/NBTCache.java b/src/main/java/xyz/arthurb/mirai/server/util/NBTCache.java
new file mode 100644
index 0000000000000000000000000000000000000000..b907dbb3da6370724cf67653c5c947a4326bd98b
--- /dev/null
+++ b/src/main/java/xyz/arthurb/mirai/server/util/NBTCache.java
@@ -0,0 +1,32 @@
+package xyz.arthurb.mirai.server.util;
+
+import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenCustomHashMap;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.nbt.CompoundTag;
+
+import java.io.File;
+
+public class NBTCache extends Object2ObjectLinkedOpenCustomHashMap<File, CompoundTag> {
+
+ public NBTCache() {
+ super(100, 0.75F, new Strategy<File>() {
+ @Override
+ public int hashCode(File k) {
+ return k.hashCode();
+ }
+
+ @Override
+ public boolean equals(File k, File k1) {
+ return k.equals(k1);
+ }
+ });
+ }
+
+ @Override
+ public CompoundTag put(File k, CompoundTag v) {
+ if (this.size() > MinecraftServer.getServer().getPlayerCount()) {
+ this.removeLast();
+ }
+ return super.putAndMoveToFirst(k, v);
+ }
+}
\ No newline at end of file