mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-06-18 14:50:57 +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.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,14 +54,19 @@ 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 {
|
||||||
|
for (Engine key : new ArrayList<>(lastUse.keySet())) {
|
||||||
|
Long last = lastUse.get(key);
|
||||||
if (last == null)
|
if (last == null)
|
||||||
continue;
|
continue;
|
||||||
if (now - last > 600000) { // 10 minutes
|
if (now - last > 60000) { // 1 minute
|
||||||
cache.remove(key);
|
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) {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
int index = size.getAndIncrement();
|
int index = size.getAndIncrement();
|
||||||
palette.put(t, index);
|
palette.put(t, index);
|
||||||
|
|
||||||
if (t != null) {
|
if (t != null) {
|
||||||
lookup.put(index, t);
|
lookup.put(index, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
return index;
|
return index;
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -74,6 +80,8 @@ public class HashPalette<T> implements Palette<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void iterate(Consumer2<T, Integer> c) {
|
public void iterate(Consumer2<T, Integer> c) {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
for (T i : palette.keySet()) {
|
for (T i : palette.keySet()) {
|
||||||
if (i == null) {
|
if (i == null) {
|
||||||
continue;
|
continue;
|
||||||
@@ -81,5 +89,8 @@ public class HashPalette<T> implements Palette<T> {
|
|||||||
|
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user