mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-07-01 23:47:21 +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");
|
||||
return;
|
||||
}
|
||||
if (chunkUpdater != null) {
|
||||
chunkUpdater.stop();
|
||||
}
|
||||
|
||||
chunkUpdater = new ChunkUpdater(world);
|
||||
if (sender().isPlayer()) {
|
||||
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")
|
||||
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;
|
||||
}
|
||||
public void pause( ) {
|
||||
if (chunkUpdater == null) {
|
||||
sender().sendMessage(C.GOLD + "You cant pause something that doesnt exist?");
|
||||
return;
|
||||
@ -68,40 +65,32 @@ public class CommandUpdater implements DecreeExecutor {
|
||||
boolean status = chunkUpdater.pause();
|
||||
if (sender().isPlayer()) {
|
||||
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 {
|
||||
sender().sendMessage(C.IRIS + "Unpause task for: " + C.GRAY + world.getName());
|
||||
sender().sendMessage(C.IRIS + "Unpause task for: " + C.GRAY + chunkUpdater.getName());
|
||||
}
|
||||
} else {
|
||||
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 {
|
||||
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")
|
||||
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;
|
||||
}
|
||||
public void stop() {
|
||||
if (chunkUpdater == null) {
|
||||
sender().sendMessage(C.GOLD + "You cant stop something that doesnt exist?");
|
||||
return;
|
||||
}
|
||||
if (sender().isPlayer()) {
|
||||
sender().sendMessage("Stopping Updater for: " + C.GRAY + world.getName());
|
||||
sender().sendMessage("Stopping Updater for: " + C.GRAY + chunkUpdater.getName());
|
||||
} else {
|
||||
Iris.info("Stopping Updater for: " + C.GRAY + world.getName());
|
||||
Iris.info("Stopping Updater for: " + C.GRAY + chunkUpdater.getName());
|
||||
}
|
||||
chunkUpdater.stop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -2,7 +2,9 @@ package com.volmit.iris.core.pregenerator;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
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.engine.data.cache.Cache;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.format.Form;
|
||||
@ -28,8 +30,7 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
public class ChunkUpdater {
|
||||
private final AtomicBoolean paused = new AtomicBoolean();
|
||||
private final AtomicBoolean cancelled = new AtomicBoolean();
|
||||
private final KMap<Chunk, Long> lastUse = new KMap<>();
|
||||
private final KMap<Chunk, AtomicInteger> counters = new KMap<>();
|
||||
private final KMap<Long, Pair<Long, AtomicInteger>> lastUse = new KMap<>();
|
||||
private final RollingSequence chunksPerSecond = new RollingSequence(5);
|
||||
private final AtomicInteger totalMaxChunks = new AtomicInteger();
|
||||
private final AtomicInteger chunksProcessed = new AtomicInteger();
|
||||
@ -58,6 +59,10 @@ public class ChunkUpdater {
|
||||
this.latch = new CountDownLatch(totalMaxChunks.get());
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return world.getName();
|
||||
}
|
||||
|
||||
public int getChunks() {
|
||||
return totalMaxChunks.get();
|
||||
}
|
||||
@ -83,7 +88,6 @@ public class ChunkUpdater {
|
||||
cancelled.set(true);
|
||||
}
|
||||
|
||||
|
||||
private void update() {
|
||||
Iris.info("Updating..");
|
||||
try {
|
||||
@ -192,9 +196,8 @@ public class ChunkUpdater {
|
||||
|
||||
for (int xx = -1; xx <= 1; xx++) {
|
||||
for (int zz = -1; zz <= 1; zz++) {
|
||||
var chunk = world.getChunkAt(x + xx, z + zz, false);
|
||||
var counter = counters.get(chunk);
|
||||
if (counter != null) counter.decrementAndGet();
|
||||
var counter = lastUse.get(Cache.key(x + xx, z + zz));
|
||||
if (counter != null) counter.getB().decrementAndGet();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
@ -243,9 +246,9 @@ public class ChunkUpdater {
|
||||
if (!c.isGenerated())
|
||||
generated.set(false);
|
||||
|
||||
counters.computeIfAbsent(c, k -> new AtomicInteger(-1))
|
||||
.updateAndGet(i -> i == -1 ? 1 : ++i);
|
||||
lastUse.put(c, M.ms());
|
||||
var pair = lastUse.computeIfAbsent(Cache.key(c), k -> new Pair<>(0L, new AtomicInteger(-1)));
|
||||
pair.setA(M.ms());
|
||||
pair.getB().updateAndGet(i -> i == -1 ? 1 : ++i);
|
||||
} finally {
|
||||
latch.countDown();
|
||||
}
|
||||
@ -262,15 +265,22 @@ public class ChunkUpdater {
|
||||
}
|
||||
|
||||
private synchronized void unloadChunks() {
|
||||
for (Chunk i : new ArrayList<>(lastUse.keySet())) {
|
||||
Long lastUseTime = lastUse.get(i);
|
||||
var counter = counters.get(i);
|
||||
if (lastUseTime != null && M.ms() - lastUseTime >= 5000 && (counter == null || counter.get() == 0)) {
|
||||
for (var key : new ArrayList<>(lastUse.keySet())) {
|
||||
if (key == null) continue;
|
||||
var pair = lastUse.get(key);
|
||||
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(() -> {
|
||||
i.removePluginChunkTicket(Iris.instance);
|
||||
i.unload();
|
||||
lastUse.remove(i);
|
||||
counters.remove(i);
|
||||
world.removePluginChunkTicket(x, z, Iris.instance);
|
||||
world.unloadChunk(x, z);
|
||||
lastUse.remove(key);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -82,6 +82,7 @@ import java.awt.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
@ -289,23 +290,25 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
||||
return;
|
||||
}
|
||||
|
||||
if (mantle.hasFlag(c.getX(), c.getZ(), MantleFlag.ETCHED)) return;
|
||||
mantle.flag(c.getX(), c.getZ(), MantleFlag.ETCHED, true);
|
||||
var chunk = mantle.getChunk(c);
|
||||
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) -> {
|
||||
int betterY = y + getWorld().minHeight();
|
||||
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());
|
||||
});
|
||||
}).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) -> {
|
||||
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();
|
||||
KMap<Long, Integer> updates = new KMap<>();
|
||||
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);
|
||||
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
|
||||
|
@ -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