From 2452a2f6338f30af9be46bb847b7de02c315a08d Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Tue, 27 May 2025 16:23:02 +0200 Subject: [PATCH] cleanup of the mantle trimmer / EngineSVC --- .../com/volmit/iris/core/IrisSettings.java | 9 + .../iris/core/commands/CommandDeveloper.java | 50 +-- .../iris/core/service/IrisEngineSVC.java | 382 +++++++----------- .../iris/engine/mantle/EngineMantle.java | 12 +- .../engine/platform/BukkitChunkGenerator.java | 24 +- .../com/volmit/iris/util/mantle/Mantle.java | 150 ++++--- 6 files changed, 244 insertions(+), 383 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/core/IrisSettings.java b/core/src/main/java/com/volmit/iris/core/IrisSettings.java index 1a86aad11..655967aad 100644 --- a/core/src/main/java/com/volmit/iris/core/IrisSettings.java +++ b/core/src/main/java/com/volmit/iris/core/IrisSettings.java @@ -23,6 +23,7 @@ import com.volmit.iris.Iris; import com.volmit.iris.util.io.IO; import com.volmit.iris.util.json.JSONException; import com.volmit.iris.util.json.JSONObject; +import com.volmit.iris.util.misc.getHardware; import com.volmit.iris.util.plugin.VolmitSender; import lombok.AllArgsConstructor; import lombok.Data; @@ -160,6 +161,14 @@ public class IrisSettings { public int resourceLoaderCacheSize = 1_024; public int objectLoaderCacheSize = 4_096; public int scriptLoaderCacheSize = 512; + public int tectonicPlateSize = -1; + + public int getTectonicPlateSize() { + if (tectonicPlateSize > 0) + return tectonicPlateSize; + + return (int) (getHardware.getProcessMemory() / 200L); + } } @Data diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java b/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java index d54a97e5b..5d6090b00 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java @@ -20,7 +20,6 @@ package com.volmit.iris.core.commands; import com.volmit.iris.Iris; import com.volmit.iris.core.ServerConfigurator; -import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.nms.datapack.DataVersion; import com.volmit.iris.core.service.IrisEngineSVC; import com.volmit.iris.core.tools.IrisPackBenchmarking; @@ -68,53 +67,8 @@ public class CommandDeveloper implements DecreeExecutor { @Decree(description = "Get Loaded TectonicPlates Count", origin = DecreeOrigin.BOTH, sync = true) public void EngineStatus() { - List IrisWorlds = new ArrayList<>(); - int TotalLoadedChunks = 0; - int TotalQueuedTectonicPlates = 0; - int TotalNotQueuedTectonicPlates = 0; - int TotalTectonicPlates = 0; - - long lowestUnloadDuration = 0; - long highestUnloadDuration = 0; - - for (World world : Bukkit.getWorlds()) { - try { - if (IrisToolbelt.access(world).getEngine() != null) { - IrisWorlds.add(world); - } - } catch (Exception e) { - // no - } - } - - for (World world : IrisWorlds) { - Engine engine = IrisToolbelt.access(world).getEngine(); - TotalQueuedTectonicPlates += (int) engine.getMantle().getToUnload(); - TotalNotQueuedTectonicPlates += (int) engine.getMantle().getNotQueuedLoadedRegions(); - TotalTectonicPlates += engine.getMantle().getLoadedRegionCount(); - if (highestUnloadDuration <= (long) engine.getMantle().getTectonicDuration()) { - highestUnloadDuration = (long) engine.getMantle().getTectonicDuration(); - } - if (lowestUnloadDuration >= (long) engine.getMantle().getTectonicDuration()) { - lowestUnloadDuration = (long) engine.getMantle().getTectonicDuration(); - } - for (Chunk chunk : world.getLoadedChunks()) { - if (chunk.isLoaded()) { - TotalLoadedChunks++; - } - } - } - Iris.info("-------------------------"); - Iris.info(C.DARK_PURPLE + "Engine Status"); - Iris.info(C.DARK_PURPLE + "Total Loaded Chunks: " + C.LIGHT_PURPLE + TotalLoadedChunks); - Iris.info(C.DARK_PURPLE + "Tectonic Limit: " + C.LIGHT_PURPLE + IrisEngineSVC.getTectonicLimit()); - Iris.info(C.DARK_PURPLE + "Tectonic Total Plates: " + C.LIGHT_PURPLE + TotalTectonicPlates); - Iris.info(C.DARK_PURPLE + "Tectonic Active Plates: " + C.LIGHT_PURPLE + TotalNotQueuedTectonicPlates); - Iris.info(C.DARK_PURPLE + "Tectonic ToUnload: " + C.LIGHT_PURPLE + TotalQueuedTectonicPlates); - Iris.info(C.DARK_PURPLE + "Lowest Tectonic Unload Duration: " + C.LIGHT_PURPLE + Form.duration(lowestUnloadDuration)); - Iris.info(C.DARK_PURPLE + "Highest Tectonic Unload Duration: " + C.LIGHT_PURPLE + Form.duration(highestUnloadDuration)); - Iris.info(C.DARK_PURPLE + "Cache Size: " + C.LIGHT_PURPLE + Form.f(IrisData.cacheSize())); - Iris.info("-------------------------"); + Iris.service(IrisEngineSVC.class) + .engineStatus(sender()); } @Decree(description = "Test") diff --git a/core/src/main/java/com/volmit/iris/core/service/IrisEngineSVC.java b/core/src/main/java/com/volmit/iris/core/service/IrisEngineSVC.java index 2220ccc26..e6c2e364f 100644 --- a/core/src/main/java/com/volmit/iris/core/service/IrisEngineSVC.java +++ b/core/src/main/java/com/volmit/iris/core/service/IrisEngineSVC.java @@ -1,317 +1,245 @@ package com.volmit.iris.core.service; +import com.google.common.util.concurrent.AtomicDouble; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; +import com.volmit.iris.core.loader.IrisData; +import com.volmit.iris.core.nms.container.Pair; import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.platform.PlatformChunkGenerator; -import com.volmit.iris.util.collection.KList; -import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.Form; -import com.volmit.iris.util.mantle.TectonicPlate; -import com.volmit.iris.util.misc.getHardware; import com.volmit.iris.util.plugin.IrisService; -import com.volmit.iris.util.scheduling.ChronoLatch; +import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.scheduling.Looper; -import com.volmit.iris.util.scheduling.PrecisionStopwatch; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.event.EventHandler; -import org.bukkit.event.server.PluginDisableEvent; -import org.bukkit.event.server.ServerLoadEvent; import org.bukkit.event.world.WorldLoadEvent; import org.bukkit.event.world.WorldUnloadEvent; -import org.checkerframework.checker.units.qual.A; -import java.util.*; -import java.util.concurrent.atomic.AtomicBoolean; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.locks.ReentrantLock; import java.util.function.Supplier; public class IrisEngineSVC implements IrisService { - public static IrisEngineSVC instance; - public boolean isServerShuttingDown = false; - public boolean isServerLoaded = false; - private static final AtomicInteger tectonicLimit = new AtomicInteger(30); - private ReentrantLock lastUseLock; - private KMap lastUse; - private List IrisWorlds; - private Looper cacheTicker; + private final AtomicInteger tectonicLimit = new AtomicInteger(30); + private final AtomicInteger tectonicPlates = new AtomicInteger(); + private final AtomicInteger queuedTectonicPlates = new AtomicInteger(); + private final AtomicDouble maxIdleDuration = new AtomicDouble(); + private final AtomicDouble minIdleDuration = new AtomicDouble(); + private final AtomicLong loadedChunks = new AtomicLong(); + private final List> worlds = new CopyOnWriteArrayList<>(); private Looper trimTicker; private Looper unloadTicker; private Looper updateTicker; - private PrecisionStopwatch trimAlive; - private PrecisionStopwatch unloadAlive; - public PrecisionStopwatch trimActiveAlive; - public PrecisionStopwatch unloadActiveAlive; - private AtomicInteger TotalTectonicPlates; - private AtomicInteger TotalQueuedTectonicPlates; - private AtomicInteger TotalNotQueuedTectonicPlates; - private AtomicBoolean IsUnloadAlive; - private AtomicBoolean IsTrimAlive; - ChronoLatch cl; - - public List corruptedIrisWorlds = new ArrayList<>(); @Override public void onEnable() { - this.cl = new ChronoLatch(5000); - lastUse = new KMap<>(); - lastUseLock = new ReentrantLock(); - IrisWorlds = new ArrayList<>(); - IsUnloadAlive = new AtomicBoolean(true); - IsTrimAlive = new AtomicBoolean(true); - trimActiveAlive = new PrecisionStopwatch(); - unloadActiveAlive = new PrecisionStopwatch(); - trimAlive = new PrecisionStopwatch(); - unloadAlive = new PrecisionStopwatch(); - TotalTectonicPlates = new AtomicInteger(); - TotalQueuedTectonicPlates = new AtomicInteger(); - TotalNotQueuedTectonicPlates = new AtomicInteger(); - tectonicLimit.set(2); - long t = getHardware.getProcessMemory(); - while (t > 200) { - tectonicLimit.getAndAdd(1); - t = t - 200; + tectonicLimit.set(IrisSettings.get().getPerformance().getTectonicPlateSize()); + for (World world : Bukkit.getWorlds()) { + var access = IrisToolbelt.access(world); + if (access == null) return; + worlds.add(new Pair<>(world, access)); } - this.setup(); - this.TrimLogic(); - this.UnloadLogic(); - - trimAlive.begin(); - unloadAlive.begin(); - trimActiveAlive.begin(); - unloadActiveAlive.begin(); - - updateTicker.start(); - cacheTicker.start(); - //trimTicker.start(); - //unloadTicker.start(); - instance = this; + trimLogic(); + unloadLogic(); + setup(); } - public void engineStatus() { - boolean trimAlive = trimTicker.isAlive(); - boolean unloadAlive = unloadTicker.isAlive(); - Iris.info("Status:"); - Iris.info("- Trim: " + trimAlive); - Iris.info("- Unload: " + unloadAlive); - + @Override + public void onDisable() { + updateTicker.interrupt(); + trimTicker.interrupt(); + unloadTicker.interrupt(); + worlds.clear(); } - public static int getTectonicLimit() { - return tectonicLimit.get(); + public void engineStatus(VolmitSender sender) { + sender.sendMessage(C.DARK_PURPLE + "-------------------------"); + sender.sendMessage(C.DARK_PURPLE + "Status:"); + sender.sendMessage(C.DARK_PURPLE + "- Trim: " + C.LIGHT_PURPLE + trimTicker.isAlive()); + sender.sendMessage(C.DARK_PURPLE + "- Unload: " + C.LIGHT_PURPLE + unloadTicker.isAlive()); + sender.sendMessage(C.DARK_PURPLE + "- Update: " + C.LIGHT_PURPLE + updateTicker.isAlive()); + sender.sendMessage(C.DARK_PURPLE + "Tectonic Plates:"); + sender.sendMessage(C.DARK_PURPLE + "- Limit: " + C.LIGHT_PURPLE + tectonicLimit.get()); + sender.sendMessage(C.DARK_PURPLE + "- Total: " + C.LIGHT_PURPLE + tectonicPlates.get()); + sender.sendMessage(C.DARK_PURPLE + "- Queued: " + C.LIGHT_PURPLE + queuedTectonicPlates.get()); + sender.sendMessage(C.DARK_PURPLE + "- Max Idle Duration: " + C.LIGHT_PURPLE + Form.duration(maxIdleDuration.get(), 2)); + sender.sendMessage(C.DARK_PURPLE + "- Min Idle Duration: " + C.LIGHT_PURPLE + Form.duration(minIdleDuration.get(), 2)); + sender.sendMessage(C.DARK_PURPLE + "Other:"); + sender.sendMessage(C.DARK_PURPLE + "- Iris Worlds: " + C.LIGHT_PURPLE + worlds.size()); + sender.sendMessage(C.DARK_PURPLE + "- Loaded Chunks: " + C.LIGHT_PURPLE + loadedChunks.get()); + sender.sendMessage(C.DARK_PURPLE + "- Cache Size: " + C.LIGHT_PURPLE + Form.f(IrisData.cacheSize())); + sender.sendMessage(C.DARK_PURPLE + "-------------------------"); } @EventHandler public void onWorldUnload(WorldUnloadEvent event) { - updateWorlds(); + worlds.removeIf(p -> p.getA() == event.getWorld()); } @EventHandler public void onWorldLoad(WorldLoadEvent event) { - updateWorlds(); + var world = event.getWorld(); + var access = IrisToolbelt.access(world); + if (access == null) return; + worlds.add(new Pair<>(world, access)); } - @EventHandler - public void onServerBoot(ServerLoadEvent event) { - isServerLoaded = true; - } - - @EventHandler - public void onPluginDisable(PluginDisableEvent event) { - if (event.getPlugin().equals(Iris.instance)) { - isServerShuttingDown = true; - } - } - - public void updateWorlds() { - for (World world : Bukkit.getWorlds()) { - try { - if (IrisToolbelt.access(world).getEngine() != null) { - IrisWorlds.add(world); - } - } catch (Exception e) { - // no - } - } - } - - private void setup() { - cacheTicker = new Looper() { - @Override - protected long loop() { - long now = System.currentTimeMillis(); - lastUseLock.lock(); - try { - for (World key : new ArrayList<>(lastUse.keySet())) { - Long last = lastUse.get(key); - if (last == null) - continue; - if (now - last > 60000) { - lastUse.remove(key); - } - } - } finally { - lastUseLock.unlock(); - } - return 1000; - } - }; + private synchronized void setup() { + if (updateTicker != null && updateTicker.isAlive()) + return; updateTicker = new Looper() { @Override protected long loop() { try { - TotalQueuedTectonicPlates.set(0); - TotalNotQueuedTectonicPlates.set(0); - TotalTectonicPlates.set(0); - for (World world : IrisWorlds) { - Engine engine = Objects.requireNonNull(IrisToolbelt.access(world)).getEngine(); - TotalQueuedTectonicPlates.addAndGet((int) engine.getMantle().getToUnload()); - TotalNotQueuedTectonicPlates.addAndGet((int) engine.getMantle().getNotQueuedLoadedRegions()); - TotalTectonicPlates.addAndGet(engine.getMantle().getLoadedRegionCount()); - } - if (!isServerShuttingDown && isServerLoaded) { - if (!trimTicker.isAlive()) { - Iris.info(C.RED + "TrimTicker found dead! Booting it up!"); - try { - TrimLogic(); - } catch (Exception e) { - Iris.error("What happened?"); - e.printStackTrace(); - } - } + queuedTectonicPlates.set(0); + tectonicPlates.set(0); + loadedChunks.set(0); - if (!unloadTicker.isAlive()) { - Iris.info(C.RED + "UnloadTicker found dead! Booting it up!"); - try { - UnloadLogic(); - } catch (Exception e) { - Iris.error("What happened?"); - e.printStackTrace(); - } + double maxDuration = Long.MIN_VALUE; + double minDuration = Long.MAX_VALUE; + for (var pair : worlds) { + var engine = pair.getB().getEngine(); + if (engine == null) continue; + + queuedTectonicPlates.addAndGet((int) engine.getMantle().getUnloadRegionCount()); + tectonicPlates.addAndGet(engine.getMantle().getLoadedRegionCount()); + loadedChunks.addAndGet(pair.getA().getLoadedChunks().length); + + double duration = engine.getMantle().getAdjustedIdleDuration(); + if (duration > maxDuration) maxDuration = duration; + if (duration < minDuration) minDuration = duration; + } + maxIdleDuration.set(maxDuration); + minIdleDuration.set(minDuration); + + if (!trimTicker.isAlive()) { + Iris.error("TrimTicker found dead! Booting it up!"); + try { + trimLogic(); + } catch (Exception e) { + Iris.error("What happened?"); + e.printStackTrace(); } } - } catch (Exception e) { - return -1; + if (!unloadTicker.isAlive()) { + Iris.error("UnloadTicker found dead! Booting it up!"); + try { + unloadLogic(); + } catch (Exception e) { + Iris.error("What happened?"); + e.printStackTrace(); + } + } + } catch (Throwable e) { + e.printStackTrace(); } return 1000; } }; + updateTicker.start(); } - public void TrimLogic() { - if (trimTicker == null || !trimTicker.isAlive()) { - trimTicker = new Looper() { - private final Supplier supplier = createSupplier(); - @Override - protected long loop() { - long start = System.currentTimeMillis(); - trimAlive.reset(); - try { - Engine engine = supplier.get(); - if (engine != null) { - engine.getMantle().trim(tectonicLimit.get() / lastUse.size()); - } - } catch (Throwable e) { - Iris.reportError(e); - Iris.info(C.RED + "EngineSVC: Failed to trim."); - e.printStackTrace(); - return -1; + private synchronized void trimLogic() { + if (trimTicker != null && trimTicker.isAlive()) + return; + + trimTicker = new Looper() { + private final Supplier supplier = createSupplier(); + + @Override + protected long loop() { + long start = System.currentTimeMillis(); + try { + Engine engine = supplier.get(); + if (engine != null) { + engine.getMantle().trim(tectonicLimit.get() / worlds.size()); } - - int size = lastUse.size(); - long time = (size > 0 ? 1000 / size : 1000) - (System.currentTimeMillis() - start); - if (time <= 0) - return 0; - return time; + } catch (Throwable e) { + Iris.reportError(e); + Iris.error("EngineSVC: Failed to trim."); + e.printStackTrace(); + return -1; } - }; - trimTicker.start(); - } + + int size = worlds.size(); + long time = (size > 0 ? 1000 / size : 1000) - (System.currentTimeMillis() - start); + if (time <= 0) + return 0; + return time; + } + }; + trimTicker.start(); } - public void UnloadLogic() { - if (unloadTicker == null || !unloadTicker.isAlive()) { - unloadTicker = new Looper() { - private final Supplier supplier = createSupplier(); - @Override - protected long loop() { - long start = System.currentTimeMillis(); - unloadAlive.reset(); - try { - Engine engine = supplier.get(); - if (engine != null) { - long unloadStart = System.currentTimeMillis(); - int count = engine.getMantle().unloadTectonicPlate(tectonicLimit.get() / lastUse.size()); - if (count > 0) { - Iris.debug(C.GOLD + "Unloaded " + C.YELLOW + count + " TectonicPlates in " + C.RED + Form.duration(System.currentTimeMillis() - unloadStart, 2)); - } + private synchronized void unloadLogic() { + if (unloadTicker != null && unloadTicker.isAlive()) + return; + + unloadTicker = new Looper() { + private final Supplier supplier = createSupplier(); + + @Override + protected long loop() { + long start = System.currentTimeMillis(); + try { + Engine engine = supplier.get(); + if (engine != null) { + long unloadStart = System.currentTimeMillis(); + int count = engine.getMantle().unloadTectonicPlate(tectonicLimit.get() / worlds.size()); + if (count > 0) { + Iris.debug(C.GOLD + "Unloaded " + C.YELLOW + count + " TectonicPlates in " + C.RED + Form.duration(System.currentTimeMillis() - unloadStart, 2)); } - } catch (Throwable e) { - Iris.reportError(e); - Iris.info(C.RED + "EngineSVC: Failed to unload."); - e.printStackTrace(); - return -1; } - - int size = lastUse.size(); - long time = (size > 0 ? 1000 / size : 1000) - (System.currentTimeMillis() - start); - if (time <= 0) - return 0; - return time; + } catch (Throwable e) { + Iris.reportError(e); + Iris.error("EngineSVC: Failed to unload."); + e.printStackTrace(); + return -1; } - }; - unloadTicker.start(); - } + + int size = worlds.size(); + long time = (size > 0 ? 1000 / size : 1000) - (System.currentTimeMillis() - start); + if (time <= 0) + return 0; + return time; + } + }; + unloadTicker.start(); } private Supplier createSupplier() { AtomicInteger i = new AtomicInteger(); return () -> { - List worlds = Bukkit.getWorlds(); if (i.get() >= worlds.size()) { i.set(0); } try { for (int j = 0; j < worlds.size(); j++) { - World world = worlds.get(i.getAndIncrement()); - PlatformChunkGenerator generator = IrisToolbelt.access(world); + var pair = worlds.get(i.getAndIncrement()); if (i.get() >= worlds.size()) { i.set(0); } - if (generator != null) { - Engine engine = generator.getEngine(); - boolean closed = engine.getMantle().getData().isClosed(); - if (engine != null && !engine.isStudio() && !closed) { - lastUseLock.lock(); - lastUse.put(world, System.currentTimeMillis()); - lastUseLock.unlock(); - return engine; - } + var engine = pair.getB().getEngine(); + if (engine != null && !engine.isClosed() && engine.getMantle().getMantle().shouldReduce(engine)) { + return engine; } } } catch (Throwable e) { - Iris.info(C.RED + "EngineSVC: Failed to create supplier."); + Iris.error("EngineSVC: Failed to create supplier."); e.printStackTrace(); Iris.reportError(e); } return null; }; } - - @Override - public void onDisable() { - cacheTicker.interrupt(); - trimTicker.interrupt(); - unloadTicker.interrupt(); - lastUse.clear(); - } } diff --git a/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java b/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java index b55ce9e7f..d581fecaa 100644 --- a/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java +++ b/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java @@ -299,13 +299,11 @@ public interface EngineMantle extends IObjectPlacer { } } - default long getToUnload(){ - return getMantle().getToUnload().size(); + default long getUnloadRegionCount() { + return getMantle().getUnloadRegionCount(); } - default long getNotQueuedLoadedRegions(){ - return getMantle().getLoadedRegions().size() - getMantle().getToUnload().size(); - } - default double getTectonicDuration(){ - return getMantle().getAdjustedIdleDuration().get(); + + default double getAdjustedIdleDuration() { + return getMantle().getAdjustedIdleDuration(); } } \ No newline at end of file diff --git a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java index c2ed23c83..410e8bbe0 100644 --- a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java +++ b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java @@ -86,12 +86,12 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun private final boolean studio; private final AtomicInteger a = new AtomicInteger(0); private final CompletableFuture spawnChunks = new CompletableFuture<>(); - private Engine engine; - private Looper hotloader; - private StudioMode lastMode; - private DummyBiomeProvider dummyBiomeProvider; + private volatile Engine engine; + private volatile Looper hotloader; + private volatile StudioMode lastMode; + private volatile DummyBiomeProvider dummyBiomeProvider; @Setter - private StudioGenerator studioGenerator; + private volatile StudioGenerator studioGenerator; private boolean initialized = false; @@ -110,20 +110,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun Bukkit.getServer().getPluginManager().registerEvents(this, Iris.instance); } - private static Field getField(Class clazz, String fieldName) - throws NoSuchFieldException { - try { - return clazz.getDeclaredField(fieldName); - } catch (NoSuchFieldException e) { - Class superClass = clazz.getSuperclass(); - if (superClass == null) { - throw e; - } else { - return getField(superClass, fieldName); - } - } - } - @EventHandler(priority = EventPriority.LOWEST) public void onWorldInit(WorldInitEvent event) { try { diff --git a/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java b/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java index 59ba16399..41fa887f0 100644 --- a/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java +++ b/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java @@ -21,14 +21,13 @@ package com.volmit.iris.util.mantle; import com.google.common.util.concurrent.AtomicDouble; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; -import com.volmit.iris.core.service.IrisEngineSVC; import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.engine.data.cache.Cache; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.mantle.EngineMantle; import com.volmit.iris.engine.mantle.MantleWriter; -import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.collection.KSet; import com.volmit.iris.util.documentation.BlockCoordinates; import com.volmit.iris.util.documentation.ChunkCoordinates; import com.volmit.iris.util.documentation.RegionCoordinates; @@ -51,8 +50,6 @@ import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.locks.ReentrantLock; /** * The mantle can store any type of data slice anywhere and manage regions & IO on it's own. @@ -60,18 +57,18 @@ import java.util.concurrent.locks.ReentrantLock; */ public class Mantle { - private static final boolean disableClear = System.getProperty("disableClear", "false").equals("true"); private final File dataFolder; @Getter private final int worldHeight; private final Map lastUse; - @Getter private final Map loadedRegions; private final HyperLock hyperLock; private final AtomicBoolean closed; private final MultiBurst ioBurst; private final AtomicBoolean ioTrim; private final AtomicBoolean ioTectonicUnload; + private final AtomicDouble adjustedIdleDuration; + private final KSet toUnload; /** * Create a new mantle @@ -91,6 +88,8 @@ public class Mantle { loadedRegions = new KMap<>(); lastUse = new KMap<>(); ioBurst = MultiBurst.burst; + adjustedIdleDuration = new AtomicDouble(0); + toUnload = new KSet<>(); Iris.debug("Opened The Mantle " + C.DARK_AQUA + dataFolder.getAbsolutePath()); } @@ -410,16 +409,6 @@ public class Mantle { return numberOfEntries * bytesPerEntry; } - @Getter - private final AtomicDouble adjustedIdleDuration = new AtomicDouble(0); - @Getter - private final AtomicInteger forceAggressiveThreshold = new AtomicInteger(30); - @Getter - private final AtomicLong oldestTectonicPlate = new AtomicLong(0); - private final ReentrantLock unloadLock = new ReentrantLock(); - @Getter - private final KList toUnload = new KList<>(); - /** * Save & unload regions that have not been used for more than the * specified amount of milliseconds @@ -441,85 +430,74 @@ public class Mantle { } ioTrim.set(true); - unloadLock.lock(); try { - if (lastUse != null && IrisEngineSVC.instance != null) { - if (!lastUse.isEmpty()) { - Iris.debug("Trimming Tectonic Plates older than " + Form.duration(adjustedIdleDuration.get(), 0)); - for (long i : new ArrayList<>(lastUse.keySet())) { - double finalAdjustedIdleDuration = adjustedIdleDuration.get(); - hyperLock.withLong(i, () -> { - Long lastUseTime = lastUse.get(i); - if (lastUseTime != null && M.ms() - lastUseTime >= finalAdjustedIdleDuration) { - toUnload.add(i); - Iris.debug("Tectonic Region added to unload"); - IrisEngineSVC.instance.trimActiveAlive.reset(); - } - }); - } - } - } + double adjustedIdleDuration = this.adjustedIdleDuration.get(); + Iris.debug("Trimming Tectonic Plates older than " + Form.duration(adjustedIdleDuration, 0)); + if (lastUse.isEmpty()) return; + double unloadTime = M.ms() - adjustedIdleDuration; + for (long id : lastUse.keySet()) { + hyperLock.withLong(id, () -> { + Long lastUseTime = lastUse.get(id); + if (lastUseTime != null && lastUseTime < unloadTime) { + toUnload.add(id); + Iris.debug("Tectonic Region added to unload"); + } + }); + } } catch (Throwable e) { Iris.reportError(e); } finally { ioTrim.set(false); - unloadLock.unlock(); } } public synchronized int unloadTectonicPlate(int tectonicLimit) { + if (closed.get()) { + throw new RuntimeException("The Mantle is closed"); + } + AtomicInteger i = new AtomicInteger(); - unloadLock.lock(); - BurstExecutor burst = null; - if (IrisEngineSVC.instance != null) { - try { - KList copy = toUnload.copy(); - if (!disableClear) toUnload.clear(); - burst = MultiBurst.burst.burst(copy.size()); - burst.setMulticore(copy.size() > tectonicLimit); - for (int j = 0; j < copy.size(); j++) { - Long id = copy.get(j); - if (id == null) { - Iris.error("Null id in unloadTectonicPlate at index " + j); - continue; + BurstExecutor burst = ioBurst.burst(toUnload.size()); + burst.setMulticore(toUnload.size() > tectonicLimit); + + ioTectonicUnload.set(true); + try { + for (long id : toUnload) { + burst.queue(() -> hyperLock.withLong(id, () -> { + TectonicPlate m = loadedRegions.get(id); + if (m == null) { + Iris.debug("Tectonic Plate was added to unload while not loaded " + C.DARK_GREEN + Cache.keyX(id) + " " + Cache.keyZ(id)); + toUnload.remove(id); + return; } - burst.queue(() -> - hyperLock.withLong(id, () -> { - TectonicPlate m = loadedRegions.get(id); - if (m != null) { - if (m.inUse()) { - Iris.debug("Tectonic Plate was added to unload while in use " + C.DARK_GREEN + m.getX() + " " + m.getZ()); - if (disableClear) toUnload.remove(id); - lastUse.put(id, M.ms()); - return; - } - try { - m.write(fileForRegion(dataFolder, id, false)); - oldFileForRegion(dataFolder, id).delete(); - loadedRegions.remove(id); - lastUse.remove(id); - if (disableClear) toUnload.remove(id); - i.incrementAndGet(); - Iris.debug("Unloaded Tectonic Plate " + C.DARK_GREEN + Cache.keyX(id) + " " + Cache.keyZ(id)); - IrisEngineSVC.instance.unloadActiveAlive.reset(); - } catch (IOException e) { - Iris.reportError(e); - } - } - })); - } - burst.complete(); - } catch (Throwable e) { - e.printStackTrace(); - if (burst != null) - burst.complete(); - } finally { - unloadLock.unlock(); - ioTectonicUnload.set(true); + if (m.inUse()) { + Iris.debug("Tectonic Plate was added to unload while in use " + C.DARK_GREEN + m.getX() + " " + m.getZ()); + toUnload.remove(id); + return; + } + + try { + m.write(fileForRegion(dataFolder, id, false)); + oldFileForRegion(dataFolder, id).delete(); + loadedRegions.remove(id); + lastUse.remove(id); + toUnload.remove(id); + i.incrementAndGet(); + Iris.debug("Unloaded Tectonic Plate " + C.DARK_GREEN + Cache.keyX(id) + " " + Cache.keyZ(id)); + } catch (IOException e) { + Iris.reportError(e); + } + })); } - return i.get(); + burst.complete(); + } catch (Throwable e) { + Iris.reportError(e); + e.printStackTrace(); + burst.complete(); + } finally { + ioTectonicUnload.set(false); } return i.get(); } @@ -535,7 +513,7 @@ public class Mantle { */ @RegionCoordinates private TectonicPlate get(int x, int z) { - if (ioTrim.get()) { + if (ioTrim.get() || ioTectonicUnload.get()) { try { return getSafe(x, z).get(); } catch (InterruptedException e) { @@ -645,6 +623,14 @@ public class Mantle { return loadedRegions.size(); } + public int getUnloadRegionCount() { + return toUnload.size(); + } + + public double getAdjustedIdleDuration() { + return adjustedIdleDuration.get(); + } + public void set(int x, int y, int z, MatterSlice slice) { if (slice.isEmpty()) { return;