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 2c80ecbaf..644d887e0 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 @@ -16,11 +16,13 @@ import org.bukkit.World; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.ReentrantLock; import java.util.function.Supplier; public class IrisEngineSVC implements IrisService { private static final AtomicInteger tectonicLimit = new AtomicInteger(30); - private final KMap cache = new KMap<>(); + private final ReentrantLock lastUseLock = new ReentrantLock(); + private final KMap lastUse = new KMap<>(); private Looper cacheTicker; private Looper trimTicker; private Looper unloadTicker; @@ -52,13 +54,18 @@ public class IrisEngineSVC implements IrisService { @Override protected long loop() { long now = System.currentTimeMillis(); - for (Engine key : cache.keySet()) { - Long last = cache.get(key); - if (last == null) - continue; - if (now - last > 600000) { // 10 minutes - cache.remove(key); + lastUseLock.lock(); + try { + for (Engine key : new ArrayList<>(lastUse.keySet())) { + Long last = lastUse.get(key); + if (last == null) + continue; + if (now - last > 60000) { // 1 minute + lastUse.remove(key); + } } + } finally { + lastUseLock.unlock(); } return 1000; } @@ -71,14 +78,14 @@ public class IrisEngineSVC implements IrisService { try { Engine engine = supplier.get(); if (engine != null) { - engine.getMantle().trim(tectonicLimit.get() / cache.size()); + engine.getMantle().trim(tectonicLimit.get() / lastUse.size()); } } catch (Throwable e) { Iris.reportError(e); return -1; } - int size = cache.size(); + int size = lastUse.size(); long time = (size > 0 ? 1000/size : 1000) - (System.currentTimeMillis() - start); if (time <= 0) return 0; @@ -106,7 +113,7 @@ public class IrisEngineSVC implements IrisService { return -1; } - int size = cache.size(); + int size = lastUse.size(); long time = (size > 0 ? 1000/size : 1000) - (System.currentTimeMillis() - start); if (time <= 0) return 0; @@ -132,7 +139,9 @@ public class IrisEngineSVC implements IrisService { if (generator != null) { Engine engine = generator.getEngine(); if (engine != null) { - cache.put(engine, System.currentTimeMillis()); + lastUseLock.lock(); + lastUse.put(engine, System.currentTimeMillis()); + lastUseLock.unlock(); return engine; } } @@ -149,6 +158,6 @@ public class IrisEngineSVC implements IrisService { cacheTicker.interrupt(); trimTicker.interrupt(); unloadTicker.interrupt(); - cache.clear(); + lastUse.clear(); } } diff --git a/core/src/main/java/com/volmit/iris/util/hunk/bits/HashPalette.java b/core/src/main/java/com/volmit/iris/util/hunk/bits/HashPalette.java index 2afc2c696..c35c02acc 100644 --- a/core/src/main/java/com/volmit/iris/util/hunk/bits/HashPalette.java +++ b/core/src/main/java/com/volmit/iris/util/hunk/bits/HashPalette.java @@ -23,8 +23,10 @@ import com.volmit.iris.util.function.Consumer2; import java.util.LinkedHashMap; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.ReentrantLock; public class HashPalette implements Palette { + private final ReentrantLock lock = new ReentrantLock(); private final LinkedHashMap palette; private final KMap lookup; private final AtomicInteger size; @@ -47,14 +49,18 @@ public class HashPalette implements Palette { @Override public int add(T t) { - int index = size.getAndIncrement(); - palette.put(t, index); + lock.lock(); + try { + int index = size.getAndIncrement(); + palette.put(t, index); - if (t != null) { - lookup.put(index, t); + if (t != null) { + lookup.put(index, t); + } + return index; + } finally { + lock.unlock(); } - - return index; } @Override @@ -74,12 +80,17 @@ public class HashPalette implements Palette { @Override public void iterate(Consumer2 c) { - for (T i : palette.keySet()) { - if (i == null) { - continue; - } + lock.lock(); + try { + for (T i : palette.keySet()) { + if (i == null) { + continue; + } - c.accept(i, id(i)); + c.accept(i, id(i)); + } + } finally { + lock.unlock(); } } } 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 7b101cd2f..d4c04a189 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 @@ -50,6 +50,7 @@ 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. @@ -396,8 +397,9 @@ public class Mantle { private final AtomicInteger forceAggressiveThreshold = new AtomicInteger(30); @Getter private final AtomicLong oldestTectonicPlate = new AtomicLong(0); + private final ReentrantLock unloadLock = new ReentrantLock(); @Getter - private Set toUnload = new HashSet<>(); + private final Set toUnload = new HashSet<>(); /** * Save & unload regions that have not been used for more than the @@ -421,6 +423,7 @@ public class Mantle { } ioTrim.set(true); + unloadLock.lock(); try { Iris.debug("Trimming Tectonic Plates older than " + Form.duration(adjustedIdleDuration.get(), 0)); if (lastUse != null) { @@ -438,14 +441,13 @@ public class Mantle { } finally { ioTrim.set(false); + unloadLock.unlock(); } } public int unloadTectonicPlate() { AtomicInteger i = new AtomicInteger(); - Set toUnload = this.toUnload; - this.toUnload = new HashSet<>(); - toUnload.removeIf(Objects::isNull); + unloadLock.lock(); try { List> futures = new ArrayList<>(); ExecutorService service = Executors.newFixedThreadPool(dynamicThreads.get()); @@ -471,15 +473,16 @@ public class Mantle { try { while (!futures.isEmpty()) { futures.remove(0).get(); + futures.removeIf(Future::isDone); } service.shutdown(); } catch (InterruptedException ignored) {} } catch (Exception e) { e.printStackTrace(); } finally { - this.toUnload.addAll(toUnload); + unloadLock.unlock(); + ioTectonicUnload.set(true); } - ioTectonicUnload.set(true); return i.get(); }