Overall performance improvement

This commit is contained in:
TheMode 2021-04-09 05:40:40 +02:00
parent c2f302ad0e
commit 01d233f7d8
8 changed files with 69 additions and 27 deletions

View File

@ -4,8 +4,10 @@ import com.google.common.collect.Queues;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.InstanceManager;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.player.NettyPlayerConnection;
import net.minestom.server.thread.PerInstanceThreadProvider;
import net.minestom.server.thread.ThreadProvider;
import net.minestom.server.utils.async.AsyncUtils;
import org.jetbrains.annotations.NotNull;
import java.util.List;
@ -80,6 +82,12 @@ public final class UpdateManager {
// Tick end callbacks
doTickCallback(tickEndCallbacks, tickTime / 1000000L);
// Flush all waiting packets
AsyncUtils.runAsync(() -> connectionManager.getOnlinePlayers().stream()
.filter(player -> player.getPlayerConnection() instanceof NettyPlayerConnection)
.map(player -> (NettyPlayerConnection) player.getPlayerConnection())
.forEach(NettyPlayerConnection::flush));
} catch (Exception e) {
MinecraftServer.getExceptionManager().handleException(e);
}

View File

@ -1,8 +1,5 @@
package net.minestom.server.instance;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectMaps;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import net.minestom.server.MinecraftServer;
import net.minestom.server.data.Data;
import net.minestom.server.data.SerializableData;
@ -34,6 +31,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
@ -56,7 +54,7 @@ public class InstanceContainer extends Instance {
// the chunk generator used, can be null
private ChunkGenerator chunkGenerator;
// (chunk index -> chunk) map, contains all the chunks in the instance
private final Long2ObjectMap<Chunk> chunks = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>());
private final Map<Long, Chunk> chunks = new ConcurrentHashMap<>();
// contains all the chunks to remove during the next instance tick, should be synchronized
protected final Set<Chunk> scheduledChunksToRemove = new HashSet<>();

View File

@ -19,6 +19,7 @@ import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.cache.CacheablePacket;
import net.minestom.server.utils.cache.TemporaryCache;
import net.minestom.server.utils.cache.TemporaryPacketCache;
import net.minestom.server.utils.cache.TimedBuffer;
import net.minestom.server.utils.chunk.ChunkUtils;
import net.minestom.server.world.biomes.Biome;
@ -34,8 +35,7 @@ import java.util.concurrent.TimeUnit;
public class ChunkDataPacket implements ServerPacket, CacheablePacket {
private static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager();
private static final TemporaryCache<TimedBuffer> CACHE = new TemporaryCache<>(5, TimeUnit.MINUTES,
notification -> notification.getValue().getBuffer().release());
private static final TemporaryCache<TimedBuffer> CACHE = new TemporaryPacketCache(5, TimeUnit.MINUTES);
public boolean fullChunk;
public Biome[] biomes;

View File

@ -6,6 +6,7 @@ import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.cache.CacheablePacket;
import net.minestom.server.utils.cache.TemporaryCache;
import net.minestom.server.utils.cache.TemporaryPacketCache;
import net.minestom.server.utils.cache.TimedBuffer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -17,8 +18,7 @@ import java.util.concurrent.TimeUnit;
public class UpdateLightPacket implements ServerPacket, CacheablePacket {
private static final TemporaryCache<TimedBuffer> CACHE = new TemporaryCache<>(5, TimeUnit.MINUTES,
notification -> notification.getValue().getBuffer().release());
private static final TemporaryCache<TimedBuffer> CACHE = new TemporaryPacketCache(5, TimeUnit.MINUTES);
public int chunkX;
public int chunkZ;
@ -102,7 +102,7 @@ public class UpdateLightPacket implements ServerPacket, CacheablePacket {
skyLight.clear();
for (int i = 0; i < 14; i++) {
int length = reader.readVarInt();
if(length != 2048) {
if (length != 2048) {
throw new IllegalStateException("Length must be 2048.");
}
@ -114,7 +114,7 @@ public class UpdateLightPacket implements ServerPacket, CacheablePacket {
blockLight.clear();
for (int i = 0; i < 6; i++) {
int length = reader.readVarInt();
if(length != 2048) {
if (length != 2048) {
throw new IllegalStateException("Length must be 2048.");
}

View File

@ -71,22 +71,6 @@ public class NettyPlayerConnection extends PlayerConnection {
this.tickBuffer.ensureWritable(INITIAL_BUFFER_SIZE);
}
@Override
public void update() {
// Flush
final int bufferSize = tickBuffer.writerIndex();
if (bufferSize > 0) {
this.channel.eventLoop().submit(() -> {
if (channel.isActive()) {
writeWaitingPackets();
channel.flush();
}
});
}
// Network stats
super.update();
}
/**
* Sets the encryption key and add the codecs to the pipeline.
*
@ -196,7 +180,7 @@ public class NettyPlayerConnection extends PlayerConnection {
}
}
private void writeWaitingPackets() {
public void writeWaitingPackets() {
if (tickBuffer.writerIndex() == 0) {
// Nothing to write
return;
@ -221,6 +205,16 @@ public class NettyPlayerConnection extends PlayerConnection {
}
}
public void flush() {
final int bufferSize = tickBuffer.writerIndex();
if (bufferSize > 0) {
if (channel.isActive()) {
writeWaitingPackets();
channel.flush();
}
}
}
@NotNull
@Override
public SocketAddress getRemoteAddress() {

View File

@ -46,6 +46,9 @@ public interface CacheablePacket {
@Nullable
static FramedPacket getCache(@NotNull ServerPacket serverPacket) {
if (!(serverPacket instanceof CacheablePacket))
return null;
final CacheablePacket cacheablePacket = (CacheablePacket) serverPacket;
final UUID identifier = cacheablePacket.getIdentifier();
if (identifier == null) {
@ -72,4 +75,20 @@ public interface CacheablePacket {
}
}
static void writeCache(@NotNull ByteBuf buffer, @NotNull ServerPacket serverPacket) {
FramedPacket framedPacket = CacheablePacket.getCache(serverPacket);
if (framedPacket == null) {
PacketUtils.writeFramedPacket(buffer, serverPacket);
return;
}
final ByteBuf body = framedPacket.getBody();
synchronized (body) {
if (framedPacket.getBody().refCnt() != 0) {
buffer.writeBytes(body, body.readerIndex(), body.readableBytes());
} else {
PacketUtils.writeFramedPacket(buffer, serverPacket);
}
}
}
}

View File

@ -0,0 +1,16 @@
package net.minestom.server.utils.cache;
import io.netty.buffer.ByteBuf;
import java.util.concurrent.TimeUnit;
public class TemporaryPacketCache extends TemporaryCache<TimedBuffer> {
public TemporaryPacketCache(long duration, TimeUnit timeUnit) {
super(duration, timeUnit, notification -> {
final ByteBuf buffer = notification.getValue().getBuffer();
synchronized (buffer) {
buffer.release();
}
});
}
}

View File

@ -37,6 +37,13 @@ public final class Check {
}
}
@Contract("true, _, _ -> fail")
public static void argCondition(boolean condition, @NotNull String reason, Object... arguments) {
if (condition) {
throw new IllegalArgumentException(MessageFormat.format(reason, arguments));
}
}
@Contract("_ -> fail")
public static void fail(@NotNull String reason) {
throw new IllegalArgumentException(reason);