#3451: Improve length field prepending on bungee -> server connection
Use alternative implementation of Varint21LengthFieldPrepender on bungee -> server connection for improved speed - it uses separate buffer to prepend the length to avoid copying large data buffer. Not applied bungee -> client because encrypting 1-5 bytes of length separately through expensive jni call could make it not worth (not measured).
This commit is contained in:
parent
2e6f0dd442
commit
2ef5e7004b
@ -0,0 +1,25 @@
|
|||||||
|
package net.md_5.bungee.protocol;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.channel.ChannelHandler;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepend length of the message as a Varint21 using an extra buffer for the length, avoiding copying packet data
|
||||||
|
*/
|
||||||
|
@ChannelHandler.Sharable
|
||||||
|
public class Varint21LengthFieldExtraBufPrepender extends MessageToMessageEncoder<ByteBuf>
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception
|
||||||
|
{
|
||||||
|
int bodyLen = msg.readableBytes();
|
||||||
|
ByteBuf lenBuf = ctx.alloc().ioBuffer( Varint21LengthFieldPrepender.varintSize( bodyLen ) );
|
||||||
|
DefinedPacket.writeVarInt( bodyLen, lenBuf );
|
||||||
|
out.add( lenBuf );
|
||||||
|
out.add( msg.retain() );
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,9 @@ import io.netty.channel.ChannelHandler;
|
|||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.MessageToByteEncoder;
|
import io.netty.handler.codec.MessageToByteEncoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepend length of the message as a Varint21 by writing length and data to a new buffer
|
||||||
|
*/
|
||||||
@ChannelHandler.Sharable
|
@ChannelHandler.Sharable
|
||||||
public class Varint21LengthFieldPrepender extends MessageToByteEncoder<ByteBuf>
|
public class Varint21LengthFieldPrepender extends MessageToByteEncoder<ByteBuf>
|
||||||
{
|
{
|
||||||
@ -20,7 +23,7 @@ public class Varint21LengthFieldPrepender extends MessageToByteEncoder<ByteBuf>
|
|||||||
out.writeBytes( msg );
|
out.writeBytes( msg );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int varintSize(int paramInt)
|
static int varintSize(int paramInt)
|
||||||
{
|
{
|
||||||
if ( ( paramInt & 0xFFFFFF80 ) == 0 )
|
if ( ( paramInt & 0xFFFFFF80 ) == 0 )
|
||||||
{
|
{
|
||||||
|
@ -182,7 +182,7 @@ public class BungeeServerInfo implements ServerInfo
|
|||||||
new Bootstrap()
|
new Bootstrap()
|
||||||
.channel( PipelineUtils.getChannel( socketAddress ) )
|
.channel( PipelineUtils.getChannel( socketAddress ) )
|
||||||
.group( BungeeCord.getInstance().eventLoops )
|
.group( BungeeCord.getInstance().eventLoops )
|
||||||
.handler( PipelineUtils.BASE )
|
.handler( PipelineUtils.BASE_SERVERSIDE )
|
||||||
.option( ChannelOption.CONNECT_TIMEOUT_MILLIS, BungeeCord.getInstance().getConfig().getRemotePingTimeout() )
|
.option( ChannelOption.CONNECT_TIMEOUT_MILLIS, BungeeCord.getInstance().getConfig().getRemotePingTimeout() )
|
||||||
.remoteAddress( socketAddress )
|
.remoteAddress( socketAddress )
|
||||||
.connect()
|
.connect()
|
||||||
|
@ -320,7 +320,7 @@ public final class UserConnection implements ProxiedPlayer
|
|||||||
@Override
|
@Override
|
||||||
protected void initChannel(Channel ch) throws Exception
|
protected void initChannel(Channel ch) throws Exception
|
||||||
{
|
{
|
||||||
PipelineUtils.BASE.initChannel( ch );
|
PipelineUtils.BASE_SERVERSIDE.initChannel( ch );
|
||||||
ch.pipeline().addAfter( PipelineUtils.FRAME_DECODER, PipelineUtils.PACKET_DECODER, new MinecraftDecoder( Protocol.HANDSHAKE, false, getPendingConnection().getVersion() ) );
|
ch.pipeline().addAfter( PipelineUtils.FRAME_DECODER, PipelineUtils.PACKET_DECODER, new MinecraftDecoder( Protocol.HANDSHAKE, false, getPendingConnection().getVersion() ) );
|
||||||
ch.pipeline().addAfter( PipelineUtils.FRAME_PREPENDER, PipelineUtils.PACKET_ENCODER, new MinecraftEncoder( Protocol.HANDSHAKE, false, getPendingConnection().getVersion() ) );
|
ch.pipeline().addAfter( PipelineUtils.FRAME_PREPENDER, PipelineUtils.PACKET_ENCODER, new MinecraftEncoder( Protocol.HANDSHAKE, false, getPendingConnection().getVersion() ) );
|
||||||
ch.pipeline().get( HandlerBoss.class ).setHandler( new ServerConnector( bungee, UserConnection.this, target ) );
|
ch.pipeline().get( HandlerBoss.class ).setHandler( new ServerConnector( bungee, UserConnection.this, target ) );
|
||||||
|
@ -30,6 +30,8 @@ import java.net.SocketAddress;
|
|||||||
import java.util.concurrent.ThreadFactory;
|
import java.util.concurrent.ThreadFactory;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
import net.md_5.bungee.BungeeCord;
|
import net.md_5.bungee.BungeeCord;
|
||||||
import net.md_5.bungee.Util;
|
import net.md_5.bungee.Util;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
@ -42,6 +44,7 @@ import net.md_5.bungee.protocol.MinecraftDecoder;
|
|||||||
import net.md_5.bungee.protocol.MinecraftEncoder;
|
import net.md_5.bungee.protocol.MinecraftEncoder;
|
||||||
import net.md_5.bungee.protocol.Protocol;
|
import net.md_5.bungee.protocol.Protocol;
|
||||||
import net.md_5.bungee.protocol.Varint21FrameDecoder;
|
import net.md_5.bungee.protocol.Varint21FrameDecoder;
|
||||||
|
import net.md_5.bungee.protocol.Varint21LengthFieldExtraBufPrepender;
|
||||||
import net.md_5.bungee.protocol.Varint21LengthFieldPrepender;
|
import net.md_5.bungee.protocol.Varint21LengthFieldPrepender;
|
||||||
|
|
||||||
public class PipelineUtils
|
public class PipelineUtils
|
||||||
@ -82,9 +85,11 @@ public class PipelineUtils
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
public static final Base BASE = new Base();
|
public static final Base BASE = new Base( false );
|
||||||
|
public static final Base BASE_SERVERSIDE = new Base( true );
|
||||||
private static final KickStringWriter legacyKicker = new KickStringWriter();
|
private static final KickStringWriter legacyKicker = new KickStringWriter();
|
||||||
private static final Varint21LengthFieldPrepender framePrepender = new Varint21LengthFieldPrepender();
|
private static final Varint21LengthFieldPrepender framePrepender = new Varint21LengthFieldPrepender();
|
||||||
|
private static final Varint21LengthFieldExtraBufPrepender serverFramePrepender = new Varint21LengthFieldExtraBufPrepender();
|
||||||
public static final String TIMEOUT_HANDLER = "timeout";
|
public static final String TIMEOUT_HANDLER = "timeout";
|
||||||
public static final String PACKET_DECODER = "packet-decoder";
|
public static final String PACKET_DECODER = "packet-decoder";
|
||||||
public static final String PACKET_ENCODER = "packet-encoder";
|
public static final String PACKET_ENCODER = "packet-encoder";
|
||||||
@ -152,9 +157,13 @@ public class PipelineUtils
|
|||||||
private static final int HIGH_MARK = Integer.getInteger( "net.md_5.bungee.high_mark", 2 << 20 ); // 2 mb
|
private static final int HIGH_MARK = Integer.getInteger( "net.md_5.bungee.high_mark", 2 << 20 ); // 2 mb
|
||||||
private static final WriteBufferWaterMark MARK = new WriteBufferWaterMark( LOW_MARK, HIGH_MARK );
|
private static final WriteBufferWaterMark MARK = new WriteBufferWaterMark( LOW_MARK, HIGH_MARK );
|
||||||
|
|
||||||
|
@NoArgsConstructor // for backwards compatibility
|
||||||
|
@AllArgsConstructor
|
||||||
public static final class Base extends ChannelInitializer<Channel>
|
public static final class Base extends ChannelInitializer<Channel>
|
||||||
{
|
{
|
||||||
|
|
||||||
|
private boolean toServer = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initChannel(Channel ch) throws Exception
|
public void initChannel(Channel ch) throws Exception
|
||||||
{
|
{
|
||||||
@ -170,7 +179,9 @@ public class PipelineUtils
|
|||||||
|
|
||||||
ch.pipeline().addLast( FRAME_DECODER, new Varint21FrameDecoder() );
|
ch.pipeline().addLast( FRAME_DECODER, new Varint21FrameDecoder() );
|
||||||
ch.pipeline().addLast( TIMEOUT_HANDLER, new ReadTimeoutHandler( BungeeCord.getInstance().config.getTimeout(), TimeUnit.MILLISECONDS ) );
|
ch.pipeline().addLast( TIMEOUT_HANDLER, new ReadTimeoutHandler( BungeeCord.getInstance().config.getTimeout(), TimeUnit.MILLISECONDS ) );
|
||||||
ch.pipeline().addLast( FRAME_PREPENDER, framePrepender );
|
// No encryption bungee -> server, therefore use extra buffer to avoid copying everything for length prepending
|
||||||
|
// Not used bungee -> client as header would need to be encrypted separately through expensive JNI call
|
||||||
|
ch.pipeline().addLast( FRAME_PREPENDER, ( toServer ) ? serverFramePrepender : framePrepender );
|
||||||
|
|
||||||
ch.pipeline().addLast( BOSS_HANDLER, new HandlerBoss() );
|
ch.pipeline().addLast( BOSS_HANDLER, new HandlerBoss() );
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user