From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Hugo Planque Date: Thu, 21 Jan 2021 17:56:03 +0100 Subject: [PATCH] New nbt cache The goal of this patch is to reduce I/O operations from the main thread while saving player data and also to avoid too many I/O operations while reading NBT Player file by using a cache (Which start to delete the oldest data when there is too much player compared to the map size) diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index 2a06f663ce64529842cfb0f4cf16c28ee143f110..084f7435ce50a10cd22e967f695064fb00c9b165 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -824,7 +824,9 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant dataCache = new org.yatopiamc.yatopia.server.cache.NBTCache<>(); // Yatopia - NBT Cache system + public final java.util.concurrent.ExecutorService executorService = java.util.concurrent.Executors.newSingleThreadExecutor(); // Yatopia - NBT Cache system public WorldNBTStorage(Convertable.ConversionSession convertable_conversionsession, DataFixer datafixer) { this.a = datafixer; @@ -30,11 +32,22 @@ public class WorldNBTStorage { NBTTagCompound nbttagcompound = entityhuman.save(new NBTTagCompound()); File file = File.createTempFile(entityhuman.getUniqueIDString() + "-", ".dat", this.playerDir); - NBTCompressedStreamTools.a(nbttagcompound, file); + // NBTCompressedStreamTools.a(nbttagcompound, file); // Yatopia + // Yatopia start - NBT Cache system + Runnable task = () -> { try { NBTCompressedStreamTools.a(nbttagcompound, file); File file1 = new File(this.playerDir, entityhuman.getUniqueIDString() + ".dat"); File file2 = new File(this.playerDir, entityhuman.getUniqueIDString() + ".dat_old"); SystemUtils.a(file1, file, file2); + } catch (Exception exception) { + WorldNBTStorage.LOGGER.error("Failed to save player data for {}", entityhuman.getName(), exception); // Paper + } + }; + synchronized (this.dataCache){ + this.dataCache.put(file, nbttagcompound); + } + this.executorService.execute(task); + // Yatopia end } catch (Exception exception) { WorldNBTStorage.LOGGER.error("Failed to save player data for {}", entityhuman.getName(), exception); // Paper } @@ -50,9 +63,18 @@ public class WorldNBTStorage { // 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() && !normalFile ) // Paper - Check online mode first // Akarin - ensures normal file // Yatopia + // Yatopia start - NBT Cache system + NBTTagCompound 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 { file = new File( this.playerDir, java.util.UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + entityhuman.getName() ).getBytes( "UTF-8" ) ).toString() + ".dat"); + synchronized (this.dataCache){ + playerData = this.dataCache.get(file); + } if ( file.exists() ) { usingWrongFile = true; @@ -60,10 +82,13 @@ public class WorldNBTStorage { } } // Spigot End - - if (normalFile) { // Akarin - avoid double I/O operation + // if (normalFile) { // Akarin - avoid double I/O operation // Yatopia + if (playerData != null) { + nbttagcompound = playerData; + } else if (normalFile) { // Akarin - avoid double I/O operation nbttagcompound = NBTCompressedStreamTools.a(file); } + // Yatopia end // Spigot Start if ( usingWrongFile ) { diff --git a/src/main/java/org/yatopiamc/yatopia/server/cache/NBTCache.java b/src/main/java/org/yatopiamc/yatopia/server/cache/NBTCache.java new file mode 100644 index 0000000000000000000000000000000000000000..adc5975ded5f655a7b5da59daa1ff3b63697f841 --- /dev/null +++ b/src/main/java/org/yatopiamc/yatopia/server/cache/NBTCache.java @@ -0,0 +1,29 @@ +package org.yatopiamc.yatopia.server.cache; + +import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenCustomHashMap; +import net.minecraft.server.MinecraftServer; + +public class NBTCache extends Object2ObjectLinkedOpenCustomHashMap { + + public NBTCache() { + super(100, 0.75F, new Strategy() { + @Override + public int hashCode(K k) { + return k.hashCode(); + } + + @Override + public boolean equals(K k, K k1) { + return k.equals(k1); + } + }); + } + + @Override + public V put(K k, V v) { + if (this.size() > MinecraftServer.getServer().getPlayerCount()) { + this.removeLast(); + } + return super.putAndMoveToFirst(k, v); + } +}