mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-07-02 07:56:48 +00:00
updater fixes
This commit is contained in:
parent
11ae48bea1
commit
a1495a10e5
@ -43,6 +43,10 @@ public class CommandUpdater implements DecreeExecutor {
|
|||||||
sender().sendMessage(C.GOLD + "This is not an Iris world");
|
sender().sendMessage(C.GOLD + "This is not an Iris world");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (chunkUpdater != null) {
|
||||||
|
chunkUpdater.stop();
|
||||||
|
}
|
||||||
|
|
||||||
chunkUpdater = new ChunkUpdater(world);
|
chunkUpdater = new ChunkUpdater(world);
|
||||||
if (sender().isPlayer()) {
|
if (sender().isPlayer()) {
|
||||||
sender().sendMessage(C.GREEN + "Updating " + world.getName() + C.GRAY + " Total chunks: " + Form.f(chunkUpdater.getChunks()));
|
sender().sendMessage(C.GREEN + "Updating " + world.getName() + C.GRAY + " Total chunks: " + Form.f(chunkUpdater.getChunks()));
|
||||||
@ -53,14 +57,7 @@ public class CommandUpdater implements DecreeExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Decree(description = "Pause the updater")
|
@Decree(description = "Pause the updater")
|
||||||
public void pause(
|
public void pause( ) {
|
||||||
@Param(description = "World to pause the Updater at")
|
|
||||||
World world
|
|
||||||
) {
|
|
||||||
if (!IrisToolbelt.isIrisWorld(world)) {
|
|
||||||
sender().sendMessage(C.GOLD + "This is not an Iris world");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (chunkUpdater == null) {
|
if (chunkUpdater == null) {
|
||||||
sender().sendMessage(C.GOLD + "You cant pause something that doesnt exist?");
|
sender().sendMessage(C.GOLD + "You cant pause something that doesnt exist?");
|
||||||
return;
|
return;
|
||||||
@ -68,40 +65,32 @@ public class CommandUpdater implements DecreeExecutor {
|
|||||||
boolean status = chunkUpdater.pause();
|
boolean status = chunkUpdater.pause();
|
||||||
if (sender().isPlayer()) {
|
if (sender().isPlayer()) {
|
||||||
if (status) {
|
if (status) {
|
||||||
sender().sendMessage(C.IRIS + "Paused task for: " + C.GRAY + world.getName());
|
sender().sendMessage(C.IRIS + "Paused task for: " + C.GRAY + chunkUpdater.getName());
|
||||||
} else {
|
} else {
|
||||||
sender().sendMessage(C.IRIS + "Unpause task for: " + C.GRAY + world.getName());
|
sender().sendMessage(C.IRIS + "Unpause task for: " + C.GRAY + chunkUpdater.getName());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (status) {
|
if (status) {
|
||||||
Iris.info(C.IRIS + "Paused task for: " + C.GRAY + world.getName());
|
Iris.info(C.IRIS + "Paused task for: " + C.GRAY + chunkUpdater.getName());
|
||||||
} else {
|
} else {
|
||||||
Iris.info(C.IRIS + "Unpause task for: " + C.GRAY + world.getName());
|
Iris.info(C.IRIS + "Unpause task for: " + C.GRAY + chunkUpdater.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Decree(description = "Stops the updater")
|
@Decree(description = "Stops the updater")
|
||||||
public void stop(
|
public void stop() {
|
||||||
@Param(description = "World to stop the Updater at")
|
|
||||||
World world
|
|
||||||
) {
|
|
||||||
if (!IrisToolbelt.isIrisWorld(world)) {
|
|
||||||
sender().sendMessage(C.GOLD + "This is not an Iris world");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (chunkUpdater == null) {
|
if (chunkUpdater == null) {
|
||||||
sender().sendMessage(C.GOLD + "You cant stop something that doesnt exist?");
|
sender().sendMessage(C.GOLD + "You cant stop something that doesnt exist?");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (sender().isPlayer()) {
|
if (sender().isPlayer()) {
|
||||||
sender().sendMessage("Stopping Updater for: " + C.GRAY + world.getName());
|
sender().sendMessage("Stopping Updater for: " + C.GRAY + chunkUpdater.getName());
|
||||||
} else {
|
} else {
|
||||||
Iris.info("Stopping Updater for: " + C.GRAY + world.getName());
|
Iris.info("Stopping Updater for: " + C.GRAY + chunkUpdater.getName());
|
||||||
}
|
}
|
||||||
chunkUpdater.stop();
|
chunkUpdater.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,7 +2,9 @@ package com.volmit.iris.core.pregenerator;
|
|||||||
|
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.core.IrisSettings;
|
import com.volmit.iris.core.IrisSettings;
|
||||||
|
import com.volmit.iris.core.nms.container.Pair;
|
||||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
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.framework.Engine;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
import com.volmit.iris.util.collection.KMap;
|
||||||
import com.volmit.iris.util.format.Form;
|
import com.volmit.iris.util.format.Form;
|
||||||
@ -28,8 +30,7 @@ import java.util.concurrent.atomic.AtomicLong;
|
|||||||
public class ChunkUpdater {
|
public class ChunkUpdater {
|
||||||
private final AtomicBoolean paused = new AtomicBoolean();
|
private final AtomicBoolean paused = new AtomicBoolean();
|
||||||
private final AtomicBoolean cancelled = new AtomicBoolean();
|
private final AtomicBoolean cancelled = new AtomicBoolean();
|
||||||
private final KMap<Chunk, Long> lastUse = new KMap<>();
|
private final KMap<Long, Pair<Long, AtomicInteger>> lastUse = new KMap<>();
|
||||||
private final KMap<Chunk, AtomicInteger> counters = new KMap<>();
|
|
||||||
private final RollingSequence chunksPerSecond = new RollingSequence(5);
|
private final RollingSequence chunksPerSecond = new RollingSequence(5);
|
||||||
private final AtomicInteger totalMaxChunks = new AtomicInteger();
|
private final AtomicInteger totalMaxChunks = new AtomicInteger();
|
||||||
private final AtomicInteger chunksProcessed = new AtomicInteger();
|
private final AtomicInteger chunksProcessed = new AtomicInteger();
|
||||||
@ -58,6 +59,10 @@ public class ChunkUpdater {
|
|||||||
this.latch = new CountDownLatch(totalMaxChunks.get());
|
this.latch = new CountDownLatch(totalMaxChunks.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return world.getName();
|
||||||
|
}
|
||||||
|
|
||||||
public int getChunks() {
|
public int getChunks() {
|
||||||
return totalMaxChunks.get();
|
return totalMaxChunks.get();
|
||||||
}
|
}
|
||||||
@ -83,7 +88,6 @@ public class ChunkUpdater {
|
|||||||
cancelled.set(true);
|
cancelled.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void update() {
|
private void update() {
|
||||||
Iris.info("Updating..");
|
Iris.info("Updating..");
|
||||||
try {
|
try {
|
||||||
@ -192,9 +196,8 @@ public class ChunkUpdater {
|
|||||||
|
|
||||||
for (int xx = -1; xx <= 1; xx++) {
|
for (int xx = -1; xx <= 1; xx++) {
|
||||||
for (int zz = -1; zz <= 1; zz++) {
|
for (int zz = -1; zz <= 1; zz++) {
|
||||||
var chunk = world.getChunkAt(x + xx, z + zz, false);
|
var counter = lastUse.get(Cache.key(x + xx, z + zz));
|
||||||
var counter = counters.get(chunk);
|
if (counter != null) counter.getB().decrementAndGet();
|
||||||
if (counter != null) counter.decrementAndGet();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@ -243,9 +246,9 @@ public class ChunkUpdater {
|
|||||||
if (!c.isGenerated())
|
if (!c.isGenerated())
|
||||||
generated.set(false);
|
generated.set(false);
|
||||||
|
|
||||||
counters.computeIfAbsent(c, k -> new AtomicInteger(-1))
|
var pair = lastUse.computeIfAbsent(Cache.key(c), k -> new Pair<>(0L, new AtomicInteger(-1)));
|
||||||
.updateAndGet(i -> i == -1 ? 1 : ++i);
|
pair.setA(M.ms());
|
||||||
lastUse.put(c, M.ms());
|
pair.getB().updateAndGet(i -> i == -1 ? 1 : ++i);
|
||||||
} finally {
|
} finally {
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
}
|
}
|
||||||
@ -262,15 +265,22 @@ public class ChunkUpdater {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void unloadChunks() {
|
private synchronized void unloadChunks() {
|
||||||
for (Chunk i : new ArrayList<>(lastUse.keySet())) {
|
for (var key : new ArrayList<>(lastUse.keySet())) {
|
||||||
Long lastUseTime = lastUse.get(i);
|
if (key == null) continue;
|
||||||
var counter = counters.get(i);
|
var pair = lastUse.get(key);
|
||||||
if (lastUseTime != null && M.ms() - lastUseTime >= 5000 && (counter == null || counter.get() == 0)) {
|
if (pair == null) continue;
|
||||||
|
var lastUseTime = pair.getA();
|
||||||
|
var counter = pair.getB();
|
||||||
|
if (lastUseTime == null || counter == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (M.ms() - lastUseTime >= 5000 && counter.get() == 0) {
|
||||||
|
int x = Cache.keyX(key);
|
||||||
|
int z = Cache.keyZ(key);
|
||||||
J.s(() -> {
|
J.s(() -> {
|
||||||
i.removePluginChunkTicket(Iris.instance);
|
world.removePluginChunkTicket(x, z, Iris.instance);
|
||||||
i.unload();
|
world.unloadChunk(x, z);
|
||||||
lastUse.remove(i);
|
lastUse.remove(key);
|
||||||
counters.remove(i);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,6 +82,7 @@ import java.awt.*;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
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;
|
||||||
@ -289,23 +290,25 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mantle.hasFlag(c.getX(), c.getZ(), MantleFlag.ETCHED)) return;
|
var chunk = mantle.getChunk(c);
|
||||||
mantle.flag(c.getX(), c.getZ(), MantleFlag.ETCHED, true);
|
if (chunk.isFlagged(MantleFlag.ETCHED)) return;
|
||||||
|
chunk.flag(MantleFlag.ETCHED, true);
|
||||||
|
|
||||||
mantle.raiseFlag(c.getX(), c.getZ(), MantleFlag.TILE, () -> J.sfut(() -> {
|
Semaphore semaphore = new Semaphore(3);
|
||||||
|
chunk.raiseFlag(MantleFlag.TILE, run(semaphore, () -> J.s(() -> {
|
||||||
mantle.iterateChunk(c.getX(), c.getZ(), TileWrapper.class, (x, y, z, v) -> {
|
mantle.iterateChunk(c.getX(), c.getZ(), TileWrapper.class, (x, y, z, v) -> {
|
||||||
int betterY = y + getWorld().minHeight();
|
int betterY = y + getWorld().minHeight();
|
||||||
if (!TileData.setTileState(c.getBlock(x, betterY, z), v.getData()))
|
if (!TileData.setTileState(c.getBlock(x, betterY, z), v.getData()))
|
||||||
Iris.warn("Failed to set tile entity data at [%d %d %d | %s] for tile %s!", x, betterY, z, c.getBlock(x, betterY, z).getBlockData().getMaterial().getKey(), v.getData().getMaterial().name());
|
Iris.warn("Failed to set tile entity data at [%d %d %d | %s] for tile %s!", x, betterY, z, c.getBlock(x, betterY, z).getBlockData().getMaterial().getKey(), v.getData().getMaterial().name());
|
||||||
});
|
});
|
||||||
}).join());
|
})));
|
||||||
mantle.raiseFlag(c.getX(), c.getZ(), MantleFlag.CUSTOM, () -> J.sfut(() -> {
|
chunk.raiseFlag(MantleFlag.CUSTOM, run(semaphore, () -> J.s(() -> {
|
||||||
mantle.iterateChunk(c.getX(), c.getZ(), Identifier.class, (x, y, z, v) -> {
|
mantle.iterateChunk(c.getX(), c.getZ(), Identifier.class, (x, y, z, v) -> {
|
||||||
Iris.service(ExternalDataSVC.class).processUpdate(this, c.getBlock(x & 15, y + getWorld().minHeight(), z & 15), v);
|
Iris.service(ExternalDataSVC.class).processUpdate(this, c.getBlock(x & 15, y + getWorld().minHeight(), z & 15), v);
|
||||||
});
|
});
|
||||||
}).join());
|
})));
|
||||||
|
|
||||||
mantle.raiseFlag(c.getX(), c.getZ(), MantleFlag.UPDATE, () -> J.sfut(() -> {
|
chunk.raiseFlag(MantleFlag.UPDATE, run(semaphore, () -> J.s(() -> {
|
||||||
PrecisionStopwatch p = PrecisionStopwatch.start();
|
PrecisionStopwatch p = PrecisionStopwatch.start();
|
||||||
KMap<Long, Integer> updates = new KMap<>();
|
KMap<Long, Integer> updates = new KMap<>();
|
||||||
RNG r = new RNG(Cache.key(c.getX(), c.getZ()));
|
RNG r = new RNG(Cache.key(c.getX(), c.getZ()));
|
||||||
@ -352,7 +355,23 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
|||||||
});
|
});
|
||||||
mantle.deleteChunkSlice(c.getX(), c.getZ(), MatterUpdate.class);
|
mantle.deleteChunkSlice(c.getX(), c.getZ(), MatterUpdate.class);
|
||||||
getMetrics().getUpdates().put(p.getMilliseconds());
|
getMetrics().getUpdates().put(p.getMilliseconds());
|
||||||
}, RNG.r.i(0, 20)).join());
|
}, RNG.r.i(0, 20))));
|
||||||
|
|
||||||
|
try {
|
||||||
|
semaphore.acquire(3);
|
||||||
|
} catch (InterruptedException ignored) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Runnable run(Semaphore semaphore, Runnable runnable) {
|
||||||
|
return () -> {
|
||||||
|
if (!semaphore.tryAcquire())
|
||||||
|
return;
|
||||||
|
try {
|
||||||
|
runnable.run();
|
||||||
|
} finally {
|
||||||
|
semaphore.release();
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@BlockCoordinates
|
@BlockCoordinates
|
||||||
|
@ -0,0 +1,70 @@
|
|||||||
|
package com.volmit.iris.util.profile;
|
||||||
|
|
||||||
|
|
||||||
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.core.IrisSettings;
|
||||||
|
import com.volmit.iris.util.math.M;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class LoadBalancer extends MsptTimings {
|
||||||
|
private final Semaphore semaphore;
|
||||||
|
private final int maxPermits;
|
||||||
|
private final double range;
|
||||||
|
@Setter
|
||||||
|
private int minMspt, maxMspt;
|
||||||
|
private int permits, lastMspt;
|
||||||
|
private long lastTime = M.ms();
|
||||||
|
|
||||||
|
public LoadBalancer(Semaphore semaphore, int maxPermits, IrisSettings.MsRange range) {
|
||||||
|
this(semaphore, maxPermits, range.getMin(), range.getMax());
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoadBalancer(Semaphore semaphore, int maxPermits, int minMspt, int maxMspt) {
|
||||||
|
this.semaphore = semaphore;
|
||||||
|
this.maxPermits = maxPermits;
|
||||||
|
this.minMspt = minMspt;
|
||||||
|
this.maxMspt = maxMspt;
|
||||||
|
this.range = maxMspt - minMspt;
|
||||||
|
setName("LoadBalancer");
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void update(int raw) {
|
||||||
|
lastTime = M.ms();
|
||||||
|
int mspt = raw;
|
||||||
|
if (mspt < lastMspt) {
|
||||||
|
int min = (int) Math.max(lastMspt * IrisSettings.get().getUpdater().getChunkLoadSensitivity(), 1);
|
||||||
|
mspt = Math.max(mspt, min);
|
||||||
|
}
|
||||||
|
lastMspt = mspt;
|
||||||
|
mspt = Math.max(mspt - minMspt, 0);
|
||||||
|
double percent = mspt / range;
|
||||||
|
|
||||||
|
int target = (int) (maxPermits * percent);
|
||||||
|
target = Math.min(target, maxPermits - 20);
|
||||||
|
|
||||||
|
int diff = target - permits;
|
||||||
|
permits = target;
|
||||||
|
|
||||||
|
if (diff == 0) return;
|
||||||
|
Iris.debug("Adjusting load to %s (%s) permits (%s mspt, %.2f)".formatted(target, diff, raw, percent));
|
||||||
|
|
||||||
|
if (diff > 0) semaphore.acquireUninterruptibly(diff);
|
||||||
|
else semaphore.release(Math.abs(diff));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
interrupt();
|
||||||
|
semaphore.release(permits);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRange(IrisSettings.MsRange range) {
|
||||||
|
minMspt = range.getMin();
|
||||||
|
maxMspt = range.getMax();
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user