mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-12-31 04:46:40 +00:00
fix ArrayIndexOutOfBoundsException
fix NullPointerException fix ConcurrentModificationException x2
This commit is contained in:
@@ -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<Engine, Long> cache = new KMap<>();
|
||||
private final ReentrantLock lastUseLock = new ReentrantLock();
|
||||
private final KMap<Engine, Long> 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<T> implements Palette<T> {
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
private final LinkedHashMap<T, Integer> palette;
|
||||
private final KMap<Integer, T> lookup;
|
||||
private final AtomicInteger size;
|
||||
@@ -47,14 +49,18 @@ public class HashPalette<T> implements Palette<T> {
|
||||
|
||||
@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<T> implements Palette<T> {
|
||||
|
||||
@Override
|
||||
public void iterate(Consumer2<T, Integer> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Long> toUnload = new HashSet<>();
|
||||
private final Set<Long> 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<Long> toUnload = this.toUnload;
|
||||
this.toUnload = new HashSet<>();
|
||||
toUnload.removeIf(Objects::isNull);
|
||||
unloadLock.lock();
|
||||
try {
|
||||
List<Future<?>> 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();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user