diff options
Diffstat (limited to 'patches/unapplied/server/0697-Allow-controlled-flushing-for-network-manager.patch')
-rw-r--r-- | patches/unapplied/server/0697-Allow-controlled-flushing-for-network-manager.patch | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/patches/unapplied/server/0697-Allow-controlled-flushing-for-network-manager.patch b/patches/unapplied/server/0697-Allow-controlled-flushing-for-network-manager.patch new file mode 100644 index 0000000000..77361f9f13 --- /dev/null +++ b/patches/unapplied/server/0697-Allow-controlled-flushing-for-network-manager.patch @@ -0,0 +1,150 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf <[email protected]> +Date: Sat, 4 Apr 2020 15:27:44 -0700 +Subject: [PATCH] Allow controlled flushing for network manager + +Only make one flush call when emptying the packet queue too + +This patch will be used to optimise out flush calls in later +patches. + +diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java +index 1404389f16cb6ed8bb1b2dad35e364b1428810a4..d7dd0b806d8d8e3f04f165a2b29097a5c1bcd199 100644 +--- a/src/main/java/net/minecraft/network/Connection.java ++++ b/src/main/java/net/minecraft/network/Connection.java +@@ -124,6 +124,39 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> { + public ConnectionProtocol protocol; + // Paper end + ++ // Paper start - allow controlled flushing ++ volatile boolean canFlush = true; ++ private final java.util.concurrent.atomic.AtomicInteger packetWrites = new java.util.concurrent.atomic.AtomicInteger(); ++ private int flushPacketsStart; ++ private final Object flushLock = new Object(); ++ ++ public void disableAutomaticFlush() { ++ synchronized (this.flushLock) { ++ this.flushPacketsStart = this.packetWrites.get(); // must be volatile and before canFlush = false ++ this.canFlush = false; ++ } ++ } ++ ++ public void enableAutomaticFlush() { ++ synchronized (this.flushLock) { ++ this.canFlush = true; ++ if (this.packetWrites.get() != this.flushPacketsStart) { // must be after canFlush = true ++ this.flush(); // only make the flush call if we need to ++ } ++ } ++ } ++ ++ private final void flush() { ++ if (this.channel.eventLoop().inEventLoop()) { ++ this.channel.flush(); ++ } else { ++ this.channel.eventLoop().execute(() -> { ++ this.channel.flush(); ++ }); ++ } ++ } ++ // Paper end - allow controlled flushing ++ + public Connection(PacketFlow side) { + this.receiving = side; + } +@@ -292,7 +325,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> { + io.papermc.paper.util.MCUtil.isMainThread() && packet.isReady() && this.queue.isEmpty() && + (packet.getExtraPackets() == null || packet.getExtraPackets().isEmpty()) + ))) { +- this.sendPacket(packet, callbacks); ++ this.sendPacket(packet, callbacks, null); // Paper + return; + } + // write the packets to the queue, then flush - antixray hooks there already +@@ -316,6 +349,14 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> { + } + + private void sendPacket(Packet<?> packet, @Nullable PacketSendListener callbacks) { ++ // Paper start - add flush parameter ++ this.sendPacket(packet, callbacks, Boolean.TRUE); ++ } ++ private void sendPacket(Packet<?> packet, @Nullable PacketSendListener callbacks, Boolean flushConditional) { ++ this.packetWrites.getAndIncrement(); // must be befeore using canFlush ++ boolean effectiveFlush = flushConditional == null ? this.canFlush : flushConditional.booleanValue(); ++ final boolean flush = effectiveFlush || packet instanceof net.minecraft.network.protocol.game.ClientboundKeepAlivePacket || packet instanceof ClientboundDisconnectPacket; // no delay for certain packets ++ // Paper end - add flush parameter + ConnectionProtocol enumprotocol = ConnectionProtocol.getProtocolForPacket(packet); + ConnectionProtocol enumprotocol1 = this.getCurrentProtocol(); + +@@ -330,16 +371,21 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> { + } + + if (this.channel.eventLoop().inEventLoop()) { +- this.doSendPacket(packet, callbacks, enumprotocol, enumprotocol1); ++ this.doSendPacket(packet, callbacks, enumprotocol, enumprotocol1, flush); // Paper + } else { + this.channel.eventLoop().execute(() -> { +- this.doSendPacket(packet, callbacks, enumprotocol, enumprotocol1); ++ this.doSendPacket(packet, callbacks, enumprotocol, enumprotocol1, flush); // Paper + }); + } + + } + + private void doSendPacket(Packet<?> packet, @Nullable PacketSendListener callbacks, ConnectionProtocol packetState, ConnectionProtocol currentState) { ++ // Paper start - add flush parameter ++ this.doSendPacket(packet, callbacks, packetState, currentState, true); ++ } ++ private void doSendPacket(Packet<?> packet, @Nullable PacketSendListener callbacks, ConnectionProtocol packetState, ConnectionProtocol currentState, boolean flush) { ++ // Paper end - add flush parameter + if (packetState != currentState) { + this.setProtocol(packetState); + } +@@ -353,7 +399,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> { + + try { + // Paper end +- ChannelFuture channelfuture = this.channel.writeAndFlush(packet); ++ ChannelFuture channelfuture = flush ? this.channel.writeAndFlush(packet) : this.channel.write(packet); // Paper - add flush parameter + + if (callbacks != null) { + channelfuture.addListener((future) -> { +@@ -409,6 +455,10 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> { + private boolean processQueue() { + try { // Paper - add pending task queue + if (this.queue.isEmpty()) return true; ++ // Paper start - make only one flush call per sendPacketQueue() call ++ final boolean needsFlush = this.canFlush; ++ boolean hasWrotePacket = false; ++ // Paper end - make only one flush call per sendPacketQueue() call + // If we are on main, we are safe here in that nothing else should be processing queue off main anymore + // But if we are not on main due to login/status, the parent is synchronized on packetQueue + java.util.Iterator<PacketHolder> iterator = this.queue.iterator(); +@@ -416,7 +466,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> { + PacketHolder queued = iterator.next(); // poll -> peek + + // Fix NPE (Spigot bug caused by handleDisconnection()) +- if (queued == null) { ++ if (false && queued == null) { // Paper - diff on change, this logic is redundant: iterator guarantees ret of an element - on change, hook the flush logic here + return true; + } + +@@ -428,11 +478,17 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> { + + Packet<?> packet = queued.packet; + if (!packet.isReady()) { ++ // Paper start - make only one flush call per sendPacketQueue() call ++ if (hasWrotePacket && (needsFlush || this.canFlush)) { ++ this.flush(); ++ } ++ // Paper end - make only one flush call per sendPacketQueue() call + return false; + } else { + iterator.remove(); + if (queued.tryMarkConsumed()) { // Paper - try to mark isConsumed flag for de-duplicating packet +- this.sendPacket(packet, queued.listener); ++ this.sendPacket(packet, queued.listener, (!iterator.hasNext() && (needsFlush || this.canFlush)) ? Boolean.TRUE : Boolean.FALSE); // Paper - make only one flush call per sendPacketQueue() call ++ hasWrotePacket = true; // Paper - make only one flush call per sendPacketQueue() call + } + } + } |