diff --git a/src/main/java/org/ultramine/server/data/NBTFileDataProvider.java b/src/main/java/org/ultramine/server/data/NBTFileDataProvider.java index 08b6e6d..6c228ed 100644 --- a/src/main/java/org/ultramine/server/data/NBTFileDataProvider.java +++ b/src/main/java/org/ultramine/server/data/NBTFileDataProvider.java @@ -2,13 +2,14 @@ import java.io.File; import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ThreadLocalRandom; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -33,6 +34,8 @@ private final ServerConfigurationManager mgr; private File umPlayerDir; private List fastWarps = Collections.emptyList(); + private final Map savingPlayersCache = new ConcurrentHashMap<>(); + private long cachedPlayerCounter; public NBTFileDataProvider(ServerConfigurationManager mgr) { @@ -168,8 +171,11 @@ public NBTTagCompound loadPlayer(SaveHandler sh, GameProfile player) { - File dir = sh.getPlayerSaveDir(); - File file = new File(dir, player.getId().toString() + ".dat"); + File file = getPlayerNbtFile(sh, player); + CachedPlayerStruct data = savingPlayersCache.get(file); + if(data != null) + return data.nbt; + if(file.exists()) { try @@ -187,7 +193,17 @@ public void savePlayer(SaveHandler sh, GameProfile player, NBTTagCompound nbt) { - AsyncIOUtils.safeWriteNBT(new File(sh.getPlayerSaveDir(), player.getId().toString() + ".dat"), nbt); + File file = getPlayerNbtFile(sh, player); + long nextId = cachedPlayerCounter++; + savingPlayersCache.put(file, new CachedPlayerStruct(nbt, nextId)); + AsyncIOUtils.safeWriteNBT(file, nbt, () -> + savingPlayersCache.computeIfPresent(file, (file1, data) -> data.id == nextId ? null : data) + ); + } + + private static File getPlayerNbtFile(SaveHandler sh, GameProfile player) + { + return new File(sh.getPlayerSaveDir(), player.getId().toString() + ".dat"); } private NBTTagCompound getPlayerDataNBT(String username) @@ -227,23 +243,6 @@ return pdata; } - private void safeWriteNBT(File file, NBTTagCompound nbt) - { - try - { - File file1 = new File(file.getParentFile(), file.getName()+".tmp"); - CompressedStreamTools.writeCompressed(nbt, new FileOutputStream(file1)); - - if (file.exists()) - file.delete(); - file1.renameTo(file); - } - catch(IOException e) - { - log.warn("Failed to write file: "+file.getAbsolutePath(), e); - } - } - private void writeWarpList() { File file = mgr.getServerInstance().getStorageFile("warps.yml"); @@ -258,4 +257,16 @@ public Map warps; public List fastWarps; } + + private static class CachedPlayerStruct + { + public NBTTagCompound nbt; + public long id; + + public CachedPlayerStruct(NBTTagCompound nbt, long id) + { + this.nbt = nbt; + this.id = id; + } + } } diff --git a/src/main/java/org/ultramine/server/util/AsyncIOUtils.java b/src/main/java/org/ultramine/server/util/AsyncIOUtils.java index e6c8ee9..7344d5f 100644 --- a/src/main/java/org/ultramine/server/util/AsyncIOUtils.java +++ b/src/main/java/org/ultramine/server/util/AsyncIOUtils.java @@ -27,9 +27,9 @@ { FileUtils.writeStringToFile(file, data, Charsets.UTF_8); } - catch(IOException e) + catch(Exception e) { - log.warn("Failed to write file: "+file.getAbsolutePath(), e); + log.error("Failed to write file: "+file.getAbsolutePath(), e); } } }); @@ -46,16 +46,21 @@ { FileUtils.writeByteArrayToFile(file, data); } - catch(IOException e) + catch(Exception e) { - log.warn("Failed to write file: "+file.getAbsolutePath(), e); + log.error("Failed to write file: "+file.getAbsolutePath(), e); } } }); } - + public static void safeWriteNBT(final File file, final NBTTagCompound nbt) { + safeWriteNBT(file, nbt, null); + } + + public static void safeWriteNBT(final File file, final NBTTagCompound nbt, Runnable callback) + { GlobalExecutors.writingIO().execute(new Runnable() { @Override @@ -67,12 +72,14 @@ CompressedStreamTools.writeCompressed(nbt, new FileOutputStream(file1)); if (file.exists()) - file.delete(); - file1.renameTo(file); + FileUtils.forceDelete(file); + FileUtils.moveFile(file1, file); + if(callback != null) + callback.run(); } - catch(IOException e) + catch(Exception e) { - log.warn("Failed to write file: "+file.getAbsolutePath(), e); + log.error("Failed to write file: "+file.getAbsolutePath(), e); } } });