Implement missing writabilityChanged() and add backlog logging with BACKPRESSURE_LOG to all writabilityChanged() implementations. (#1745)

This commit is contained in:
Wouter Gritter
2026-03-18 19:23:01 +01:00
committed by GitHub
parent 5017f8c9f2
commit 99bd030996
3 changed files with 59 additions and 0 deletions

View File

@@ -60,6 +60,7 @@ import com.velocitypowered.proxy.protocol.packet.config.TagsUpdatePacket;
import com.velocitypowered.proxy.protocol.util.PluginMessageUtil; import com.velocitypowered.proxy.protocol.util.PluginMessageUtil;
import io.netty.buffer.ByteBufUtil; import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import java.io.IOException; import java.io.IOException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@@ -72,6 +73,9 @@ import org.apache.logging.log4j.Logger;
* 1.20.2+ switching. Yes, some of this is exceptionally stupid. * 1.20.2+ switching. Yes, some of this is exceptionally stupid.
*/ */
public class ConfigSessionHandler implements MinecraftSessionHandler { public class ConfigSessionHandler implements MinecraftSessionHandler {
private static final boolean BACKPRESSURE_LOG =
Boolean.getBoolean("velocity.log-server-backpressure");
private static final Logger logger = LogManager.getLogger(ConfigSessionHandler.class); private static final Logger logger = LogManager.getLogger(ConfigSessionHandler.class);
private final VelocityServer server; private final VelocityServer server;
private final VelocityServerConnection serverConn; private final VelocityServerConnection serverConn;
@@ -382,6 +386,22 @@ public class ConfigSessionHandler implements MinecraftSessionHandler {
serverConn.getPlayer().getConnection().write(packet); serverConn.getPlayer().getConnection().write(packet);
} }
@Override
public void writabilityChanged() {
Channel serverChan = serverConn.ensureConnected().getChannel();
boolean writable = serverChan.isWritable();
if (BACKPRESSURE_LOG) {
if (writable) {
logger.info("{} is writable, will auto-read player connection data", this.serverConn);
} else {
logger.info("{} is not writable, not auto-reading player connection data", this.serverConn);
}
}
serverConn.getPlayer().getConnection().setAutoReading(writable);
}
private void switchFailure(Throwable cause) { private void switchFailure(Throwable cause) {
logger.error("Unable to switch to new server {} for {}", serverConn.getServerInfo().getName(), logger.error("Unable to switch to new server {} for {}", serverConn.getServerInfo().getName(),
serverConn.getPlayer().getUsername(), cause); serverConn.getPlayer().getUsername(), cause);

View File

@@ -60,6 +60,8 @@ import org.apache.logging.log4j.Logger;
* Handles the client config stage. * Handles the client config stage.
*/ */
public class ClientConfigSessionHandler implements MinecraftSessionHandler { public class ClientConfigSessionHandler implements MinecraftSessionHandler {
private static final boolean BACKPRESSURE_LOG =
Boolean.getBoolean("velocity.log-server-backpressure");
private static final Logger logger = LogManager.getLogger(ClientConfigSessionHandler.class); private static final Logger logger = LogManager.getLogger(ClientConfigSessionHandler.class);
private final VelocityServer server; private final VelocityServer server;
@@ -268,6 +270,33 @@ public class ClientConfigSessionHandler implements MinecraftSessionHandler {
player.disconnect(Component.translatable("velocity.error.player-connection-error", NamedTextColor.RED)); player.disconnect(Component.translatable("velocity.error.player-connection-error", NamedTextColor.RED));
} }
@Override
public void writabilityChanged() {
final boolean writable = player.getConnection().getChannel().isWritable();
if (BACKPRESSURE_LOG) {
if (writable) {
logger.info("{} is writable, will auto-read backend connection data", player);
} else {
logger.info("{} is not writable, not auto-reading backend connection data", player);
}
}
if (!writable) {
// Flush pending packets to free up memory. Schedule on a future event loop invocation
// to avoid disabling auto-read while the flush resolves backpressure.
player.getConnection().eventLoop().execute(() -> player.getConnection().flush());
}
final VelocityServerConnection serverConn = player.getConnectionInFlightOrConnectedServer();
if (serverConn != null) {
final MinecraftConnection smc = serverConn.getConnection();
if (smc != null) {
smc.setAutoReading(writable);
}
}
}
/** /**
* Calls the {@link PlayerConfigurationEvent}. * Calls the {@link PlayerConfigurationEvent}.
* For 1.20.5+ backends this is done when the client responds to * For 1.20.5+ backends this is done when the client responds to

View File

@@ -98,6 +98,8 @@ import org.checkerframework.checker.nullness.qual.Nullable;
* center that joins backend servers with players. * center that joins backend servers with players.
*/ */
public class ClientPlaySessionHandler implements MinecraftSessionHandler { public class ClientPlaySessionHandler implements MinecraftSessionHandler {
private static final boolean BACKPRESSURE_LOG =
Boolean.getBoolean("velocity.log-server-backpressure");
private static final Logger logger = LogManager.getLogger(ClientPlaySessionHandler.class); private static final Logger logger = LogManager.getLogger(ClientPlaySessionHandler.class);
@@ -505,6 +507,14 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
public void writabilityChanged() { public void writabilityChanged() {
boolean writable = player.getConnection().getChannel().isWritable(); boolean writable = player.getConnection().getChannel().isWritable();
if (BACKPRESSURE_LOG) {
if (writable) {
logger.info("{} is writable, will auto-read backend connection data", player);
} else {
logger.info("{} is not writable, not auto-reading backend connection data", player);
}
}
if (!writable) { if (!writable) {
// We might have packets queued from the server, so flush them now to free up memory. Make // We might have packets queued from the server, so flush them now to free up memory. Make
// sure to do it on a future invocation of the event loop, otherwise while the issue will // sure to do it on a future invocation of the event loop, otherwise while the issue will