From f0476fea9b048e42f8a7a4d10a891c7321cfa8f8 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 26 May 2025 20:54:12 +0200 Subject: [PATCH 1/3] implement version header for tectonic plates --- build.gradle | 5 ++ .../com/volmit/iris/core/IrisSettings.java | 1 + .../iris/core/commands/CommandDeveloper.java | 9 ++-- .../iris/util/atomics/AtomicAverage.java | 12 ++--- .../com/volmit/iris/util/collection/KSet.java | 54 ++++++++++++++++--- .../com/volmit/iris/util/mantle/Mantle.java | 38 +++++++++---- .../volmit/iris/util/mantle/MantleChunk.java | 11 +++- .../iris/util/mantle/TectonicPlate.java | 24 +++++---- .../com/volmit/iris/util/matter/Matter.java | 17 +++--- 9 files changed, 124 insertions(+), 47 deletions(-) diff --git a/build.gradle b/build.gradle index b385555b4..67610d095 100644 --- a/build.gradle +++ b/build.gradle @@ -113,6 +113,11 @@ shadowJar { relocate 'net.kyori', 'com.volmit.iris.util.kyori' relocate 'org.bstats', 'com.volmit.util.metrics' archiveFileName.set("Iris-${project.version}.jar") + + dependencies { + exclude(dependency("org.ow2.asm:asm:")) + exclude(dependency("org.jetbrains:")) + } } dependencies { 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 826746193..1a86aad11 100644 --- a/core/src/main/java/com/volmit/iris/core/IrisSettings.java +++ b/core/src/main/java/com/volmit/iris/core/IrisSettings.java @@ -191,6 +191,7 @@ public class IrisSettings { public boolean DoomsdayAnnihilationSelfDestructMode = false; public boolean commandSounds = true; public boolean debug = false; + public boolean dumpMantleOnError = false; public boolean disableNMS = false; public boolean pluginMetrics = true; public boolean splashLogoStartup = true; 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 f9590151a..d54a97e5b 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 @@ -166,7 +166,7 @@ public class CommandDeveloper implements DecreeExecutor { File tectonicplates = new File(folder, "mantle"); for (File i : Objects.requireNonNull(tectonicplates.listFiles())) { - TectonicPlate.read(maxHeight, i); + TectonicPlate.read(maxHeight, i, true); c++; Iris.info("Loaded count: " + c ); @@ -272,7 +272,8 @@ public class CommandDeveloper implements DecreeExecutor { @Param(description = "base IrisWorld") World world, @Param(description = "raw TectonicPlate File") String path, @Param(description = "Algorithm to Test") String algorithm, - @Param(description = "Amount of Tests") int amount) { + @Param(description = "Amount of Tests") int amount, + @Param(description = "Is versioned", defaultValue = "false") boolean versioned) { if (!IrisToolbelt.isIrisWorld(world)) { sender().sendMessage(C.RED + "This is not an Iris world. Iris worlds: " + String.join(", ", Bukkit.getServer().getWorlds().stream().filter(IrisToolbelt::isIrisWorld).map(World::getName).toList())); return; @@ -289,7 +290,7 @@ public class CommandDeveloper implements DecreeExecutor { service.submit(() -> { try { CountingDataInputStream raw = CountingDataInputStream.wrap(new FileInputStream(file)); - TectonicPlate plate = new TectonicPlate(height, raw); + TectonicPlate plate = new TectonicPlate(height, raw, versioned); raw.close(); double d1 = 0; @@ -308,7 +309,7 @@ public class CommandDeveloper implements DecreeExecutor { size = tmp.length(); start = System.currentTimeMillis(); CountingDataInputStream din = createInput(tmp, algorithm); - new TectonicPlate(height, din); + new TectonicPlate(height, din, true); din.close(); d2 += System.currentTimeMillis() - start; tmp.delete(); diff --git a/core/src/main/java/com/volmit/iris/util/atomics/AtomicAverage.java b/core/src/main/java/com/volmit/iris/util/atomics/AtomicAverage.java index cf9da6d1c..f3574db1d 100644 --- a/core/src/main/java/com/volmit/iris/util/atomics/AtomicAverage.java +++ b/core/src/main/java/com/volmit/iris/util/atomics/AtomicAverage.java @@ -31,11 +31,11 @@ import com.volmit.iris.util.data.DoubleArrayUtils; */ public class AtomicAverage { protected final AtomicDoubleArray values; - protected int cursor; - private double average; - private double lastSum; - private boolean dirty; - private boolean brandNew; + protected transient int cursor; + private transient double average; + private transient double lastSum; + private transient boolean dirty; + private transient boolean brandNew; /** * Create an average holder @@ -57,7 +57,7 @@ public class AtomicAverage { * * @param i the value */ - public void put(double i) { + public synchronized void put(double i) { try { dirty = true; diff --git a/core/src/main/java/com/volmit/iris/util/collection/KSet.java b/core/src/main/java/com/volmit/iris/util/collection/KSet.java index ad96f7085..53b602f9a 100644 --- a/core/src/main/java/com/volmit/iris/util/collection/KSet.java +++ b/core/src/main/java/com/volmit/iris/util/collection/KSet.java @@ -18,29 +18,67 @@ package com.volmit.iris.util.collection; -import java.util.Collection; -import java.util.HashSet; +import org.jetbrains.annotations.NotNull; -public class KSet extends HashSet { +import java.io.Serializable; +import java.util.AbstractSet; +import java.util.Collection; +import java.util.Iterator; +import java.util.concurrent.ConcurrentHashMap; + +public class KSet extends AbstractSet implements Serializable { private static final long serialVersionUID = 1L; + private final ConcurrentHashMap map; public KSet() { - super(); + map = new ConcurrentHashMap<>(); } public KSet(Collection c) { - super(c); + this(); + addAll(c); } public KSet(int initialCapacity, float loadFactor) { - super(initialCapacity, loadFactor); + map = new ConcurrentHashMap<>(initialCapacity, loadFactor); } public KSet(int initialCapacity) { - super(initialCapacity); + map = new ConcurrentHashMap<>(initialCapacity); + } + + @Override + public int size() { + return map.size(); + } + + @Override + public boolean contains(Object o) { + return map.containsKey(o); + } + + @Override + public boolean add(T t) { + return map.putIfAbsent(t, Boolean.TRUE) == null; + } + + @Override + public boolean remove(Object o) { + return map.remove(o) != null; + } + + @Override + public void clear() { + map.clear(); + } + + @NotNull + @Override + public Iterator iterator() { + return map.keySet().iterator(); } public KSet copy() { - return new KSet(this); + return new KSet<>(this); } } 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 3ae6ad880..59ba16399 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 @@ -103,7 +103,7 @@ public class Mantle { * @return the file */ public static File fileForRegion(File folder, int x, int z) { - return fileForRegion(folder, key(x, z)); + return fileForRegion(folder, key(x, z), true); } /** @@ -113,12 +113,28 @@ public class Mantle { * @param key the region key * @return the file */ - public static File fileForRegion(File folder, Long key) { - File f = new File(folder, "p." + key + ".ttp.lz4b"); - if (!f.getParentFile().exists()) { - f.getParentFile().mkdirs(); + public static File fileForRegion(File folder, Long key, boolean convert) { + File f = oldFileForRegion(folder, key); + File fv = new File(folder, "pv." + key + ".ttp.lz4b"); + if (f.exists() && !fv.exists() && convert) + return f; + + if (!fv.getParentFile().exists()) { + fv.getParentFile().mkdirs(); } - return f; + return fv; + } + + + /** + * Get the old file for the given region + * + * @param folder the data folder + * @param key the region key + * @return the file + */ + public static File oldFileForRegion(File folder, Long key) { + return new File(folder, "p." + key + ".ttp.lz4b"); } /** @@ -210,7 +226,7 @@ public class Mantle { @RegionCoordinates public boolean hasTectonicPlate(int x, int z) { Long k = key(x, z); - return loadedRegions.containsKey(k) || fileForRegion(dataFolder, k).exists(); + return loadedRegions.containsKey(k) || fileForRegion(dataFolder, k, true).exists(); } /** @@ -364,7 +380,8 @@ public class Mantle { loadedRegions.forEach((i, plate) -> b.queue(() -> { try { plate.close(); - plate.write(fileForRegion(dataFolder, i)); + plate.write(fileForRegion(dataFolder, i, false)); + oldFileForRegion(dataFolder, i).delete(); } catch (Throwable e) { Iris.error("Failed to write Tectonic Plate " + C.DARK_GREEN + Cache.keyX(i) + " " + Cache.keyZ(i)); e.printStackTrace(); @@ -479,7 +496,8 @@ public class Mantle { return; } try { - m.write(fileForRegion(dataFolder, id)); + m.write(fileForRegion(dataFolder, id, false)); + oldFileForRegion(dataFolder, id).delete(); loadedRegions.remove(id); lastUse.remove(id); if (disableClear) toUnload.remove(id); @@ -577,7 +595,7 @@ public class Mantle { if (file.exists()) { try { Iris.addPanic("reading.tectonic-plate", file.getAbsolutePath()); - region = TectonicPlate.read(worldHeight, file); + region = TectonicPlate.read(worldHeight, file, file.getName().startsWith("pv.")); if (region.getX() != x || region.getZ() != z) { Iris.warn("Loaded Tectonic Plate " + x + "," + z + " but read it as " + region.getX() + "," + region.getZ() + "... Assuming " + x + "," + z); diff --git a/core/src/main/java/com/volmit/iris/util/mantle/MantleChunk.java b/core/src/main/java/com/volmit/iris/util/mantle/MantleChunk.java index 0cfea94d8..ae4fd1701 100644 --- a/core/src/main/java/com/volmit/iris/util/mantle/MantleChunk.java +++ b/core/src/main/java/com/volmit/iris/util/mantle/MantleChunk.java @@ -19,6 +19,7 @@ package com.volmit.iris.util.mantle; import com.volmit.iris.Iris; +import com.volmit.iris.util.data.Varint; import com.volmit.iris.util.documentation.ChunkCoordinates; import com.volmit.iris.util.function.Consumer4; import com.volmit.iris.util.io.CountingDataInputStream; @@ -74,11 +75,12 @@ public class MantleChunk { * @throws IOException shit happens * @throws ClassNotFoundException shit happens */ - public MantleChunk(int sectionHeight, CountingDataInputStream din) throws IOException { + public MantleChunk(int version, int sectionHeight, CountingDataInputStream din) throws IOException { this(sectionHeight, din.readByte(), din.readByte()); int s = din.readByte(); + int l = version < 0 ? flags.length() : Varint.readUnsignedVarInt(din); - for (int i = 0; i < flags.length(); i++) { + for (int i = 0; i < flags.length() && i < l; i++) { flags.set(i, din.readBoolean() ? 1 : 0); } @@ -87,6 +89,10 @@ public class MantleChunk { long size = din.readInt(); if (size == 0) continue; long start = din.count(); + if (i >= sectionHeight) { + din.skipTo(start + size); + continue; + } try { sections.set(i, Matter.readDin(din)); @@ -210,6 +216,7 @@ public class MantleChunk { dos.writeByte(x); dos.writeByte(z); dos.writeByte(sections.length()); + Varint.writeUnsignedVarInt(flags.length(), dos); for (int i = 0; i < flags.length(); i++) { dos.writeBoolean(flags.get(i) == 1); diff --git a/core/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java b/core/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java index e635d4649..82c259aaf 100644 --- a/core/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java +++ b/core/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java @@ -19,9 +19,10 @@ package com.volmit.iris.util.mantle; import com.volmit.iris.Iris; +import com.volmit.iris.core.IrisSettings; import com.volmit.iris.engine.EnginePanic; import com.volmit.iris.engine.data.cache.Cache; -import com.volmit.iris.util.collection.KSet; +import com.volmit.iris.util.data.Varint; import com.volmit.iris.util.documentation.ChunkCoordinates; import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.Form; @@ -44,7 +45,9 @@ import java.util.concurrent.atomic.AtomicReferenceArray; * Tectonic Plates are fully atomic & thread safe */ public class TectonicPlate { - private static final KSet errors = new KSet<>(); + private static final ThreadLocal errors = ThreadLocal.withInitial(() -> false); + public static final int MISSING = -1; + public static final int CURRENT = 0; private final int sectionHeight; private final AtomicReferenceArray chunks; @@ -74,11 +77,12 @@ public class TectonicPlate { * @param din the data input * @throws IOException shit happens yo */ - public TectonicPlate(int worldHeight, CountingDataInputStream din) throws IOException { + public TectonicPlate(int worldHeight, CountingDataInputStream din, boolean versioned) throws IOException { this(worldHeight, din.readInt(), din.readInt()); if (!din.markSupported()) throw new IOException("Mark not supported!"); + int v = versioned ? Varint.readUnsignedVarInt(din) : MISSING; for (int i = 0; i < chunks.length(); i++) { long size = din.readInt(); if (size == 0) continue; @@ -86,7 +90,7 @@ public class TectonicPlate { try { Iris.addPanic("read-chunk", "Chunk[" + i + "]"); - chunks.set(i, new MantleChunk(sectionHeight, din)); + chunks.set(i, new MantleChunk(v, sectionHeight, din)); EnginePanic.saveLast(); } catch (Throwable e) { long end = start + size; @@ -103,7 +107,7 @@ public class TectonicPlate { } } - public static TectonicPlate read(int worldHeight, File file) throws IOException { + public static TectonicPlate read(int worldHeight, File file, boolean versioned) throws IOException { try (FileChannel fc = FileChannel.open(file.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.SYNC)) { fc.lock(); @@ -111,10 +115,10 @@ public class TectonicPlate { LZ4BlockInputStream lz4 = new LZ4BlockInputStream(fin); BufferedInputStream bis = new BufferedInputStream(lz4); try (CountingDataInputStream din = CountingDataInputStream.wrap(bis)) { - return new TectonicPlate(worldHeight, din); + return new TectonicPlate(worldHeight, din, versioned); } } finally { - if (errors.remove(Thread.currentThread())) { + if (IrisSettings.get().getGeneral().isDumpMantleOnError() && errors.get()) { File dump = Iris.instance.getDataFolder("dump", file.getName() + ".bin"); try (FileChannel fc = FileChannel.open(file.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.SYNC)) { fc.lock(); @@ -124,6 +128,7 @@ public class TectonicPlate { Files.copy(lz4, dump.toPath(), StandardCopyOption.REPLACE_EXISTING); } } + errors.remove(); } } @@ -222,7 +227,7 @@ public class TectonicPlate { write(dos); } Files.move(temp.toPath(), file.toPath(), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); - Iris.debug("Saved Tectonic Plate " + C.DARK_GREEN + file.getName().split("\\Q.\\E")[0] + C.RED + " in " + Form.duration(p.getMilliseconds(), 2)); + Iris.debug("Saved Tectonic Plate " + C.DARK_GREEN + file.getName() + C.RED + " in " + Form.duration(p.getMilliseconds(), 2)); temp.delete(); } @@ -235,6 +240,7 @@ public class TectonicPlate { public void write(DataOutputStream dos) throws IOException { dos.writeInt(x); dos.writeInt(z); + Varint.writeUnsignedVarInt(CURRENT, dos); var bytes = new ByteArrayOutputStream(8192); var sub = new DataOutputStream(bytes); @@ -256,6 +262,6 @@ public class TectonicPlate { } public static void addError() { - errors.add(Thread.currentThread()); + errors.set(true); } } diff --git a/core/src/main/java/com/volmit/iris/util/matter/Matter.java b/core/src/main/java/com/volmit/iris/util/matter/Matter.java index c04fe2485..086b397bd 100644 --- a/core/src/main/java/com/volmit/iris/util/matter/Matter.java +++ b/core/src/main/java/com/volmit/iris/util/matter/Matter.java @@ -154,15 +154,16 @@ public interface Matter { matter.putSlice(type, slice); } catch (Throwable e) { long end = start + size; - Iris.error("Failed to read matter slice, skipping it."); - Iris.addPanic("read.byte.range", start + " " + end); - Iris.addPanic("read.byte.current", din.count() + ""); - Iris.reportError(e); - e.printStackTrace(); - Iris.panic(); - + if (!(e instanceof ClassNotFoundException)) { + Iris.error("Failed to read matter slice, skipping it."); + Iris.addPanic("read.byte.range", start + " " + end); + Iris.addPanic("read.byte.current", din.count() + ""); + Iris.reportError(e); + e.printStackTrace(); + Iris.panic(); + TectonicPlate.addError(); + } din.skipTo(end); - TectonicPlate.addError(); } } From 2452a2f6338f30af9be46bb847b7de02c315a08d Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Tue, 27 May 2025 16:23:02 +0200 Subject: [PATCH 2/3] 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; From b132862a601065669b5b87fc436f752c171fad69 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Tue, 27 May 2025 22:50:30 +0200 Subject: [PATCH 3/3] update last use for in use tectonic plates --- core/src/main/java/com/volmit/iris/util/mantle/Mantle.java | 1 + 1 file changed, 1 insertion(+) 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 41fa887f0..03bd78fe1 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 @@ -474,6 +474,7 @@ public class Mantle { if (m.inUse()) { Iris.debug("Tectonic Plate was added to unload while in use " + C.DARK_GREEN + m.getX() + " " + m.getZ()); + lastUse.put(id, M.ms()); toUnload.remove(id); return; }