fix ArrayIndexOutOfBoundsException

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